Compare commits
15 Commits
lithium-0.
...
v0.3.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
292d3ca982 | ||
|
|
25ce72434f | ||
|
|
b15e8398e7 | ||
|
|
b6410354e5 | ||
|
|
85ca21eb28 | ||
|
|
bda7cfaad9 | ||
|
|
fece86b279 | ||
|
|
27759719e9 | ||
|
|
13948cdf26 | ||
|
|
ac0c7deb43 | ||
|
|
16c8398d8a | ||
|
|
661ef813bb | ||
|
|
cf1d26a73c | ||
|
|
0cbff02a1c | ||
|
|
ce4ee767fe |
@@ -3,9 +3,11 @@ package ca.spottedleaf.moonrise.fabric;
|
||||
import ca.spottedleaf.moonrise.common.util.BaseChunkSystemHooks;
|
||||
import ca.spottedleaf.moonrise.common.PlatformHooks;
|
||||
import ca.spottedleaf.moonrise.common.util.ConfigHolder;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType;
|
||||
import com.mojang.datafixers.DSL;
|
||||
import com.mojang.datafixers.DataFixer;
|
||||
import com.mojang.serialization.Dynamic;
|
||||
import it.unimi.dsi.fastutil.longs.LongArrays;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.minecraft.core.BlockPos;
|
||||
@@ -15,6 +17,7 @@ import net.minecraft.server.level.ChunkHolder;
|
||||
import net.minecraft.server.level.GenerationChunkHolder;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.level.TicketType;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.boss.EnderDragonPart;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
@@ -255,4 +258,9 @@ public final class FabricHooks extends BaseChunkSystemHooks implements PlatformH
|
||||
public int modifyEntityTrackingRange(final Entity entity, final int currentRange) {
|
||||
return currentRange;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long[] getCounterTypesUncached(final TicketType type) {
|
||||
return type == TicketType.FORCED ? new long[] { ChunkSystemTicketType.COUNTER_TYPE_FORCED } : LongArrays.EMPTY_ARRAY;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
package ca.spottedleaf.moonrise.fabric.mixin.chunk_system;
|
||||
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemDistanceManager;
|
||||
import net.minecraft.server.level.ChunkLevel;
|
||||
import net.minecraft.server.level.DistanceManager;
|
||||
import net.minecraft.server.level.FullChunkStatus;
|
||||
import net.minecraft.server.level.TicketType;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
|
||||
@Mixin(DistanceManager.class)
|
||||
abstract class FabricDistanceManagerMixin implements ChunkSystemDistanceManager {
|
||||
|
||||
/**
|
||||
* @reason Route to new chunk system
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public <T> void addRegionTicket(final TicketType<T> type, final ChunkPos pos, final int radius, final T identifier) {
|
||||
this.moonrise$getChunkHolderManager().addTicketAtLevel(type, pos, ChunkLevel.byStatus(FullChunkStatus.FULL) - radius, identifier);
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Route to new chunk system
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public <T> void removeRegionTicket(final TicketType<T> type, final ChunkPos pos, final int radius, final T identifier) {
|
||||
this.moonrise$getChunkHolderManager().removeTicketAtLevel(type, pos, ChunkLevel.byStatus(FullChunkStatus.FULL) - radius, identifier);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,7 +36,7 @@
|
||||
"accessWidener": "moonrise.accesswidener",
|
||||
"depends": {
|
||||
"fabricloader": ">=${loader_version}",
|
||||
"minecraft": ">1.21.3 <1.21.5",
|
||||
"minecraft": ">1.21.4 <1.21.6",
|
||||
"fabric-command-api-v2": "*"
|
||||
},
|
||||
"custom": {
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
"parent": "moonrise.mixins.json",
|
||||
"package": "ca.spottedleaf.moonrise.fabric.mixin",
|
||||
"mixins": [
|
||||
"chunk_system.FabricDistanceManagerMixin",
|
||||
"chunk_system.FabricMinecraftServerMixin",
|
||||
"chunk_system.FabricServerLevelMixin",
|
||||
"collisions.EntityMixin"
|
||||
|
||||
@@ -5,22 +5,22 @@ org.gradle.caching=true
|
||||
org.gradle.configuration-cache=true
|
||||
# Fabric Properties
|
||||
# check these on https://modmuss50.me/fabric.html
|
||||
minecraft_version=1.21.4
|
||||
loader_version=0.16.9
|
||||
supported_minecraft_versions=1.21.4
|
||||
neoforge_version=21.4.33-beta
|
||||
neoform_version=1.21.4-20241203.161809
|
||||
fabric_api_version=0.110.5+1.21.4
|
||||
minecraft_version=1.21.5
|
||||
loader_version=0.16.14
|
||||
supported_minecraft_versions=1.21.5
|
||||
neoforge_version=21.5.65-beta
|
||||
neoform_version=1.21.5-20250325.162830
|
||||
fabric_api_version=0.123.0+1.21.5
|
||||
snakeyaml_version=2.3
|
||||
concurrentutil_version=0.0.3
|
||||
yamlconfig_version=1.0.2
|
||||
cloth_version=17.0.144
|
||||
modmenu_version=13.0.0-beta.1
|
||||
cloth_version=18.0.145
|
||||
modmenu_version=14.0.0-rc.2
|
||||
junit_version=5.11.3
|
||||
# version ids from modrinth
|
||||
fabric_lithium_version=t1FlWYl9
|
||||
neo_lithium_version=iDqQi66g
|
||||
fabric_lithium_version=nhc57Td2
|
||||
neo_lithium_version=P5VT33Jo
|
||||
# Mod Properties
|
||||
mod_version=0.2.0-SNAPSHOT
|
||||
mod_version=0.3.0-beta.2
|
||||
maven_group=ca.spottedleaf.moonrise
|
||||
archives_base_name=moonrise
|
||||
|
||||
@@ -4,9 +4,11 @@ import ca.spottedleaf.moonrise.common.util.BaseChunkSystemHooks;
|
||||
import ca.spottedleaf.moonrise.common.PlatformHooks;
|
||||
import ca.spottedleaf.moonrise.common.util.ConfigHolder;
|
||||
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType;
|
||||
import com.mojang.datafixers.DSL;
|
||||
import com.mojang.datafixers.DataFixer;
|
||||
import com.mojang.serialization.Dynamic;
|
||||
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtOps;
|
||||
@@ -14,6 +16,7 @@ import net.minecraft.server.level.ChunkHolder;
|
||||
import net.minecraft.server.level.GenerationChunkHolder;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.level.TicketType;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
@@ -261,4 +264,18 @@ public final class NeoForgeHooks extends BaseChunkSystemHooks implements Platfor
|
||||
public int modifyEntityTrackingRange(final Entity entity, final int currentRange) {
|
||||
return currentRange;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long[] getCounterTypesUncached(final TicketType type) {
|
||||
final LongArrayList ret = new LongArrayList();
|
||||
|
||||
if (type == TicketType.FORCED) {
|
||||
ret.add(ChunkSystemTicketType.COUNTER_TYPE_FORCED);
|
||||
}
|
||||
if (type.forceNaturalSpawning()) {
|
||||
ret.add(ChunkSystemTicketType.COUNTER_TYPER_NATURAL_SPAWNING_FORCED);
|
||||
}
|
||||
|
||||
return ret.toLongArray();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
package ca.spottedleaf.moonrise.neoforge.mixin.chunk_system;
|
||||
|
||||
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemDistanceManager;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickServerLevel;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import net.minecraft.server.level.ChunkLevel;
|
||||
import net.minecraft.server.level.DistanceManager;
|
||||
import net.minecraft.server.level.FullChunkStatus;
|
||||
import net.minecraft.server.level.Ticket;
|
||||
import net.minecraft.server.level.TicketType;
|
||||
import net.minecraft.util.SortedArraySet;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
@Mixin(DistanceManager.class)
|
||||
abstract class NeoForgeDistanceManagerMixin implements ChunkSystemDistanceManager {
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private Long2ObjectOpenHashMap<SortedArraySet<Ticket<?>>> forcedTickets;
|
||||
|
||||
/**
|
||||
* @reason Route to new chunk system
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public <T> void addRegionTicket(final TicketType<T> type, final ChunkPos pos, final int radius, final T identifier, final boolean forceTicks) {
|
||||
final int level = ChunkLevel.byStatus(FullChunkStatus.FULL) - radius;
|
||||
this.moonrise$getChunkHolderManager().addTicketAtLevel(type, pos, level, identifier);
|
||||
if (forceTicks) {
|
||||
final Ticket<T> forceTicket = new Ticket<>(type, level, identifier, forceTicks);
|
||||
|
||||
this.forcedTickets.compute(pos.toLong(), (final Long keyInMap, final SortedArraySet<Ticket<?>> valueInMap) -> {
|
||||
final SortedArraySet<Ticket<?>> ret;
|
||||
if (valueInMap != null) {
|
||||
ret = valueInMap;
|
||||
} else {
|
||||
ret = SortedArraySet.create(4);
|
||||
}
|
||||
|
||||
if (ret.add(forceTicket)) {
|
||||
((ChunkTickServerLevel)NeoForgeDistanceManagerMixin.this.moonrise$getChunkMap().level).moonrise$addPlayerTickingRequest(
|
||||
CoordinateUtils.getChunkX(keyInMap.longValue()), CoordinateUtils.getChunkZ(keyInMap.longValue())
|
||||
);
|
||||
}
|
||||
|
||||
return ret;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Route to new chunk system
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public <T> void removeRegionTicket(final TicketType<T> type, final ChunkPos pos, final int radius, final T identifier, final boolean forceTicks) {
|
||||
final int level = ChunkLevel.byStatus(FullChunkStatus.FULL) - radius;
|
||||
this.moonrise$getChunkHolderManager().removeTicketAtLevel(type, pos, level, identifier);
|
||||
if (forceTicks) {
|
||||
final Ticket<T> forceTicket = new Ticket<>(type, level, identifier, forceTicks);
|
||||
|
||||
this.forcedTickets.computeIfPresent(pos.toLong(), (final Long keyInMap, final SortedArraySet<Ticket<?>> valueInMap) -> {
|
||||
if (valueInMap.remove(forceTicket)) {
|
||||
((ChunkTickServerLevel)NeoForgeDistanceManagerMixin.this.moonrise$getChunkMap().level).moonrise$removePlayerTickingRequest(
|
||||
CoordinateUtils.getChunkX(keyInMap.longValue()), CoordinateUtils.getChunkZ(keyInMap.longValue())
|
||||
);
|
||||
}
|
||||
|
||||
return valueInMap.isEmpty() ? null : valueInMap;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Only use containsKey, as we fix the leak with this impl
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public boolean shouldForceTicks(final long chunkPos) {
|
||||
return this.forcedTickets.containsKey(chunkPos);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package ca.spottedleaf.moonrise.neoforge.mixin.chunk_system;
|
||||
|
||||
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketStorage;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType;
|
||||
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.TicketStorage;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
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;
|
||||
|
||||
@Mixin(TicketStorage.class)
|
||||
abstract class NeoForgeTicketStorageMixin implements ChunkSystemTicketStorage {
|
||||
|
||||
@Shadow
|
||||
private LongSet chunksWithForceNaturalSpawning;
|
||||
|
||||
/**
|
||||
* @reason Destroy old chunk system state
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Inject(
|
||||
method = "<init>(Lit/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap;Lit/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap;)V",
|
||||
at = @At(
|
||||
value = "RETURN"
|
||||
)
|
||||
)
|
||||
private void destroyFields(Long2ObjectOpenHashMap p_393873_, Long2ObjectOpenHashMap p_394615_, CallbackInfo ci) {
|
||||
this.chunksWithForceNaturalSpawning = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason The forced natural spawning chunks would be empty, as tickets should always be empty.
|
||||
* We need to do this to avoid throwing immediately.
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Redirect(
|
||||
method = "<init>(Lit/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap;Lit/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap;)V",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/level/TicketStorage;updateForcedNaturalSpawning()V"
|
||||
)
|
||||
)
|
||||
private void avoidUpdatingForcedNaturalChunks(final TicketStorage instance) {}
|
||||
|
||||
/**
|
||||
* @reason Route to new chunk system
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public boolean shouldForceNaturalSpawning(final ChunkPos pos) {
|
||||
final Long2IntOpenHashMap counters = ((ChunkSystemServerLevel)this.moonrise$getChunkMap().level).moonrise$getChunkTaskScheduler()
|
||||
.chunkHolderManager.getTicketCounters(ChunkSystemTicketType.COUNTER_TYPER_NATURAL_SPAWNING_FORCED);
|
||||
|
||||
if (counters == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return counters.containsKey(CoordinateUtils.getChunkKey(pos));
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ side = "BOTH"
|
||||
[[dependencies.moonrise]]
|
||||
modId = "minecraft"
|
||||
type = "required"
|
||||
versionRange = "(1.21.3,1.21.5)"
|
||||
versionRange = "(1.21.4,1.21.6)"
|
||||
ordering = "NONE"
|
||||
side = "BOTH"
|
||||
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
"parent": "moonrise.mixins.json",
|
||||
"package": "ca.spottedleaf.moonrise.neoforge.mixin",
|
||||
"mixins": [
|
||||
"chunk_system.NeoForgeDistanceManagerMixin",
|
||||
"chunk_system.NeoForgeMinecraftServerMixin",
|
||||
"chunk_system.NeoForgeServerLevelMixin",
|
||||
"chunk_system.NeoForgeTicketStorageMixin",
|
||||
"collisions.EntityMixin"
|
||||
],
|
||||
"client": [
|
||||
|
||||
@@ -23,9 +23,9 @@ pluginManagement {
|
||||
|
||||
plugins {
|
||||
id("org.gradle.toolchains.foojay-resolver-convention") version "0.9.0"
|
||||
id("quiet-fabric-loom") version "1.9.312" apply false
|
||||
id("net.neoforged.moddev") version "2.0.61-beta" apply false
|
||||
id 'com.gradleup.shadow' version '8.3.5' apply false
|
||||
id("quiet-fabric-loom") version "1.10.317" apply false
|
||||
id("net.neoforged.moddev") version "2.0.80" apply false
|
||||
id 'com.gradleup.shadow' version '8.3.6' apply false
|
||||
}
|
||||
|
||||
dependencyResolutionManagement {
|
||||
|
||||
@@ -2,6 +2,7 @@ package ca.spottedleaf.moonrise.common.list;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Reference2IntLinkedOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Arrays;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
@@ -21,15 +22,34 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
||||
private int iteratorCount;
|
||||
|
||||
public IteratorSafeOrderedReferenceSet() {
|
||||
this(16, 0.75f, 16, 0.2);
|
||||
this(Object.class);
|
||||
}
|
||||
|
||||
public IteratorSafeOrderedReferenceSet(final Class<? super E> arrComponent) {
|
||||
this(16, 0.75f, 16, 0.2, arrComponent);
|
||||
}
|
||||
|
||||
public IteratorSafeOrderedReferenceSet(final int setCapacity, final float setLoadFactor, final int arrayCapacity,
|
||||
final double maxFragFactor) {
|
||||
this(setCapacity, setLoadFactor, arrayCapacity, maxFragFactor, Object.class);
|
||||
}
|
||||
|
||||
public IteratorSafeOrderedReferenceSet(final int setCapacity, final float setLoadFactor, final int arrayCapacity,
|
||||
final double maxFragFactor, final Class<? super E> arrComponent) {
|
||||
this.indexMap = new Reference2IntLinkedOpenHashMap<>(setCapacity, setLoadFactor);
|
||||
this.indexMap.defaultReturnValue(-1);
|
||||
this.maxFragFactor = maxFragFactor;
|
||||
this.listElements = (E[])new Object[arrayCapacity];
|
||||
this.listElements = (E[])Array.newInstance(arrComponent, arrayCapacity);
|
||||
}
|
||||
|
||||
// includes null (gravestone) elements
|
||||
public E[] getListRaw() {
|
||||
return this.listElements;
|
||||
}
|
||||
|
||||
// includes null (gravestone) elements
|
||||
public int getListSize() {
|
||||
return this.listSize;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -81,7 +101,7 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
||||
public int createRawIterator() {
|
||||
++this.iteratorCount;
|
||||
if (this.indexMap.isEmpty()) {
|
||||
return -1;
|
||||
return Integer.MAX_VALUE;
|
||||
} else {
|
||||
return this.firstInvalidIndex == 0 ? this.indexMap.getInt(this.indexMap.firstKey()) : 0;
|
||||
}
|
||||
@@ -96,7 +116,7 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
return Integer.MAX_VALUE;
|
||||
}
|
||||
|
||||
public void finishRawIterator() {
|
||||
@@ -205,10 +225,6 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
||||
//this.check();
|
||||
}
|
||||
|
||||
public E rawGet(final int index) {
|
||||
return this.listElements[index];
|
||||
}
|
||||
|
||||
public int size() {
|
||||
// always returns the correct amount - listSize can be different
|
||||
return this.indexMap.size();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package ca.spottedleaf.moonrise.common.misc;
|
||||
|
||||
import ca.spottedleaf.concurrentutil.util.IntPairUtil;
|
||||
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
||||
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||
import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap;
|
||||
@@ -23,12 +23,16 @@ public final class PositionCountingAreaMap<T> {
|
||||
return this.positions.size();
|
||||
}
|
||||
|
||||
public boolean hasObjectsNear(final long pos) {
|
||||
return this.positions.containsKey(pos);
|
||||
}
|
||||
|
||||
public boolean hasObjectsNear(final int toX, final int toZ) {
|
||||
return this.positions.containsKey(IntPairUtil.key(toX, toZ));
|
||||
return this.positions.containsKey(CoordinateUtils.getChunkKey(toX, toZ));
|
||||
}
|
||||
|
||||
public int getObjectsNear(final int toX, final int toZ) {
|
||||
return this.positions.get(IntPairUtil.key(toX, toZ));
|
||||
return this.positions.get(CoordinateUtils.getChunkKey(toX, toZ));
|
||||
}
|
||||
|
||||
public boolean add(final T parameter, final int toX, final int toZ, final int distance) {
|
||||
@@ -85,12 +89,12 @@ public final class PositionCountingAreaMap<T> {
|
||||
|
||||
@Override
|
||||
protected void addCallback(final T parameter, final int toX, final int toZ) {
|
||||
PositionCountingAreaMap.this.positions.addTo(IntPairUtil.key(toX, toZ), 1);
|
||||
PositionCountingAreaMap.this.positions.addTo(CoordinateUtils.getChunkKey(toX, toZ), 1);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void removeCallback(final T parameter, final int toX, final int toZ) {
|
||||
final long key = IntPairUtil.key(toX, toZ);
|
||||
final long key = CoordinateUtils.getChunkKey(toX, toZ);
|
||||
if (PositionCountingAreaMap.this.positions.addTo(key, -1) == 1) {
|
||||
PositionCountingAreaMap.this.positions.remove(key);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package ca.spottedleaf.moonrise.common.misc;
|
||||
|
||||
import ca.spottedleaf.concurrentutil.util.IntegerUtil;
|
||||
|
||||
public abstract class SingleUserAreaMap<T> {
|
||||
|
||||
public static final int NOT_SET = Integer.MIN_VALUE;
|
||||
@@ -99,8 +97,8 @@ public abstract class SingleUserAreaMap<T> {
|
||||
final int dx = toX - fromX;
|
||||
final int dz = toZ - fromZ;
|
||||
|
||||
final int totalX = IntegerUtil.branchlessAbs(fromX - toX);
|
||||
final int totalZ = IntegerUtil.branchlessAbs(fromZ - toZ);
|
||||
final int totalX = Math.abs(fromX - toX);
|
||||
final int totalZ = Math.abs(fromZ - toZ);
|
||||
|
||||
if (Math.max(totalX, totalZ) > (2 * Math.max(newViewDistance, oldViewDistance))) {
|
||||
// teleported
|
||||
@@ -120,7 +118,7 @@ public abstract class SingleUserAreaMap<T> {
|
||||
for (int currZ = oldMinZ; currZ <= oldMaxZ; ++currZ) {
|
||||
|
||||
// only remove if we're outside the new view distance...
|
||||
if (Math.max(IntegerUtil.branchlessAbs(currX - toX), IntegerUtil.branchlessAbs(currZ - toZ)) > newViewDistance) {
|
||||
if (Math.max(Math.abs(currX - toX), Math.abs(currZ - toZ)) > newViewDistance) {
|
||||
this.removeCallback(parameter, currX, currZ);
|
||||
}
|
||||
}
|
||||
@@ -136,7 +134,7 @@ public abstract class SingleUserAreaMap<T> {
|
||||
for (int currZ = newMinZ; currZ <= newMaxZ; ++currZ) {
|
||||
|
||||
// only add if we're outside the old view distance...
|
||||
if (Math.max(IntegerUtil.branchlessAbs(currX - fromX), IntegerUtil.branchlessAbs(currZ - fromZ)) > oldViewDistance) {
|
||||
if (Math.max(Math.abs(currX - fromX), Math.abs(currZ - fromZ)) > oldViewDistance) {
|
||||
this.addCallback(parameter, currX, currZ);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ public abstract class BaseChunkSystemHooks implements ChunkSystemHooks {
|
||||
|
||||
@Override
|
||||
public void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run) {
|
||||
scheduleChunkTask(level, chunkX, chunkZ, run, Priority.NORMAL);
|
||||
this.scheduleChunkTask(level, chunkX, chunkZ, run, Priority.NORMAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -71,7 +71,7 @@ public abstract class BaseChunkSystemHooks implements ChunkSystemHooks {
|
||||
|
||||
@Override
|
||||
public boolean hasAnyChunkHolders(final ServerLevel level) {
|
||||
return getUpdatingChunkHolderCount(level) != 0;
|
||||
return this.getUpdatingChunkHolderCount(level) != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -98,16 +98,12 @@ public abstract class BaseChunkSystemHooks implements ChunkSystemHooks {
|
||||
|
||||
@Override
|
||||
public void onChunkBorder(final LevelChunk chunk, final ChunkHolder holder) {
|
||||
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getLoadedChunks().add(
|
||||
((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder()
|
||||
);
|
||||
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getLoadedChunks().add(chunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChunkNotBorder(final LevelChunk chunk, final ChunkHolder holder) {
|
||||
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getLoadedChunks().remove(
|
||||
((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder()
|
||||
);
|
||||
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getLoadedChunks().remove(chunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -118,37 +114,29 @@ public abstract class BaseChunkSystemHooks implements ChunkSystemHooks {
|
||||
|
||||
@Override
|
||||
public void onChunkTicking(final LevelChunk chunk, final ChunkHolder holder) {
|
||||
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getTickingChunks().add(
|
||||
((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder()
|
||||
);
|
||||
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getTickingChunks().add(chunk);
|
||||
if (!((ChunkSystemLevelChunk)chunk).moonrise$isPostProcessingDone()) {
|
||||
chunk.postProcessGeneration((ServerLevel)chunk.getLevel());
|
||||
}
|
||||
((ServerLevel)chunk.getLevel()).startTickingChunk(chunk);
|
||||
((ServerLevel)chunk.getLevel()).getChunkSource().chunkMap.tickingGenerated.incrementAndGet();
|
||||
((ChunkTickServerLevel)(ServerLevel)chunk.getLevel()).moonrise$markChunkForPlayerTicking(chunk); // Moonrise - chunk tick iteration
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChunkNotTicking(final LevelChunk chunk, final ChunkHolder holder) {
|
||||
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getTickingChunks().remove(
|
||||
((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder()
|
||||
);
|
||||
((ChunkTickServerLevel)(ServerLevel)chunk.getLevel()).moonrise$removeChunkForPlayerTicking(chunk); // Moonrise - chunk tick iteration
|
||||
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getTickingChunks().remove(chunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChunkEntityTicking(final LevelChunk chunk, final ChunkHolder holder) {
|
||||
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getEntityTickingChunks().add(
|
||||
((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder()
|
||||
);
|
||||
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getEntityTickingChunks().add(chunk);
|
||||
((ChunkTickServerLevel)(ServerLevel)chunk.getLevel()).moonrise$markChunkForPlayerTicking(chunk); // Moonrise - chunk tick iteration
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChunkNotEntityTicking(final LevelChunk chunk, final ChunkHolder holder) {
|
||||
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getEntityTickingChunks().remove(
|
||||
((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder()
|
||||
);
|
||||
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getEntityTickingChunks().remove(chunk);
|
||||
((ChunkTickServerLevel)(ServerLevel)chunk.getLevel()).moonrise$removeChunkForPlayerTicking(chunk); // Moonrise - chunk tick iteration
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -5,6 +5,7 @@ import net.minecraft.server.level.ChunkHolder;
|
||||
import net.minecraft.server.level.FullChunkStatus;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.level.TicketType;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
@@ -74,4 +75,6 @@ public interface ChunkSystemHooks {
|
||||
public void removePlayerFromDistanceMaps(final ServerLevel world, final ServerPlayer player);
|
||||
|
||||
public void updateMaps(final ServerLevel world, final ServerPlayer player);
|
||||
|
||||
public long[] getCounterTypesUncached(final TicketType type);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package ca.spottedleaf.moonrise.common.util;
|
||||
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import java.text.DecimalFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public final class EntityUtil {
|
||||
|
||||
private static final ThreadLocal<DecimalFormat> THREE_DECIMAL_PLACES = ThreadLocal.withInitial(() -> {
|
||||
return new DecimalFormat("#,##0.000");
|
||||
});
|
||||
|
||||
private static String formatVec(final Vec3 vec) {
|
||||
final DecimalFormat format = THREE_DECIMAL_PLACES.get();
|
||||
|
||||
return "(" + format.format(vec.x) + "," + format.format(vec.y) + "," + format.format(vec.z) + ")";
|
||||
}
|
||||
|
||||
private static String dumpEntityWithoutReferences(final Entity entity) {
|
||||
if (entity == null) {
|
||||
return "{null}";
|
||||
}
|
||||
|
||||
return "{type=" + entity.getClass().getSimpleName() + ",id=" + entity.getId() + ",uuid=" + entity.getUUID() + ",pos=" + formatVec(entity.position())
|
||||
+ ",mot=" + formatVec(entity.getDeltaMovement()) + ",aabb=" + entity.getBoundingBox() + ",removed=" + entity.getRemovalReason() + ",has_vehicle=" + (entity.getVehicle() != null)
|
||||
+ ",passenger_count=" + entity.getPassengers().size();
|
||||
}
|
||||
|
||||
public static String dumpEntity(final Entity entity) {
|
||||
final List<Entity> passengers = entity.getPassengers();
|
||||
final List<String> passengerStrings = new ArrayList<>(passengers.size());
|
||||
|
||||
for (final Entity passenger : passengers) {
|
||||
passengerStrings.add("(" + dumpEntityWithoutReferences(passenger) + ")");
|
||||
}
|
||||
|
||||
return "{root=[" + dumpEntityWithoutReferences(entity) + "], vehicle=[" + dumpEntityWithoutReferences(entity.getVehicle())
|
||||
+ "], passengers=[" + String.join(",", passengerStrings) + "]";
|
||||
}
|
||||
|
||||
private EntityUtil() {}
|
||||
}
|
||||
@@ -15,21 +15,25 @@ public class TickThread extends Thread {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(TickThread.class);
|
||||
|
||||
private static String getThreadContext() {
|
||||
return "thread=" + Thread.currentThread().getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
public static void ensureTickThread(final String reason) {
|
||||
if (!isTickThread()) {
|
||||
LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable());
|
||||
LOGGER.error("Thread failed main thread check: " + reason + ", context=" + getThreadContext(), new Throwable());
|
||||
throw new IllegalStateException(reason);
|
||||
}
|
||||
}
|
||||
|
||||
public static void ensureTickThread(final Level world, final BlockPos pos, final String reason) {
|
||||
if (!isTickThreadFor(world, pos)) {
|
||||
final String ex = "Thread " + Thread.currentThread().getName() + " failed main thread check: " +
|
||||
reason + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + pos;
|
||||
final String ex = "Thread failed main thread check: " +
|
||||
reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + pos;
|
||||
LOGGER.error(ex, new Throwable());
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
@@ -37,8 +41,8 @@ public class TickThread extends Thread {
|
||||
|
||||
public static void ensureTickThread(final Level world, final BlockPos pos, final int blockRadius, final String reason) {
|
||||
if (!isTickThreadFor(world, pos, blockRadius)) {
|
||||
final String ex = "Thread " + Thread.currentThread().getName() + " failed main thread check: " +
|
||||
reason + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + pos + ", block_radius=" + blockRadius;
|
||||
final String ex = "Thread failed main thread check: " +
|
||||
reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + pos + ", block_radius=" + blockRadius;
|
||||
LOGGER.error(ex, new Throwable());
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
@@ -46,8 +50,8 @@ public class TickThread extends Thread {
|
||||
|
||||
public static void ensureTickThread(final Level world, final ChunkPos pos, final String reason) {
|
||||
if (!isTickThreadFor(world, pos)) {
|
||||
final String ex = "Thread " + Thread.currentThread().getName() + " failed main thread check: " +
|
||||
reason + ", world=" + WorldUtil.getWorldName(world) + ", chunk_pos=" + pos;
|
||||
final String ex = "Thread failed main thread check: " +
|
||||
reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", chunk_pos=" + pos;
|
||||
LOGGER.error(ex, new Throwable());
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
@@ -55,8 +59,8 @@ public class TickThread extends Thread {
|
||||
|
||||
public static void ensureTickThread(final Level world, final int chunkX, final int chunkZ, final String reason) {
|
||||
if (!isTickThreadFor(world, chunkX, chunkZ)) {
|
||||
final String ex = "Thread " + Thread.currentThread().getName() + " failed main thread check: " +
|
||||
reason + ", world=" + WorldUtil.getWorldName(world) + ", chunk_pos=" + new ChunkPos(chunkX, chunkZ);
|
||||
final String ex = "Thread failed main thread check: " +
|
||||
reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", chunk_pos=" + new ChunkPos(chunkX, chunkZ);
|
||||
LOGGER.error(ex, new Throwable());
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
@@ -64,8 +68,8 @@ public class TickThread extends Thread {
|
||||
|
||||
public static void ensureTickThread(final Entity entity, final String reason) {
|
||||
if (!isTickThreadFor(entity)) {
|
||||
final String ex = "Thread " + Thread.currentThread().getName() + " failed main thread check: " +
|
||||
reason + ", entity=" + entity;
|
||||
final String ex = "Thread failed main thread check: " +
|
||||
reason + ", context=" + getThreadContext() + ", entity=" + EntityUtil.dumpEntity(entity);
|
||||
LOGGER.error(ex, new Throwable());
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
@@ -73,8 +77,8 @@ public class TickThread extends Thread {
|
||||
|
||||
public static void ensureTickThread(final Level world, final AABB aabb, final String reason) {
|
||||
if (!isTickThreadFor(world, aabb)) {
|
||||
final String ex = "Thread " + Thread.currentThread().getName() + " failed main thread check: " +
|
||||
reason + ", world=" + WorldUtil.getWorldName(world) + ", aabb=" + aabb;
|
||||
final String ex = "Thread failed main thread check: " +
|
||||
reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", aabb=" + aabb;
|
||||
LOGGER.error(ex, new Throwable());
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
@@ -82,8 +86,8 @@ public class TickThread extends Thread {
|
||||
|
||||
public static void ensureTickThread(final Level world, final double blockX, final double blockZ, final String reason) {
|
||||
if (!isTickThreadFor(world, blockX, blockZ)) {
|
||||
final String ex = "Thread " + Thread.currentThread().getName() + " failed main thread check: " +
|
||||
reason + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + new Vec3(blockX, 0.0, blockZ);
|
||||
final String ex = "Thread failed main thread check: " +
|
||||
reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + new Vec3(blockX, 0.0, blockZ);
|
||||
LOGGER.error(ex, new Throwable());
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ abstract class LevelMixin implements LevelAccessor, AutoCloseable {
|
||||
|
||||
if (doTick && this.shouldTickBlocksAt(tileEntity.getPos())) {
|
||||
tileEntity.tick();
|
||||
// call mid tick tasks for chunk system
|
||||
// call mid-tick tasks for chunk system
|
||||
if ((++tickedEntities & 7) == 0) {
|
||||
((ChunkSystemLevel)(Level)(Object)this).moonrise$midTickTasks();
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ abstract class StateHolderMixin<O, S> implements PropertyAccessStateHolder {
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public <T extends Comparable<T>> T getNullableValue(Property<T> property) {
|
||||
public <T extends Comparable<T>> T getNullableValue(final Property<T> property) {
|
||||
return property == null ? null : this.optimisedTable.get(this.tableIndex, property);
|
||||
}
|
||||
|
||||
@@ -166,7 +166,7 @@ abstract class StateHolderMixin<O, S> implements PropertyAccessStateHolder {
|
||||
*/
|
||||
@Overwrite
|
||||
public Map<Property<?>, Comparable<?>> getValues() {
|
||||
ZeroCollidingReferenceStateTable<O, S> table = this.optimisedTable;
|
||||
final ZeroCollidingReferenceStateTable<O, S> table = this.optimisedTable;
|
||||
// We have to use this.values until the table is loaded
|
||||
return table.isLoaded() ? table.getMapView(this.tableIndex) : this.values;
|
||||
}
|
||||
|
||||
@@ -366,7 +366,7 @@ abstract class ChunkHolderMixin extends GenerationChunkHolder implements ChunkSy
|
||||
/**
|
||||
* @reason Use ticket system to control ticket levels
|
||||
* @author Spottedleaf
|
||||
* @see net.minecraft.server.level.ServerChunkCache#addRegionTicket(TicketType, ChunkPos, int, Object)
|
||||
* @see net.minecraft.server.level.ServerChunkCache#addTicketWithRadius(TicketType, ChunkPos, int)
|
||||
*/
|
||||
@Overwrite
|
||||
public void setTicketLevel(int i) {
|
||||
@@ -397,8 +397,14 @@ abstract class ChunkHolderMixin extends GenerationChunkHolder implements ChunkSy
|
||||
* @reason Chunk system hooks for ticket level updating now in {@link NewChunkHolder#processTicketLevelUpdate(List, List)}
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public void updateFutures(final ChunkMap chunkMap, final Executor executor) {
|
||||
// inject to avoid conflicting with fabric API's mixin here, we call their event in FabricHooks
|
||||
@Inject(
|
||||
method = "updateFutures",
|
||||
at = @At(
|
||||
value = "HEAD"
|
||||
)
|
||||
)
|
||||
public void clobberUpdateFutures(final ChunkMap chunkMap, final Executor executor, final CallbackInfo ci) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package ca.spottedleaf.moonrise.mixin.chunk_system;
|
||||
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemDistanceManager;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import net.minecraft.world.level.TicketStorage;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
@@ -15,8 +16,8 @@ abstract class ChunkMap$DistanceManagerMixin extends net.minecraft.server.level.
|
||||
@Final
|
||||
ChunkMap field_17443;
|
||||
|
||||
protected ChunkMap$DistanceManagerMixin(Executor executor, Executor executor2) {
|
||||
super(executor, executor2);
|
||||
protected ChunkMap$DistanceManagerMixin(final TicketStorage p_394060_, final Executor p_140774_, final Executor p_140775_) {
|
||||
super(p_394060_, p_140774_, p_140775_);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -32,6 +32,7 @@ import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.StaticCache2D;
|
||||
import net.minecraft.util.thread.BlockableEventLoop;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.TicketStorage;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
@@ -43,7 +44,6 @@ import net.minecraft.world.level.chunk.storage.IOWorker;
|
||||
import net.minecraft.world.level.chunk.storage.RegionStorageInfo;
|
||||
import net.minecraft.world.level.entity.ChunkStatusUpdateListener;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||
import net.minecraft.world.level.storage.DimensionDataStorage;
|
||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
@@ -124,11 +124,11 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
|
||||
)
|
||||
)
|
||||
private void constructor(
|
||||
ServerLevel arg, LevelStorageSource.LevelStorageAccess arg2, DataFixer dataFixer,
|
||||
StructureTemplateManager arg3, Executor executor, BlockableEventLoop<Runnable> arg4,
|
||||
LightChunkGetter arg5, ChunkGenerator arg6, ChunkProgressListener arg7,
|
||||
ChunkStatusUpdateListener arg8, Supplier<DimensionDataStorage> supplier, int j, boolean bl,
|
||||
final CallbackInfo ci) {
|
||||
ServerLevel p_214836_, LevelStorageSource.LevelStorageAccess p_214837_, DataFixer p_214838_,
|
||||
StructureTemplateManager p_214839_, Executor p_214840_, BlockableEventLoop p_214841_,
|
||||
LightChunkGetter p_214842_, ChunkGenerator p_214843_, ChunkProgressListener p_214844_,
|
||||
ChunkStatusUpdateListener p_214845_, Supplier p_214846_, TicketStorage p_394462_, int p_214847_,
|
||||
boolean p_214848_, CallbackInfo ci) {
|
||||
// intentionally destroy old chunk system hooks
|
||||
this.updatingChunkMap = null;
|
||||
this.visibleChunkMap = null;
|
||||
@@ -143,7 +143,8 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
|
||||
// Dummy impl for mods that try to loadAsync directly
|
||||
this.worker = new IOWorker(
|
||||
// copied from super call
|
||||
new RegionStorageInfo(arg2.getLevelId(), arg.dimension(), "chunk"), arg2.getDimensionPath(arg.dimension()).resolve("region"), bl
|
||||
new RegionStorageInfo(p_214837_.getLevelId(), p_214836_.dimension(), "chunk"),
|
||||
p_214837_.getDimensionPath(p_214836_.dimension()).resolve("region"), p_214848_
|
||||
) {
|
||||
@Override
|
||||
public boolean isOldChunkAround(final ChunkPos chunkPos, final int i) {
|
||||
@@ -543,13 +544,31 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Redirect(
|
||||
method = "forEachSpawnCandidateChunk",
|
||||
method = "collectSpawningChunks",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lit/unimi/dsi/fastutil/longs/Long2ObjectLinkedOpenHashMap;get(J)Ljava/lang/Object;"
|
||||
)
|
||||
)
|
||||
private <V> V redirectChunkHolderGet(final Long2ObjectLinkedOpenHashMap<V> instance, final long key) {
|
||||
private <V> V redirectChunkHolderGetForSpawning(final Long2ObjectLinkedOpenHashMap<V> instance, final long key) {
|
||||
return (V)this.getVisibleChunkIfPresent(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Route to new chunk system
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Redirect(
|
||||
method = {
|
||||
"method_67499",
|
||||
"lambda$forEachBlockTickingChunk$36"
|
||||
},
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lit/unimi/dsi/fastutil/longs/Long2ObjectLinkedOpenHashMap;get(J)Ljava/lang/Object;"
|
||||
)
|
||||
)
|
||||
private <V> V redirectChunkHolderGetForBlockTicking(final Long2ObjectLinkedOpenHashMap<V> instance, final long key) {
|
||||
return (V)this.getVisibleChunkIfPresent(key);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,22 +1,27 @@
|
||||
package ca.spottedleaf.moonrise.mixin.chunk_system;
|
||||
|
||||
import ca.spottedleaf.moonrise.common.list.ReferenceList;
|
||||
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
||||
import ca.spottedleaf.moonrise.common.util.MoonriseConstants;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemDistanceManager;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketStorage;
|
||||
import it.unimi.dsi.fastutil.longs.LongConsumer;
|
||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||
import net.minecraft.server.level.ChunkHolder;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import net.minecraft.server.level.DistanceManager;
|
||||
import net.minecraft.server.level.LoadingChunkTracker;
|
||||
import net.minecraft.server.level.SimulationChunkTracker;
|
||||
import net.minecraft.server.level.ThrottlingChunkTaskDispatcher;
|
||||
import net.minecraft.server.level.Ticket;
|
||||
import net.minecraft.server.level.TicketType;
|
||||
import net.minecraft.server.level.TickingTracker;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.util.SortedArraySet;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.TicketStorage;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
@@ -24,6 +29,7 @@ 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.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Executor;
|
||||
|
||||
@@ -31,13 +37,14 @@ import java.util.concurrent.Executor;
|
||||
abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
|
||||
|
||||
@Shadow
|
||||
Long2ObjectOpenHashMap<SortedArraySet<Ticket<?>>> tickets;
|
||||
public LoadingChunkTracker loadingChunkTracker;
|
||||
|
||||
@Shadow
|
||||
private DistanceManager.ChunkTicketTracker ticketTracker;
|
||||
public SimulationChunkTracker simulationChunkTracker;
|
||||
|
||||
@Shadow
|
||||
private TickingTracker tickingTicketsTracker;
|
||||
@Final
|
||||
private TicketStorage ticketStorage;
|
||||
|
||||
@Shadow
|
||||
private DistanceManager.PlayerTicketTracker playerTicketManager;
|
||||
@@ -64,7 +71,8 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Destroy old chunk system state to prevent it from being used
|
||||
* @reason Destroy old chunk system state to prevent it from being used, and set the chunk map
|
||||
* for the ticket storage
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Inject(
|
||||
@@ -74,15 +82,16 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
|
||||
)
|
||||
)
|
||||
private void destroyFields(final CallbackInfo ci) {
|
||||
this.tickets = null;
|
||||
this.ticketTracker = null;
|
||||
this.tickingTicketsTracker = null;
|
||||
this.loadingChunkTracker = null;
|
||||
this.simulationChunkTracker = null;
|
||||
this.playerTicketManager = null;
|
||||
this.chunksToUpdateFutures = null;
|
||||
this.ticketDispatcher = null;
|
||||
this.ticketsToRelease = null;
|
||||
this.mainThreadExecutor = null;
|
||||
this.simulationDistance = -1;
|
||||
|
||||
((ChunkSystemTicketStorage)this.ticketStorage).moonrise$setChunkMap(this.moonrise$getChunkMap());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -90,15 +99,6 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
|
||||
return ((ChunkSystemServerLevel)this.moonrise$getChunkMap().level).moonrise$getChunkTaskScheduler().chunkHolderManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Route to new chunk system
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public void purgeStaleTickets() {
|
||||
this.moonrise$getChunkHolderManager().tick();
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Route to new chunk system
|
||||
* @author Spottedleaf
|
||||
@@ -108,46 +108,6 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
|
||||
return this.moonrise$getChunkHolderManager().processTicketUpdates();
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Route to new chunk system
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public void addTicket(final long pos, final Ticket<?> ticket) {
|
||||
this.moonrise$getChunkHolderManager().addTicketAtLevel((TicketType)ticket.getType(), pos, ticket.getTicketLevel(), ticket.key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Route to new chunk system
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public void removeTicket(final long pos, final Ticket<?> ticket) {
|
||||
this.moonrise$getChunkHolderManager().removeTicketAtLevel((TicketType)ticket.getType(), pos, ticket.getTicketLevel(), ticket.key);
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Remove old chunk system hooks
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public SortedArraySet<Ticket<?>> getTickets(final long pos) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Route to new chunk system
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public void updateChunkForced(final ChunkPos pos, final boolean forced) {
|
||||
if (forced) {
|
||||
this.moonrise$getChunkHolderManager().addTicketAtLevel(TicketType.FORCED, pos, ChunkMap.FORCED_TICKET_LEVEL, pos);
|
||||
} else {
|
||||
this.moonrise$getChunkHolderManager().removeTicketAtLevel(TicketType.FORCED, pos, ChunkMap.FORCED_TICKET_LEVEL, pos);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Remove old chunk system hooks
|
||||
* @author Spottedleaf
|
||||
@@ -170,11 +130,10 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
|
||||
method = "addPlayer",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/server/level/TickingTracker;addTicket(Lnet/minecraft/server/level/TicketType;Lnet/minecraft/world/level/ChunkPos;ILjava/lang/Object;)V"
|
||||
target = "Lnet/minecraft/world/level/TicketStorage;addTicket(Lnet/minecraft/server/level/Ticket;Lnet/minecraft/world/level/ChunkPos;)V"
|
||||
)
|
||||
)
|
||||
private <T> void skipTickingTicketTrackerAdd(final TickingTracker instance, final TicketType<T> ticketType,
|
||||
final ChunkPos chunkPos, final int i, final T object) {}
|
||||
private void skipTickingTicketTrackerAdd(final TicketStorage instance, final Ticket ticket, final ChunkPos pos) {}
|
||||
|
||||
/**
|
||||
* @reason Remove old chunk system hooks
|
||||
@@ -213,11 +172,10 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
|
||||
method = "removePlayer",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/server/level/TickingTracker;removeTicket(Lnet/minecraft/server/level/TicketType;Lnet/minecraft/world/level/ChunkPos;ILjava/lang/Object;)V"
|
||||
target = "Lnet/minecraft/world/level/TicketStorage;removeTicket(Lnet/minecraft/server/level/Ticket;Lnet/minecraft/world/level/ChunkPos;)V"
|
||||
)
|
||||
)
|
||||
private <T> void skipTickingTicketTrackerRemove(final TickingTracker instance, final TicketType<T> ticketType,
|
||||
final ChunkPos chunkPos, final int i, final T object) {}
|
||||
private void skipTickingTicketTrackerRemove(final TicketStorage instance, final Ticket ticket, final ChunkPos pos) {}
|
||||
|
||||
/**
|
||||
* @reason Remove old chunk system hooks
|
||||
@@ -268,8 +226,9 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public String getTicketDebugString(final long pos) {
|
||||
return this.moonrise$getChunkHolderManager().getTicketDebugString(pos);
|
||||
public int getChunkLevel(final long pos, final boolean simulation) {
|
||||
final NewChunkHolder chunkHolder = this.moonrise$getChunkHolderManager().getChunkHolder(pos);
|
||||
return chunkHolder == null ? ChunkHolderManager.MAX_TICKET_LEVEL + 1 : chunkHolder.getTicketLevel();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -293,55 +252,30 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
|
||||
((ChunkSystemServerLevel)this.moonrise$getChunkMap().level).moonrise$getPlayerChunkLoader().setTickDistance(clamped);
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Route to new chunk system
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public void forEachEntityTickingChunk(final LongConsumer consumer) {
|
||||
final ReferenceList<LevelChunk> chunks = ((ChunkSystemServerLevel)this.moonrise$getChunkMap().level).moonrise$getEntityTickingChunks();
|
||||
final LevelChunk[] raw = chunks.getRawDataUnchecked();
|
||||
final int size = chunks.size();
|
||||
|
||||
Objects.checkFromToIndex(0, size, raw.length);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
final LevelChunk chunk = raw[i];
|
||||
|
||||
consumer.accept(CoordinateUtils.getChunkKey(chunk.getPos()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Route to new chunk system
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public String getDebugStatus() {
|
||||
return "No DistanceManager stats available";
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Remove old chunk system hooks
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public void dumpTickets(final String file) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Remove old chunk system hooks
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public TickingTracker tickingTracker() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Remove old chunk system hooks
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public LongSet getTickingChunks() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason This hack is not required anymore, see {@link MinecraftServerMixin}
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public void removeTicketsOnClosing() {}
|
||||
|
||||
/**
|
||||
* @reason This hack is not required anymore, see {@link MinecraftServerMixin}
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public boolean hasTickets() {
|
||||
throw new UnsupportedOperationException();
|
||||
return "N/A";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package ca.spottedleaf.moonrise.mixin.chunk_system;
|
||||
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.world.level.gameevent.DynamicGameEventListener;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(DynamicGameEventListener.class)
|
||||
abstract class DynamicGameEventListenerMixin {
|
||||
@Shadow
|
||||
@Nullable
|
||||
private SectionPos lastSection;
|
||||
|
||||
@Inject(
|
||||
method = "remove",
|
||||
at = @At("RETURN")
|
||||
)
|
||||
private void onRemove(final CallbackInfo ci) {
|
||||
// We need to unset the last section when removed, otherwise if the same instance is re-added at the same position it
|
||||
// will assume there was no change and fail to re-register.
|
||||
// In vanilla, chunks rarely unload and re-load quickly enough to trigger this issue. However, our chunk system has a
|
||||
// quirk where fast chunk reload cycles will often occur on player login (see PR #22).
|
||||
// So we fix this vanilla oversight as our changes cause it to manifest in bugs much more often (see issue #87).
|
||||
this.lastSection = null;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkData;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.mojang.logging.LogUtils;
|
||||
import net.minecraft.server.level.FullChunkStatus;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
@@ -32,10 +33,6 @@ abstract class EntityMixin implements ChunkSystemEntity {
|
||||
@Shadow
|
||||
protected abstract Stream<Entity> getIndirectPassengersStream();
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private static Logger LOGGER;
|
||||
|
||||
@Shadow
|
||||
private Level level;
|
||||
|
||||
@@ -43,6 +40,8 @@ abstract class EntityMixin implements ChunkSystemEntity {
|
||||
@Nullable
|
||||
private Entity.RemovalReason removalReason;
|
||||
|
||||
@Unique
|
||||
private static final Logger LOGGER = LogUtils.getLogger();
|
||||
|
||||
@Unique
|
||||
private final boolean isHardColliding = this.moonrise$isHardCollidingUncached();
|
||||
|
||||
@@ -25,7 +25,7 @@ abstract class EntityTickListMixin {
|
||||
private Int2ObjectMap<Entity> passive;
|
||||
|
||||
@Unique
|
||||
private final IteratorSafeOrderedReferenceSet<Entity> entities = new IteratorSafeOrderedReferenceSet<>();
|
||||
private final IteratorSafeOrderedReferenceSet<Entity> entities = new IteratorSafeOrderedReferenceSet<>(Entity.class);
|
||||
|
||||
/**
|
||||
* @reason Initialise new fields and destroy old state
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package ca.spottedleaf.moonrise.mixin.chunk_system;
|
||||
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.ticks.ChunkSystemLevelChunkTicks;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
@@ -48,7 +49,7 @@ abstract class LevelChunkMixin extends ChunkAccess implements ChunkSystemLevelCh
|
||||
private boolean postProcessingDone;
|
||||
|
||||
@Unique
|
||||
private ServerChunkCache.ChunkAndHolder chunkAndHolder;
|
||||
private NewChunkHolder chunkAndHolder;
|
||||
|
||||
@Override
|
||||
public final boolean moonrise$isPostProcessingDone() {
|
||||
@@ -56,12 +57,12 @@ abstract class LevelChunkMixin extends ChunkAccess implements ChunkSystemLevelCh
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ServerChunkCache.ChunkAndHolder moonrise$getChunkAndHolder() {
|
||||
public final NewChunkHolder moonrise$getChunkHolder() {
|
||||
return this.chunkAndHolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void moonrise$setChunkAndHolder(final ServerChunkCache.ChunkAndHolder holder) {
|
||||
public final void moonrise$setChunkHolder(final NewChunkHolder holder) {
|
||||
this.chunkAndHolder = holder;
|
||||
}
|
||||
|
||||
|
||||
@@ -105,12 +105,12 @@ abstract class LevelChunkTicksMixin<T> implements ChunkSystemLevelChunkTicks, Se
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Inject(
|
||||
method = "save(JLjava/util/function/Function;)Lnet/minecraft/nbt/ListTag;",
|
||||
method = "pack",
|
||||
at = @At(
|
||||
value = "HEAD"
|
||||
)
|
||||
)
|
||||
private void saveHook(final long time, final Function<T, String> idFunction, final CallbackInfoReturnable<ListTag> cir) {
|
||||
private void saveHook(final long time, final CallbackInfoReturnable<ListTag> cir) {
|
||||
this.lastSaved = time;
|
||||
}
|
||||
|
||||
|
||||
@@ -190,6 +190,11 @@ abstract class MinecraftServerMixin extends ReentrantBlockableEventLoop<TickTask
|
||||
)
|
||||
)
|
||||
private boolean doNotWaitChunkSystemShutdown(final Stream<ServerLevel> instance, final Predicate<? super ServerLevel> predicate) {
|
||||
// note: make sure we call deactivateTicketsOnClosing
|
||||
for (final ServerLevel world : this.getAllLevels()) {
|
||||
world.getChunkSource().deactivateTicketsOnClosing();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -238,9 +243,9 @@ abstract class MinecraftServerMixin extends ReentrantBlockableEventLoop<TickTask
|
||||
)
|
||||
)
|
||||
private void closeIOThreads(final CallbackInfo ci) {
|
||||
LOGGER.info("Waiting for I/O tasks to complete...");
|
||||
LOGGER.info("Waiting for all RegionFile I/O tasks to complete...");
|
||||
MoonriseRegionFileIO.flush((MinecraftServer)(Object)this);
|
||||
LOGGER.info("All I/O tasks to complete");
|
||||
LOGGER.info("All RegionFile I/O tasks to complete");
|
||||
if ((Object)this instanceof DedicatedServer) {
|
||||
MoonriseCommon.haltExecutors();
|
||||
}
|
||||
|
||||
@@ -3,18 +3,17 @@ package ca.spottedleaf.moonrise.mixin.chunk_system;
|
||||
import ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable;
|
||||
import ca.spottedleaf.concurrentutil.util.Priority;
|
||||
import ca.spottedleaf.moonrise.common.PlatformHooks;
|
||||
import ca.spottedleaf.moonrise.common.list.ReferenceList;
|
||||
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
||||
import ca.spottedleaf.moonrise.common.util.TickThread;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemServerChunkCache;
|
||||
import net.minecraft.server.level.ChunkHolder;
|
||||
import net.minecraft.server.level.ChunkLevel;
|
||||
import net.minecraft.server.level.ChunkResult;
|
||||
import net.minecraft.server.level.DistanceManager;
|
||||
import net.minecraft.server.level.FullChunkStatus;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
@@ -35,8 +34,6 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@@ -59,9 +56,6 @@ abstract class ServerChunkCacheMixin extends ChunkSource implements ChunkSystemS
|
||||
@Unique
|
||||
private final ConcurrentLong2ReferenceChainedHashTable<LevelChunk> fullChunks = new ConcurrentLong2ReferenceChainedHashTable<>();
|
||||
|
||||
@Unique
|
||||
private long chunksTicked;
|
||||
|
||||
@Override
|
||||
public final void moonrise$setFullChunk(final int chunkX, final int chunkZ, final LevelChunk chunk) {
|
||||
final long key = CoordinateUtils.getChunkKey(chunkX, chunkZ);
|
||||
@@ -339,38 +333,34 @@ abstract class ServerChunkCacheMixin extends ChunkSource implements ChunkSystemS
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Perform mid-tick chunk task processing during chunk tick
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Inject(
|
||||
method = "tickChunks(Lnet/minecraft/util/profiling/ProfilerFiller;JLjava/util/List;)V",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
shift = At.Shift.AFTER,
|
||||
target = "Lnet/minecraft/server/level/ServerLevel;tickChunk(Lnet/minecraft/world/level/chunk/LevelChunk;I)V"
|
||||
)
|
||||
)
|
||||
private void midTickChunks(final CallbackInfo ci) {
|
||||
if ((++this.chunksTicked & 7L) != 0L) {
|
||||
return;
|
||||
}
|
||||
|
||||
((ChunkSystemMinecraftServer)this.level.getServer()).moonrise$executeMidTickTasks();
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason In the chunk system, ticking chunks always have loaded entities. Of course, they are also always
|
||||
* marked to be as ticking as well.
|
||||
* @reason In the chunk system, spawn chunks will return only entity ticking chunks - we can elide the
|
||||
* entity ticking range check.
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Redirect(
|
||||
method = "tickChunks(Lnet/minecraft/util/profiling/ProfilerFiller;JLjava/util/List;)V",
|
||||
method = "tickSpawningChunk",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/server/level/ServerLevel;shouldTickBlocksAt(J)Z"
|
||||
target = "Lnet/minecraft/server/level/DistanceManager;inEntityTickingRange(J)Z"
|
||||
)
|
||||
)
|
||||
private boolean shortShouldTickBlocks(final ServerLevel instance, final long pos) {
|
||||
private boolean shortTickThunder(final DistanceManager instance, final long pos) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason In the chunk system, spawn chunks will return only entity ticking chunks - we can elide the
|
||||
* entity ticking check.
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Redirect(
|
||||
method = "tickSpawningChunk",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/server/level/ServerLevel;canSpawnEntitiesInChunk(Lnet/minecraft/world/level/ChunkPos;)Z"
|
||||
)
|
||||
)
|
||||
private boolean onlyCheckWBForSpawning(final ServerLevel instance, final ChunkPos pos) {
|
||||
return instance.getWorldBorder().isWithinBounds(pos);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.EntityData
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.PoiDataController;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevelReader;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunkHolder;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server.ServerEntityLookup;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager;
|
||||
@@ -27,13 +26,11 @@ import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ChunkHolder;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import net.minecraft.server.level.DistanceManager;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.progress.ChunkProgressListener;
|
||||
import net.minecraft.util.profiling.ProfilerFiller;
|
||||
import net.minecraft.world.RandomSequences;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
@@ -64,12 +61,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import java.io.Writer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
@Mixin(ServerLevel.class)
|
||||
@@ -121,16 +116,16 @@ abstract class ServerLevelMixin extends Level implements ChunkSystemServerLevel,
|
||||
private final NearbyPlayers nearbyPlayers = new NearbyPlayers((ServerLevel)(Object)this);
|
||||
|
||||
@Unique
|
||||
private static final ServerChunkCache.ChunkAndHolder[] EMPTY_CHUNK_AND_HOLDERS = new ServerChunkCache.ChunkAndHolder[0];
|
||||
private static final LevelChunk[] EMPTY_LEVEL_CHUNKS = new LevelChunk[0];
|
||||
|
||||
@Unique
|
||||
private final ReferenceList<ServerChunkCache.ChunkAndHolder> loadedChunks = new ReferenceList<>(EMPTY_CHUNK_AND_HOLDERS);
|
||||
private final ReferenceList<LevelChunk> loadedChunks = new ReferenceList<>(EMPTY_LEVEL_CHUNKS);
|
||||
|
||||
@Unique
|
||||
private final ReferenceList<ServerChunkCache.ChunkAndHolder> tickingChunks = new ReferenceList<>(EMPTY_CHUNK_AND_HOLDERS);
|
||||
private final ReferenceList<LevelChunk> tickingChunks = new ReferenceList<>(EMPTY_LEVEL_CHUNKS);
|
||||
|
||||
@Unique
|
||||
private final ReferenceList<ServerChunkCache.ChunkAndHolder> entityTickingChunks = new ReferenceList<>(EMPTY_CHUNK_AND_HOLDERS);
|
||||
private final ReferenceList<LevelChunk> entityTickingChunks = new ReferenceList<>(EMPTY_LEVEL_CHUNKS);
|
||||
|
||||
/**
|
||||
* @reason Initialise fields / destroy entity manager state
|
||||
@@ -334,17 +329,17 @@ abstract class ServerLevelMixin extends Level implements ChunkSystemServerLevel,
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ReferenceList<ServerChunkCache.ChunkAndHolder> moonrise$getLoadedChunks() {
|
||||
public final ReferenceList<LevelChunk> moonrise$getLoadedChunks() {
|
||||
return this.loadedChunks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ReferenceList<ServerChunkCache.ChunkAndHolder> moonrise$getTickingChunks() {
|
||||
public final ReferenceList<LevelChunk> moonrise$getTickingChunks() {
|
||||
return this.tickingChunks;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final ReferenceList<ServerChunkCache.ChunkAndHolder> moonrise$getEntityTickingChunks() {
|
||||
public final ReferenceList<LevelChunk> moonrise$getEntityTickingChunks() {
|
||||
return this.entityTickingChunks;
|
||||
}
|
||||
|
||||
@@ -666,7 +661,7 @@ abstract class ServerLevelMixin extends Level implements ChunkSystemServerLevel,
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public boolean isPositionEntityTicking(BlockPos pos) {
|
||||
public boolean isPositionEntityTicking(final BlockPos pos) {
|
||||
final NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(CoordinateUtils.getChunkKey(pos));
|
||||
return chunkHolder != null && chunkHolder.isEntityTickingReady();
|
||||
}
|
||||
@@ -676,7 +671,7 @@ abstract class ServerLevelMixin extends Level implements ChunkSystemServerLevel,
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public boolean isNaturalSpawningAllowed(final BlockPos pos) {
|
||||
public boolean areEntitiesActuallyLoadedAndTicking(final ChunkPos pos) {
|
||||
final NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(CoordinateUtils.getChunkKey(pos));
|
||||
return chunkHolder != null && chunkHolder.isEntityTickingReady();
|
||||
}
|
||||
@@ -685,8 +680,14 @@ abstract class ServerLevelMixin extends Level implements ChunkSystemServerLevel,
|
||||
* @reason Redirect to chunk system
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public boolean isNaturalSpawningAllowed(final ChunkPos pos) {
|
||||
@Redirect(
|
||||
method = "canSpawnEntitiesInChunk",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/level/entity/PersistentEntitySectionManager;canPositionTick(Lnet/minecraft/world/level/ChunkPos;)Z"
|
||||
)
|
||||
)
|
||||
private <T extends EntityAccess> boolean redirectCanEntitiesSpawnTickCheck(final PersistentEntitySectionManager<T> instance, final ChunkPos pos) {
|
||||
final NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(CoordinateUtils.getChunkKey(pos));
|
||||
return chunkHolder != null && chunkHolder.isEntityTickingReady();
|
||||
}
|
||||
|
||||
@@ -49,8 +49,7 @@ abstract class SortedArraySetMixin<T> extends AbstractSet<T> implements ChunkSys
|
||||
if (i >= len) {
|
||||
return false;
|
||||
}
|
||||
if (!filter.test(backingArray[i])) {
|
||||
++i;
|
||||
if (!filter.test(backingArray[i++])) {
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
@@ -58,7 +57,7 @@ abstract class SortedArraySetMixin<T> extends AbstractSet<T> implements ChunkSys
|
||||
|
||||
// we only want to write back to backingArray if we really need to
|
||||
|
||||
int lastIndex = i; // this is where new elements are shifted to
|
||||
int lastIndex = i - 1; // this is where new elements are shifted to
|
||||
|
||||
for (; i < len; ++i) {
|
||||
final T curr = backingArray[i];
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package ca.spottedleaf.moonrise.mixin.chunk_system;
|
||||
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicket;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType;
|
||||
import net.minecraft.server.level.Ticket;
|
||||
import net.minecraft.server.level.TicketType;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
@@ -8,61 +9,75 @@ import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import java.util.Comparator;
|
||||
|
||||
@Mixin(Ticket.class)
|
||||
abstract class TicketMixin<T> implements ChunkSystemTicket<T>, Comparable<Ticket<?>> {
|
||||
abstract class TicketMixin<T> implements ChunkSystemTicket<T>, Comparable<Ticket> {
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private TicketType<T> type;
|
||||
private TicketType type;
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private int ticketLevel;
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
public T key;
|
||||
private long ticksLeft;
|
||||
|
||||
|
||||
@Unique
|
||||
private long removeDelay;
|
||||
private T identifier;
|
||||
|
||||
@Override
|
||||
public final long moonrise$getRemoveDelay() {
|
||||
return this.removeDelay;
|
||||
return this.ticksLeft;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void moonrise$setRemoveDelay(final long removeDelay) {
|
||||
this.removeDelay = removeDelay;
|
||||
this.ticksLeft = removeDelay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final T moonrise$getIdentifier() {
|
||||
return this.identifier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void moonrise$setIdentifier(final T identifier) {
|
||||
if ((identifier == null) != (((ChunkSystemTicketType<T>)(Object)this.type).moonrise$getIdentifierComparator() == null)) {
|
||||
throw new IllegalStateException("Nullability of identifier should match nullability of comparator");
|
||||
}
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Change debug to include remove delay
|
||||
* @reason Change debug to include remove identifier
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Ticket[" + this.type + " " + this.ticketLevel + " (" + this.key + ")] to die in " + this.removeDelay;
|
||||
return "Ticket[" + this.type + " " + this.ticketLevel + " (" + this.identifier + ")] to die in " + this.ticksLeft;
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Remove old chunk system hook
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public void setCreatedTick(final long tickCreated) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
@Override
|
||||
public final int compareTo(final Ticket ticket) {
|
||||
final int levelCompare = Integer.compare(this.ticketLevel, ((TicketMixin<?>)(Object)ticket).ticketLevel);
|
||||
if (levelCompare != 0) {
|
||||
return levelCompare;
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Remove old chunk system hook
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public boolean timedOut(final long currentTick) {
|
||||
throw new UnsupportedOperationException();
|
||||
final int typeCompare = Long.compare(
|
||||
((ChunkSystemTicketType<T>)(Object)this.type).moonrise$getId(),
|
||||
((ChunkSystemTicketType<?>)(Object)((TicketMixin<?>)(Object)ticket).type).moonrise$getId()
|
||||
);
|
||||
if (typeCompare != 0) {
|
||||
return typeCompare;
|
||||
}
|
||||
|
||||
final Comparator<T> comparator = ((ChunkSystemTicketType<T>)(Object)this.type).moonrise$getIdentifierComparator();
|
||||
return comparator == null ? 0 : comparator.compare(this.identifier, ((TicketMixin<T>)(Object)ticket).identifier);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
package ca.spottedleaf.moonrise.mixin.chunk_system;
|
||||
|
||||
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicket;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketStorage;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType;
|
||||
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import net.minecraft.server.level.Ticket;
|
||||
import net.minecraft.server.level.TicketType;
|
||||
import net.minecraft.util.SortedArraySet;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.TicketStorage;
|
||||
import net.minecraft.world.level.saveddata.SavedData;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
@Mixin(TicketStorage.class)
|
||||
abstract class TicketStorageMixin extends SavedData implements ChunkSystemTicketStorage {
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private Long2ObjectOpenHashMap<List<Ticket>> deactivatedTickets;
|
||||
|
||||
@Shadow
|
||||
private Long2ObjectOpenHashMap<List<Ticket>> tickets;
|
||||
|
||||
@Shadow
|
||||
private LongSet chunksWithForcedTickets;
|
||||
|
||||
@Unique
|
||||
private ChunkMap chunkMap;
|
||||
|
||||
@Override
|
||||
public final ChunkMap moonrise$getChunkMap() {
|
||||
return this.chunkMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void moonrise$setChunkMap(final ChunkMap chunkMap) {
|
||||
this.chunkMap = chunkMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Destroy old chunk system state
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Inject(
|
||||
method = "<init>(Lit/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap;Lit/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap;)V",
|
||||
at = @At(
|
||||
value = "RETURN"
|
||||
)
|
||||
)
|
||||
private void destroyFields(Long2ObjectOpenHashMap p_393873_, Long2ObjectOpenHashMap p_394615_, CallbackInfo ci) {
|
||||
if (!this.tickets.isEmpty()) {
|
||||
throw new IllegalStateException("Expect tickets to be empty here!");
|
||||
}
|
||||
this.tickets = null;
|
||||
this.chunksWithForcedTickets = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason The forced chunks would be empty, as tickets should always be empty.
|
||||
* We need to do this to avoid throwing immediately.
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Redirect(
|
||||
method = "<init>(Lit/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap;Lit/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap;)V",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/level/TicketStorage;updateForcedChunks()V"
|
||||
)
|
||||
)
|
||||
private void avoidUpdatingForcedChunks(final TicketStorage instance) {}
|
||||
|
||||
|
||||
/**
|
||||
* @reason Redirect regular ticket retrieval to new chunk system
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Redirect(
|
||||
method = "forEachTicket(Ljava/util/function/BiConsumer;)V",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/level/TicketStorage;forEachTicket(Ljava/util/function/BiConsumer;Lit/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap;)V",
|
||||
ordinal = 0
|
||||
)
|
||||
)
|
||||
private void redirectRegularTickets(final BiConsumer<ChunkPos, Ticket> consumer, final Long2ObjectOpenHashMap<List<Ticket>> ticketsParam) {
|
||||
if (ticketsParam != null) {
|
||||
throw new IllegalStateException("Bad injection point");
|
||||
}
|
||||
|
||||
final Long2ObjectOpenHashMap<SortedArraySet<Ticket>> tickets = ((ChunkSystemServerLevel)this.chunkMap.level)
|
||||
.moonrise$getChunkTaskScheduler().chunkHolderManager.getTicketsCopy();
|
||||
|
||||
for (final Iterator<Long2ObjectMap.Entry<SortedArraySet<Ticket>>> iterator = tickets.long2ObjectEntrySet().fastIterator(); iterator.hasNext();) {
|
||||
final Long2ObjectMap.Entry<SortedArraySet<Ticket>> entry = iterator.next();
|
||||
|
||||
final long pos = entry.getLongKey();
|
||||
final SortedArraySet<Ticket> chunkTickets = entry.getValue();
|
||||
|
||||
final ChunkPos chunkPos = new ChunkPos(pos);
|
||||
|
||||
for (final Ticket ticket : chunkTickets) {
|
||||
consumer.accept(chunkPos, ticket);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @reason Avoid setting old chunk system state
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public void setLoadingChunkUpdatedListener(final TicketStorage.ChunkUpdated callback) {}
|
||||
|
||||
/**
|
||||
* @reason Avoid setting old chunk system state
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public void setSimulationChunkUpdatedListener(final TicketStorage.ChunkUpdated callback) {}
|
||||
|
||||
/**
|
||||
* @reason Redirect to new chunk system
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public boolean hasTickets() {
|
||||
return ((ChunkSystemServerLevel)this.chunkMap.level).moonrise$getChunkTaskScheduler().chunkHolderManager.hasTickets();
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Redirect to new chunk system
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public List<Ticket> getTickets(final long pos) {
|
||||
return ((ChunkSystemServerLevel)this.chunkMap.level).moonrise$getChunkTaskScheduler().chunkHolderManager
|
||||
.getTicketsAt(CoordinateUtils.getChunkX(pos), CoordinateUtils.getChunkZ(pos));
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Redirect to new chunk system
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public boolean addTicket(final long pos, final Ticket ticket) {
|
||||
final boolean ret = ((ChunkSystemServerLevel)this.chunkMap.level).moonrise$getChunkTaskScheduler().chunkHolderManager
|
||||
.addTicketAtLevel(ticket.getType(), pos, ticket.getTicketLevel(), ((ChunkSystemTicket<?>)ticket).moonrise$getIdentifier());
|
||||
|
||||
this.setDirty();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Redirect to new chunk system
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public boolean removeTicket(final long pos, final Ticket ticket) {
|
||||
final boolean ret = ((ChunkSystemServerLevel)this.chunkMap.level).moonrise$getChunkTaskScheduler().chunkHolderManager
|
||||
.removeTicketAtLevel(ticket.getType(), pos, ticket.getTicketLevel(), ((ChunkSystemTicket<?>)ticket).moonrise$getIdentifier());
|
||||
|
||||
if (ret) {
|
||||
this.setDirty();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Redirect to new chunk system
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public void purgeStaleTickets() {
|
||||
((ChunkSystemServerLevel)this.chunkMap.level).moonrise$getChunkTaskScheduler().chunkHolderManager.tick();
|
||||
this.setDirty();
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason All tickets (inactive or not) are packed and saved, so there's no real reason we need to remove them.
|
||||
* Vanilla removes them as it requires every chunk to go through the unload logic; however we already manually
|
||||
* do this on shutdown.
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Redirect(
|
||||
method = "deactivateTicketsOnClosing",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/world/level/TicketStorage;removeTicketIf(Ljava/util/function/Predicate;Lit/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap;)V"
|
||||
)
|
||||
)
|
||||
private void avoidRemovingTicketsOnShutdown(final TicketStorage instance,
|
||||
final Predicate<Ticket> predicate,
|
||||
final Long2ObjectOpenHashMap<List<Ticket>> tickets) {}
|
||||
|
||||
/**
|
||||
* @reason Destroy old chunk system hooks
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public void removeTicketIf(final Predicate<Ticket> predicate, final Long2ObjectOpenHashMap<List<Ticket>> into) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Destroy old chunk system hooks
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public void replaceTicketLevelOfType(final int newLevel, final TicketType forType) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Route to new chunk system
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public LongSet getForceLoadedChunks() {
|
||||
final Long2IntOpenHashMap forced = ((ChunkSystemServerLevel)this.chunkMap.level).moonrise$getChunkTaskScheduler()
|
||||
.chunkHolderManager.getTicketCounters(ChunkSystemTicketType.COUNTER_TYPE_FORCED);
|
||||
|
||||
if (forced == null) {
|
||||
return LongSet.of();
|
||||
}
|
||||
|
||||
return forced.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Destroy old chunk system hooks
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public LongSet getAllChunksWithTicketThat(final Predicate<Ticket> predicate) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package ca.spottedleaf.moonrise.mixin.chunk_system;
|
||||
|
||||
import ca.spottedleaf.moonrise.common.PlatformHooks;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType;
|
||||
import net.minecraft.server.level.TicketType;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
import java.util.Comparator;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
@Mixin(TicketType.class)
|
||||
abstract class TicketTypeMixin<T> implements ChunkSystemTicketType<T> {
|
||||
|
||||
@Unique
|
||||
private static AtomicLong ID_GENERATOR;
|
||||
|
||||
/**
|
||||
* @reason Need to initialise at the start of clinit, as ticket types are constructed after.
|
||||
* Using just the field initialiser would append the static initialiser.
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Inject(
|
||||
method = "<clinit>",
|
||||
at = @At(
|
||||
value = "HEAD"
|
||||
)
|
||||
)
|
||||
private static void initIdGenerator(final CallbackInfo ci) {
|
||||
ID_GENERATOR = new AtomicLong();
|
||||
}
|
||||
|
||||
@Unique
|
||||
private final long id = ID_GENERATOR.getAndIncrement();
|
||||
|
||||
@Unique
|
||||
private Comparator<T> identifierComparator;
|
||||
|
||||
@Unique
|
||||
private volatile long[] counterTypes;
|
||||
|
||||
@Override
|
||||
public final long moonrise$getId() {
|
||||
return this.id;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Comparator<T> moonrise$getIdentifierComparator() {
|
||||
return this.identifierComparator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void moonrise$setIdentifierComparator(final Comparator<T> comparator) {
|
||||
this.identifierComparator = comparator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final long[] moonrise$getCounterTypes() {
|
||||
// need to lazy init this because we cannot check if we are FORCED during construction
|
||||
final long[] types = this.counterTypes;
|
||||
if (types != null) {
|
||||
return types;
|
||||
}
|
||||
|
||||
return this.counterTypes = PlatformHooks.get().getCounterTypesUncached((TicketType)(Object)this);
|
||||
}
|
||||
}
|
||||
@@ -2,18 +2,27 @@ package ca.spottedleaf.moonrise.mixin.chunk_tick_iteration;
|
||||
|
||||
import ca.spottedleaf.moonrise.common.list.ReferenceList;
|
||||
import ca.spottedleaf.moonrise.common.misc.NearbyPlayers;
|
||||
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkData;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickDistanceManager;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickServerLevel;
|
||||
import com.llamalad7.mixinextras.sugar.Local;
|
||||
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.longs.LongIterator;
|
||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import org.spongepowered.asm.mixin.*;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
@@ -85,11 +94,15 @@ abstract class ChunkMapMixin {
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Avoid checking first if there are nearby players, as we make internal perform this implicitly.
|
||||
* @reason Avoid checking for DEFAULT state, as we make internal perform this implicitly.
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public boolean anyPlayerCloseEnoughForSpawning(final ChunkPos pos) {
|
||||
if (((ChunkTickDistanceManager)this.distanceManager).moonrise$hasAnyNearbyNarrow(pos.x, pos.z)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.anyPlayerCloseEnoughForSpawningInternal(pos);
|
||||
}
|
||||
|
||||
@@ -152,4 +165,111 @@ abstract class ChunkMapMixin {
|
||||
|
||||
return ret == null ? new ArrayList<>() : ret;
|
||||
}
|
||||
|
||||
@Unique
|
||||
private boolean isChunkNearPlayer(final ChunkMap chunkMap, final ChunkPos chunkPos, final LevelChunk levelChunk) {
|
||||
final ChunkData chunkData = ((ChunkSystemLevelChunk)levelChunk).moonrise$getChunkHolder().holderData;
|
||||
final NearbyPlayers.TrackedChunk nearbyPlayers = chunkData.nearbyPlayers;
|
||||
if (nearbyPlayers == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (((ChunkTickDistanceManager)this.distanceManager).moonrise$hasAnyNearbyNarrow(chunkPos.x, chunkPos.z)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
final ReferenceList<ServerPlayer> players = nearbyPlayers.getPlayers(NearbyPlayers.NearbyMapType.SPAWN_RANGE);
|
||||
|
||||
if (players == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final ServerPlayer[] raw = players.getRawDataUnchecked();
|
||||
final int len = players.size();
|
||||
|
||||
Objects.checkFromIndexSize(0, len, raw.length);
|
||||
for (int i = 0; i < len; ++i) {
|
||||
if (chunkMap.playerIsCloseEnoughForSpawning(raw[i], chunkPos)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Use the player ticking chunks list, which already contains chunks that are:
|
||||
* 1. entity ticking
|
||||
* 2. within spawn range (8 chunks on any axis)
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Inject(
|
||||
method = "collectSpawningChunks",
|
||||
// use cancellable inject to be compatible with the chunk system's hook here
|
||||
cancellable = true,
|
||||
at = @At(
|
||||
value = "HEAD"
|
||||
)
|
||||
)
|
||||
public void collectSpawningChunks(final List<LevelChunk> list, final CallbackInfo ci) {
|
||||
final ReferenceList<LevelChunk> tickingChunks = ((ChunkTickServerLevel)this.level).moonrise$getPlayerTickingChunks();
|
||||
|
||||
final Long2IntOpenHashMap forceSpawningChunks = ((ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler()
|
||||
.chunkHolderManager.getTicketCounters(ChunkSystemTicketType.COUNTER_TYPER_NATURAL_SPAWNING_FORCED);
|
||||
|
||||
final LevelChunk[] raw = tickingChunks.getRawDataUnchecked();
|
||||
final int size = tickingChunks.size();
|
||||
|
||||
Objects.checkFromToIndex(0, size, raw.length);
|
||||
|
||||
if (forceSpawningChunks != null && !forceSpawningChunks.isEmpty()) {
|
||||
// note: expect forceSpawningChunks.size <<< tickingChunks.size
|
||||
final LongOpenHashSet seen = new LongOpenHashSet(forceSpawningChunks.size());
|
||||
|
||||
final ChunkHolderManager chunkHolderManager = ((ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager;
|
||||
|
||||
// note: this fixes a bug in neoforge where these chunks don't tick away from a player...
|
||||
// note: this is NOT the only problem with their implementation, either...
|
||||
for (final LongIterator iterator = forceSpawningChunks.keySet().longIterator(); iterator.hasNext();) {
|
||||
final long pos = iterator.nextLong();
|
||||
|
||||
final NewChunkHolder holder = chunkHolderManager.getChunkHolder(pos);
|
||||
|
||||
if (holder == null || !holder.isEntityTickingReady()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
seen.add(pos);
|
||||
|
||||
list.add((LevelChunk)holder.getCurrentChunk());
|
||||
}
|
||||
|
||||
for (int i = 0; i < size; ++i) {
|
||||
final LevelChunk levelChunk = raw[i];
|
||||
|
||||
if (seen.contains(CoordinateUtils.getChunkKey(levelChunk.getPos()))) {
|
||||
// do not add duplicate chunks
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!this.isChunkNearPlayer((ChunkMap)(Object)this, levelChunk.getPos(), levelChunk)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
list.add(levelChunk);
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < size; ++i) {
|
||||
final LevelChunk levelChunk = raw[i];
|
||||
|
||||
if (!this.isChunkNearPlayer((ChunkMap)(Object)this, levelChunk.getPos(), levelChunk)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
list.add(levelChunk);
|
||||
}
|
||||
}
|
||||
|
||||
ci.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import it.unimi.dsi.fastutil.longs.LongIterator;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.server.level.DistanceManager;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.util.TriState;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
@@ -21,20 +22,24 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
abstract class DistanceManagerMixin implements ChunkTickDistanceManager {
|
||||
|
||||
@Shadow
|
||||
private DistanceManager.FixedPlayerDistanceChunkTracker naturalSpawnChunkCounter;
|
||||
public DistanceManager.FixedPlayerDistanceChunkTracker naturalSpawnChunkCounter;
|
||||
|
||||
|
||||
@Unique
|
||||
private final PositionCountingAreaMap<ServerPlayer> spawnChunkTracker = new PositionCountingAreaMap<>();
|
||||
@Unique
|
||||
private final PositionCountingAreaMap<ServerPlayer> narrowSpawnChunkTracker = new PositionCountingAreaMap<>();
|
||||
|
||||
@Override
|
||||
public final void moonrise$addPlayer(final ServerPlayer player, final SectionPos pos) {
|
||||
this.spawnChunkTracker.add(player, pos.x(), pos.z(), ChunkTickConstants.PLAYER_SPAWN_TRACK_RANGE);
|
||||
this.narrowSpawnChunkTracker.add(player, pos.x(), pos.z(), ChunkTickConstants.NARROW_SPAWN_TRACK_RANGE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void moonrise$removePlayer(final ServerPlayer player, final SectionPos pos) {
|
||||
this.spawnChunkTracker.remove(player);
|
||||
this.narrowSpawnChunkTracker.remove(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -43,11 +48,18 @@ abstract class DistanceManagerMixin implements ChunkTickDistanceManager {
|
||||
final boolean oldIgnore, final boolean newIgnore) {
|
||||
if (newIgnore) {
|
||||
this.spawnChunkTracker.remove(player);
|
||||
this.narrowSpawnChunkTracker.remove(player);
|
||||
} else {
|
||||
this.spawnChunkTracker.addOrUpdate(player, newPos.x(), newPos.z(), ChunkTickConstants.PLAYER_SPAWN_TRACK_RANGE);
|
||||
this.narrowSpawnChunkTracker.addOrUpdate(player, newPos.x(), newPos.z(), ChunkTickConstants.NARROW_SPAWN_TRACK_RANGE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean moonrise$hasAnyNearbyNarrow(final int chunkX, final int chunkZ) {
|
||||
return this.narrowSpawnChunkTracker.hasObjectsNear(chunkX, chunkZ);
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Destroy natural spawning tracker field to prevent it from being used
|
||||
* @author Spottedleaf
|
||||
@@ -104,8 +116,11 @@ abstract class DistanceManagerMixin implements ChunkTickDistanceManager {
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public boolean hasPlayersNearby(final long pos) {
|
||||
return this.spawnChunkTracker.hasObjectsNear(CoordinateUtils.getChunkX(pos), CoordinateUtils.getChunkZ(pos));
|
||||
public TriState hasPlayersNearby(final long pos) {
|
||||
if (this.narrowSpawnChunkTracker.hasObjectsNear(pos)) {
|
||||
return TriState.TRUE;
|
||||
}
|
||||
return this.spawnChunkTracker.hasObjectsNear(pos) ? TriState.DEFAULT : TriState.FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,30 +1,26 @@
|
||||
package ca.spottedleaf.moonrise.mixin.chunk_tick_iteration;
|
||||
|
||||
import ca.spottedleaf.moonrise.common.list.ReferenceList;
|
||||
import ca.spottedleaf.moonrise.common.misc.NearbyPlayers;
|
||||
import ca.spottedleaf.moonrise.common.util.SimpleThreadUnsafeRandom;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkData;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunkHolder;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickServerLevel;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.util.RandomSource;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.GameRules;
|
||||
import net.minecraft.world.level.chunk.ChunkSource;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Overwrite;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Mixin(ServerChunkCache.class)
|
||||
abstract class ServerChunkCacheMixin extends ChunkSource {
|
||||
@@ -41,69 +37,13 @@ abstract class ServerChunkCacheMixin extends ChunkSource {
|
||||
@Unique
|
||||
private final SimpleThreadUnsafeRandom shuffleRandom = new SimpleThreadUnsafeRandom(0L);
|
||||
|
||||
@Unique
|
||||
private boolean isChunkNearPlayer(final ChunkMap chunkMap, final ChunkPos chunkPos, final LevelChunk levelChunk) {
|
||||
final ChunkData chunkData = ((ChunkSystemChunkHolder)((ChunkSystemLevelChunk)levelChunk).moonrise$getChunkAndHolder().holder())
|
||||
.moonrise$getRealChunkHolder().holderData;
|
||||
final NearbyPlayers.TrackedChunk nearbyPlayers = chunkData.nearbyPlayers;
|
||||
if (nearbyPlayers == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final ReferenceList<ServerPlayer> players = nearbyPlayers.getPlayers(NearbyPlayers.NearbyMapType.SPAWN_RANGE);
|
||||
|
||||
if (players == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final ServerPlayer[] raw = players.getRawDataUnchecked();
|
||||
final int len = players.size();
|
||||
|
||||
Objects.checkFromIndexSize(0, len, raw.length);
|
||||
for (int i = 0; i < len; ++i) {
|
||||
if (chunkMap.playerIsCloseEnoughForSpawning(raw[i], chunkPos)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Use the player ticking chunks list, which already contains chunks that are:
|
||||
* 1. block ticking
|
||||
* 2. within spawn range (8 chunks on any axis)
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
private void collectTickingChunks(final List<LevelChunk> list) {
|
||||
final ReferenceList<ServerChunkCache.ChunkAndHolder> tickingChunks =
|
||||
((ChunkTickServerLevel)this.level).moonrise$getPlayerTickingChunks();
|
||||
|
||||
final ServerChunkCache.ChunkAndHolder[] raw = tickingChunks.getRawDataUnchecked();
|
||||
final int size = tickingChunks.size();
|
||||
|
||||
final ChunkMap chunkMap = this.chunkMap;
|
||||
|
||||
for (int i = 0; i < size; ++i) {
|
||||
final ServerChunkCache.ChunkAndHolder chunkAndHolder = raw[i];
|
||||
final LevelChunk levelChunk = chunkAndHolder.chunk();
|
||||
|
||||
if (!this.isChunkNearPlayer(chunkMap, levelChunk.getPos(), levelChunk)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
list.add(levelChunk);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Use random implementation which does not use CAS and has a faster nextInt(int)
|
||||
* function
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Redirect(
|
||||
method = "tickChunks()V",
|
||||
method = "tickChunks(Lnet/minecraft/util/profiling/ProfilerFiller;J)V",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/Util;shuffle(Ljava/util/List;Lnet/minecraft/util/RandomSource;)V"
|
||||
@@ -113,4 +53,41 @@ abstract class ServerChunkCacheMixin extends ChunkSource {
|
||||
this.shuffleRandom.setSeed(randomSource.nextLong());
|
||||
Util.shuffle(list, this.shuffleRandom);
|
||||
}
|
||||
|
||||
/**
|
||||
* @reason Do not iterate over entire chunk holder map; additionally perform mid-tick chunk task execution
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Redirect(
|
||||
method = "tickChunks(Lnet/minecraft/util/profiling/ProfilerFiller;J)V",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/server/level/ChunkMap;forEachBlockTickingChunk(Ljava/util/function/Consumer;)V"
|
||||
)
|
||||
)
|
||||
private void iterateTickingChunksFaster(final ChunkMap instance, final Consumer<LevelChunk> consumer) {
|
||||
final ServerLevel world = this.level;
|
||||
final int randomTickSpeed = world.getGameRules().getInt(GameRules.RULE_RANDOMTICKING);
|
||||
|
||||
// TODO check on update: impl of forEachBlockTickingChunk will only iterate ENTITY ticking chunks!
|
||||
// TODO check on update: consumer just runs tickChunk
|
||||
final ReferenceList<LevelChunk> entityTickingChunks = ((ChunkSystemServerLevel)world).moonrise$getEntityTickingChunks();
|
||||
|
||||
// note: we can use the backing array here because:
|
||||
// 1. we do not care about new additions
|
||||
// 2. _removes_ are impossible at this stage in the tick
|
||||
final LevelChunk[] raw = entityTickingChunks.getRawDataUnchecked();
|
||||
final int size = entityTickingChunks.size();
|
||||
|
||||
Objects.checkFromToIndex(0, size, raw.length);
|
||||
for (int i = 0; i < size; ++i) {
|
||||
world.tickChunk(raw[i], randomTickSpeed);
|
||||
|
||||
// call mid-tick tasks for chunk system
|
||||
if ((i & 7) == 0) {
|
||||
((ChunkSystemMinecraftServer)this.level.getServer()).moonrise$executeMidTickTasks();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,16 +19,16 @@ import org.spongepowered.asm.mixin.Unique;
|
||||
abstract class ServerLevelMixin implements ChunkTickServerLevel {
|
||||
|
||||
@Unique
|
||||
private static final ServerChunkCache.ChunkAndHolder[] EMPTY_PLAYER_CHUNK_HOLDERS = new ServerChunkCache.ChunkAndHolder[0];
|
||||
private static final LevelChunk[] EMPTY_LEVEL_CHUNKS = new LevelChunk[0];
|
||||
|
||||
@Unique
|
||||
private final ReferenceList<ServerChunkCache.ChunkAndHolder> playerTickingChunks = new ReferenceList<>(EMPTY_PLAYER_CHUNK_HOLDERS);
|
||||
private final ReferenceList<LevelChunk> playerTickingChunks = new ReferenceList<>(EMPTY_LEVEL_CHUNKS);
|
||||
|
||||
@Unique
|
||||
private final Long2IntOpenHashMap playerTickingRequests = new Long2IntOpenHashMap();
|
||||
|
||||
@Override
|
||||
public final ReferenceList<ServerChunkCache.ChunkAndHolder> moonrise$getPlayerTickingChunks() {
|
||||
public final ReferenceList<LevelChunk> moonrise$getPlayerTickingChunks() {
|
||||
return this.playerTickingChunks;
|
||||
}
|
||||
|
||||
@@ -39,12 +39,12 @@ abstract class ServerLevelMixin implements ChunkTickServerLevel {
|
||||
return;
|
||||
}
|
||||
|
||||
this.playerTickingChunks.add(((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder());
|
||||
this.playerTickingChunks.add(chunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void moonrise$removeChunkForPlayerTicking(final LevelChunk chunk) {
|
||||
this.playerTickingChunks.remove(((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder());
|
||||
this.playerTickingChunks.remove(chunk);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -65,9 +65,7 @@ abstract class ServerLevelMixin implements ChunkTickServerLevel {
|
||||
return;
|
||||
}
|
||||
|
||||
this.playerTickingChunks.add(
|
||||
((ChunkSystemLevelChunk)(LevelChunk)chunkHolder.getCurrentChunk()).moonrise$getChunkAndHolder()
|
||||
);
|
||||
this.playerTickingChunks.add((LevelChunk)chunkHolder.getCurrentChunk());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -93,8 +91,6 @@ abstract class ServerLevelMixin implements ChunkTickServerLevel {
|
||||
return;
|
||||
}
|
||||
|
||||
this.playerTickingChunks.remove(
|
||||
((ChunkSystemLevelChunk)(LevelChunk)chunkHolder.getCurrentChunk()).moonrise$getChunkAndHolder()
|
||||
);
|
||||
this.playerTickingChunks.remove((LevelChunk)chunkHolder.getCurrentChunk());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ interface EntityGetterMixin {
|
||||
@Overwrite
|
||||
default boolean isUnobstructed(final Entity entity, final VoxelShape voxel) {
|
||||
if (voxel.isEmpty()) {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
final AABB singleAABB = ((CollisionVoxelShape)voxel).moonrise$getSingleAABBRepresentation();
|
||||
|
||||
@@ -55,7 +55,7 @@ abstract class LevelMixin implements LevelAccessor, AutoCloseable {
|
||||
public boolean isUnobstructed(final Entity entity) {
|
||||
final AABB boundingBox = entity.getBoundingBox();
|
||||
if (CollisionUtil.isEmpty(boundingBox)) {
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
final List<Entity> entities = this.getEntities(
|
||||
|
||||
@@ -345,11 +345,8 @@ abstract class ShapesMixin {
|
||||
* @author Spottedleaf
|
||||
*/
|
||||
@Overwrite
|
||||
public static boolean blockOccudes(final VoxelShape first, final VoxelShape second, final Direction direction) {
|
||||
final boolean firstBlock = first == BLOCK;
|
||||
final boolean secondBlock = second == BLOCK;
|
||||
|
||||
if (firstBlock & secondBlock) {
|
||||
public static boolean blockOccludes(final VoxelShape first, final VoxelShape second, final Direction direction) {
|
||||
if (first == BLOCK & second == BLOCK) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ interface ServerAddressResolverMixin {
|
||||
@Redirect(
|
||||
method = {
|
||||
"method_36903",
|
||||
"*(Lnet/minecraft/client/multiplayer/resolver/ServerAddress;)Ljava/util/Optional;"
|
||||
"lambda$static$0"
|
||||
},
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
|
||||
@@ -49,10 +49,10 @@ import java.util.function.Supplier;
|
||||
abstract class ThreadedLevelLightEngineMixin extends LevelLightEngine implements StarLightLightingProvider {
|
||||
|
||||
@Shadow
|
||||
private ConsecutiveExecutor consecutiveExecutor;
|
||||
public ConsecutiveExecutor consecutiveExecutor;
|
||||
|
||||
@Shadow
|
||||
private ChunkTaskDispatcher taskDispatcher;
|
||||
public ChunkTaskDispatcher taskDispatcher;
|
||||
|
||||
public ThreadedLevelLightEngineMixin(final LightChunkGetter chunkProvider, final boolean hasBlockLight, final boolean hasSkyLight) {
|
||||
super(chunkProvider, hasBlockLight, hasSkyLight);
|
||||
@@ -86,10 +86,10 @@ abstract class ThreadedLevelLightEngineMixin extends LevelLightEngine implements
|
||||
|
||||
final Long ticketId = Long.valueOf(this.chunkWorkCounter.getAndIncrement());
|
||||
final ChunkPos pos = new ChunkPos(chunkX, chunkZ);
|
||||
world.getChunkSource().addRegionTicket(StarLightInterface.CHUNK_WORK_TICKET, pos, StarLightInterface.REGION_LIGHT_TICKET_LEVEL, ticketId);
|
||||
((ChunkSystemServerLevel)world).moonrise$getChunkTaskScheduler().chunkHolderManager.addTicketAtLevel(StarLightInterface.CHUNK_WORK_TICKET, pos, StarLightInterface.LIGHT_TICKET_LEVEL, ticketId);
|
||||
|
||||
scheduledTask.queueOrRunTask(() -> {
|
||||
world.getChunkSource().removeRegionTicket(StarLightInterface.CHUNK_WORK_TICKET, pos, StarLightInterface.REGION_LIGHT_TICKET_LEVEL, ticketId);
|
||||
((ChunkSystemServerLevel)world).moonrise$getChunkTaskScheduler().chunkHolderManager.removeTicketAtLevel(StarLightInterface.CHUNK_WORK_TICKET, pos, StarLightInterface.LIGHT_TICKET_LEVEL, ticketId);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ abstract class ThreadedLevelLightEngineMixin extends LevelLightEngine implements
|
||||
final ChunkPos pos = iterator.next();
|
||||
|
||||
final Long id = ChunkTaskScheduler.getNextChunkRelightId();
|
||||
world.getChunkSource().addRegionTicket(ChunkTaskScheduler.CHUNK_RELIGHT, pos, StarLightInterface.REGION_LIGHT_TICKET_LEVEL, id);
|
||||
((ChunkSystemServerLevel)world).moonrise$getChunkTaskScheduler().chunkHolderManager.addTicketAtLevel(ChunkTaskScheduler.CHUNK_RELIGHT, pos, StarLightInterface.LIGHT_TICKET_LEVEL, id);
|
||||
ticketIds.put(pos, id);
|
||||
|
||||
final ChunkAccess chunk = (ChunkAccess)world.getChunkSource().getChunkForLighting(pos.x, pos.z);
|
||||
@@ -113,7 +113,7 @@ abstract class ThreadedLevelLightEngineMixin extends LevelLightEngine implements
|
||||
// cannot relight this chunk
|
||||
iterator.remove();
|
||||
ticketIds.remove(pos);
|
||||
world.getChunkSource().removeRegionTicket(ChunkTaskScheduler.CHUNK_RELIGHT, pos, StarLightInterface.REGION_LIGHT_TICKET_LEVEL, id);
|
||||
((ChunkSystemServerLevel)world).moonrise$getChunkTaskScheduler().chunkHolderManager.removeTicketAtLevel(ChunkTaskScheduler.CHUNK_RELIGHT, pos, StarLightInterface.LIGHT_TICKET_LEVEL, id);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -160,9 +160,9 @@ abstract class ThreadedLevelLightEngineMixin extends LevelLightEngine implements
|
||||
}
|
||||
|
||||
for (final Map.Entry<ChunkPos, Long> entry : ticketIds.entrySet()) {
|
||||
world.getChunkSource().removeRegionTicket(
|
||||
((ChunkSystemServerLevel)world).moonrise$getChunkTaskScheduler().chunkHolderManager.removeTicketAtLevel(
|
||||
ChunkTaskScheduler.CHUNK_RELIGHT, entry.getKey(),
|
||||
StarLightInterface.REGION_LIGHT_TICKET_LEVEL, entry.getValue()
|
||||
StarLightInterface.LIGHT_TICKET_LEVEL, entry.getValue()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,13 +60,13 @@ abstract class SerializableChunkDataMixin {
|
||||
method = "parse",
|
||||
at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/nbt/CompoundTag;getBoolean(Ljava/lang/String;)Z",
|
||||
target = "Lnet/minecraft/nbt/CompoundTag;getBooleanOr(Ljava/lang/String;Z)Z",
|
||||
ordinal = 0
|
||||
)
|
||||
)
|
||||
private static boolean setLightCorrect(final CompoundTag instance, final String string,
|
||||
private static boolean setLightCorrect(final CompoundTag instance, final String string, final boolean dfl,
|
||||
@Local(ordinal = 0, argsOnly = false) final ChunkStatus status) {
|
||||
final boolean starlightCorrect = instance.get("isLightOn") != null && instance.getInt(SaveUtil.STARLIGHT_VERSION_TAG) == SaveUtil.STARLIGHT_LIGHT_VERSION;
|
||||
final boolean starlightCorrect = instance.get("isLightOn") != null && instance.getIntOr(SaveUtil.STARLIGHT_VERSION_TAG, -1) == SaveUtil.STARLIGHT_LIGHT_VERSION;
|
||||
return status.isOrAfter(ChunkStatus.LIGHT) && starlightCorrect;
|
||||
}
|
||||
|
||||
@@ -84,17 +84,17 @@ abstract class SerializableChunkDataMixin {
|
||||
)
|
||||
private static SerializableChunkData.SectionData readStarlightState(final int y, final LevelChunkSection chunkSection,
|
||||
final DataLayer blockLight, final DataLayer skyLight,
|
||||
@Local(ordinal = 3, argsOnly = false) final CompoundTag sectionData) {
|
||||
@Local(ordinal = 2, argsOnly = false) final CompoundTag sectionData) {
|
||||
final SerializableChunkData.SectionData ret = new SerializableChunkData.SectionData(
|
||||
y, chunkSection, blockLight, skyLight
|
||||
);
|
||||
|
||||
if (sectionData.contains(SaveUtil.BLOCKLIGHT_STATE_TAG, Tag.TAG_ANY_NUMERIC)) {
|
||||
((StarlightSectionData)(Object)ret).starlight$setBlockLightState(sectionData.getInt(SaveUtil.BLOCKLIGHT_STATE_TAG));
|
||||
if (sectionData.contains(SaveUtil.BLOCKLIGHT_STATE_TAG)) {
|
||||
((StarlightSectionData)(Object)ret).starlight$setBlockLightState(sectionData.getIntOr(SaveUtil.BLOCKLIGHT_STATE_TAG, 0));
|
||||
}
|
||||
|
||||
if (sectionData.contains(SaveUtil.SKYLIGHT_STATE_TAG, Tag.TAG_ANY_NUMERIC)) {
|
||||
((StarlightSectionData)(Object)ret).starlight$setSkyLightState(sectionData.getInt(SaveUtil.SKYLIGHT_STATE_TAG));
|
||||
if (sectionData.contains(SaveUtil.SKYLIGHT_STATE_TAG)) {
|
||||
((StarlightSectionData)(Object)ret).starlight$setSkyLightState(sectionData.getIntOr(SaveUtil.SKYLIGHT_STATE_TAG, 0));
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
@@ -19,8 +19,7 @@ public final class ChunkSystemConverters {
|
||||
}
|
||||
|
||||
private static int getDataVersion(final CompoundTag data, final int dfl) {
|
||||
return !data.contains(SharedConstants.DATA_VERSION_TAG, Tag.TAG_ANY_NUMERIC)
|
||||
? dfl : data.getInt(SharedConstants.DATA_VERSION_TAG);
|
||||
return data.getIntOr(SharedConstants.DATA_VERSION_TAG, dfl);
|
||||
}
|
||||
|
||||
public static CompoundTag convertPoiCompoundTag(final CompoundTag data, final ServerLevel world) {
|
||||
|
||||
@@ -1143,7 +1143,7 @@ public final class MoonriseRegionFileIO {
|
||||
LOGGER.error("Failed to decompress chunk data for task: " + this.toString(), thr);
|
||||
}
|
||||
|
||||
if (compoundTag == null) {
|
||||
if (throwable == null && compoundTag == null) {
|
||||
// need to re-try from the start
|
||||
this.scheduleReadIO();
|
||||
return;
|
||||
|
||||
@@ -48,7 +48,7 @@ public final class EntityDataController extends MoonriseRegionFileIO.RegionDataC
|
||||
}
|
||||
|
||||
private static void checkPosition(final ChunkPos pos, final CompoundTag nbt) {
|
||||
final ChunkPos nbtPos = nbt == null ? null : EntityStorage.readChunkPos(nbt);
|
||||
final ChunkPos nbtPos = nbt == null ? null : nbt.read("Position", ChunkPos.CODEC).orElse(null);
|
||||
if (nbtPos != null && !pos.equals(nbtPos)) {
|
||||
throw new IllegalArgumentException(
|
||||
"Entity chunk coordinate and serialized data do not have matching coordinates, trying to serialize coordinate " + pos.toString()
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package ca.spottedleaf.moonrise.patches.chunk_system.level;
|
||||
|
||||
import ca.spottedleaf.concurrentutil.util.Priority;
|
||||
import ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet;
|
||||
import ca.spottedleaf.moonrise.common.list.ReferenceList;
|
||||
import ca.spottedleaf.moonrise.common.misc.NearbyPlayers;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;
|
||||
@@ -10,6 +11,7 @@ import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ChunkHolder;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
@@ -56,9 +58,9 @@ public interface ChunkSystemServerLevel extends ChunkSystemLevel {
|
||||
|
||||
public NearbyPlayers moonrise$getNearbyPlayers();
|
||||
|
||||
public ReferenceList<ServerChunkCache.ChunkAndHolder> moonrise$getLoadedChunks();
|
||||
public ReferenceList<LevelChunk> moonrise$getLoadedChunks();
|
||||
|
||||
public ReferenceList<ServerChunkCache.ChunkAndHolder> moonrise$getTickingChunks();
|
||||
public ReferenceList<LevelChunk> moonrise$getTickingChunks();
|
||||
|
||||
public ReferenceList<ServerChunkCache.ChunkAndHolder> moonrise$getEntityTickingChunks();
|
||||
public ReferenceList<LevelChunk> moonrise$getEntityTickingChunks();
|
||||
}
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
package ca.spottedleaf.moonrise.patches.chunk_system.level.chunk;
|
||||
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder;
|
||||
|
||||
public interface ChunkSystemLevelChunk {
|
||||
|
||||
public boolean moonrise$isPostProcessingDone();
|
||||
|
||||
public ServerChunkCache.ChunkAndHolder moonrise$getChunkAndHolder();
|
||||
public NewChunkHolder moonrise$getChunkHolder();
|
||||
|
||||
public void moonrise$setChunkAndHolder(final ServerChunkCache.ChunkAndHolder holder);
|
||||
public void moonrise$setChunkHolder(final NewChunkHolder holder);
|
||||
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ public final class ChunkEntitySlices {
|
||||
|
||||
public static List<Entity> readEntities(final ServerLevel world, final CompoundTag compoundTag) {
|
||||
// TODO check this and below on update for format changes
|
||||
return EntityType.loadEntitiesRecursive(compoundTag.getList("Entities", 10), world, EntitySpawnReason.LOAD).collect(ImmutableList.toImmutableList());
|
||||
return EntityType.loadEntitiesRecursive(compoundTag.getListOrEmpty("Entities"), world, EntitySpawnReason.LOAD).collect(ImmutableList.toImmutableList());
|
||||
}
|
||||
|
||||
// Paper start - rewrite chunk system
|
||||
@@ -84,12 +84,12 @@ public final class ChunkEntitySlices {
|
||||
if (from == null) {
|
||||
return;
|
||||
}
|
||||
final ListTag entitiesFrom = from.getList("Entities", Tag.TAG_COMPOUND);
|
||||
final ListTag entitiesFrom = from.getListOrEmpty("Entities");
|
||||
if (entitiesFrom == null || entitiesFrom.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final ListTag entitiesInto = into.getList("Entities", Tag.TAG_COMPOUND);
|
||||
final ListTag entitiesInto = into.getListOrEmpty("Entities");
|
||||
into.put("Entities", entitiesInto); // this is in case into doesn't have any entities
|
||||
entitiesInto.addAll(0, entitiesFrom);
|
||||
}
|
||||
@@ -112,7 +112,7 @@ public final class ChunkEntitySlices {
|
||||
}
|
||||
final CompoundTag ret = NbtUtils.addCurrentDataVersion(new CompoundTag());
|
||||
ret.put("Entities", entitiesTag);
|
||||
EntityStorage.writeChunkPos(ret, chunkPos);
|
||||
ret.store("Position", ChunkPos.CODEC, chunkPos);
|
||||
|
||||
return !force && entitiesTag.isEmpty() ? null : ret;
|
||||
}
|
||||
|
||||
@@ -179,6 +179,10 @@ public abstract class EntityLookup implements LevelEntityGetter<Entity> {
|
||||
}
|
||||
}
|
||||
|
||||
public Iterable<Entity> getAllMapped() {
|
||||
return this.entityByUUID.values();
|
||||
}
|
||||
|
||||
public int getEntityCount() {
|
||||
synchronized (this.accessibleEntities) {
|
||||
return this.accessibleEntities.size();
|
||||
|
||||
@@ -159,7 +159,7 @@ public final class PoiChunk {
|
||||
|
||||
final RegistryOps<Tag> registryOps = RegistryOps.create(NbtOps.INSTANCE, world.registryAccess());
|
||||
|
||||
final CompoundTag sections = data.getCompound("Sections");
|
||||
final CompoundTag sections = data.getCompoundOrEmpty("Sections");
|
||||
|
||||
if (sections.isEmpty()) {
|
||||
// nothing to parse
|
||||
@@ -176,7 +176,7 @@ public final class PoiChunk {
|
||||
continue;
|
||||
}
|
||||
|
||||
final CompoundTag section = sections.getCompound(key);
|
||||
final CompoundTag section = sections.getCompoundOrEmpty(key);
|
||||
final DataResult<PoiSection.Packed> deserializeResult = PoiSection.Packed.CODEC.parse(registryOps, section);
|
||||
final int finalSectionY = sectionY;
|
||||
final PoiSection.Packed packed = deserializeResult.resultOrPartial((final String description) -> {
|
||||
|
||||
@@ -14,6 +14,7 @@ import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunk
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.util.ParallelSearchRadiusIteration;
|
||||
import com.google.gson.JsonObject;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap;
|
||||
@@ -45,11 +46,8 @@ import java.util.function.Function;
|
||||
|
||||
public final class RegionizedPlayerChunkLoader {
|
||||
|
||||
public static final TicketType<Long> PLAYER_TICKET = TicketType.create("chunk_system:player_ticket", Long::compareTo);
|
||||
public static final TicketType<Long> PLAYER_TICKET_DELAYED = TicketType.create("chunk_system:player_ticket_delayed", Long::compareTo, 5 * 20);
|
||||
|
||||
public static final int MIN_VIEW_DISTANCE = 2;
|
||||
public static final int MAX_VIEW_DISTANCE = 32;
|
||||
public static final TicketType PLAYER_TICKET = ChunkSystemTicketType.create("chunk_system:player_ticket", Long::compareTo);
|
||||
public static final TicketType PLAYER_TICKET_DELAYED = ChunkSystemTicketType.create("chunk_system:player_ticket_delayed", Long::compareTo, 5L * 20L);
|
||||
|
||||
public static final int GENERATED_TICKET_LEVEL = ChunkHolderManager.FULL_LOADED_TICKET_LEVEL;
|
||||
public static final int LOADED_TICKET_LEVEL = ChunkTaskScheduler.getTicketLevel(ChunkStatus.EMPTY);
|
||||
@@ -685,8 +683,7 @@ public final class RegionizedPlayerChunkLoader {
|
||||
}
|
||||
this.pushDelayedTicketOp(
|
||||
ChunkHolderManager.TicketOperation.addOp(
|
||||
chunk,
|
||||
PLAYER_TICKET, LOADED_TICKET_LEVEL, this.idBoxed
|
||||
chunk, PLAYER_TICKET, LOADED_TICKET_LEVEL, this.idBoxed
|
||||
)
|
||||
);
|
||||
chunks.add(chunk);
|
||||
|
||||
@@ -16,9 +16,11 @@ import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.ChunkLoadTas
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.ChunkProgressionTask;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.GenericDataLoadTask;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicket;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.util.ChunkSystemSortedArraySet;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ByteLinkedOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ByteMap;
|
||||
import it.unimi.dsi.fastutil.longs.Long2IntMap;
|
||||
@@ -65,13 +67,12 @@ public final class ChunkHolderManager {
|
||||
public static final int ENTITY_TICKING_TICKET_LEVEL = ChunkLevel.ENTITY_TICKING_LEVEL;
|
||||
public static final int MAX_TICKET_LEVEL = ChunkLevel.MAX_LEVEL; // inclusive
|
||||
|
||||
public static final TicketType<Unit> UNLOAD_COOLDOWN = TicketType.create("unload_cooldown", (u1, u2) -> 0, 5 * 20);
|
||||
public static final TicketType UNLOAD_COOLDOWN = ChunkSystemTicketType.create("chunk_system:unload_cooldown", null, 5L * 20L);
|
||||
|
||||
private static final long NO_TIMEOUT_MARKER = Long.MIN_VALUE;
|
||||
private static final long PROBE_MARKER = Long.MIN_VALUE + 1;
|
||||
public final ReentrantAreaLock ticketLockArea;
|
||||
|
||||
private final ConcurrentLong2ReferenceChainedHashTable<SortedArraySet<Ticket<?>>> tickets = new ConcurrentLong2ReferenceChainedHashTable<>();
|
||||
private final ConcurrentLong2ReferenceChainedHashTable<SortedArraySet<Ticket>> tickets = new ConcurrentLong2ReferenceChainedHashTable<>();
|
||||
private final ConcurrentLong2ReferenceChainedHashTable<Long2IntOpenHashMap> sectionToChunkToExpireCount = new ConcurrentLong2ReferenceChainedHashTable<>();
|
||||
final ChunkUnloadQueue unloadQueue;
|
||||
|
||||
@@ -102,6 +103,8 @@ public final class ChunkHolderManager {
|
||||
return Long.compare(coord1, coord2);
|
||||
});
|
||||
|
||||
private final ConcurrentLong2ReferenceChainedHashTable<Long2IntOpenHashMap> ticketCounters = new ConcurrentLong2ReferenceChainedHashTable<>();
|
||||
|
||||
public ChunkHolderManager(final ServerLevel world, final ChunkTaskScheduler taskScheduler) {
|
||||
this.world = world;
|
||||
this.taskScheduler = taskScheduler;
|
||||
@@ -163,7 +166,6 @@ public final class ChunkHolderManager {
|
||||
return this.chunkHolders.size();
|
||||
}
|
||||
|
||||
// TODO replace the need for this, specifically: optimise ServerChunkCache#tickChunks
|
||||
public Iterable<ChunkHolder> getOldChunkHoldersIterable() {
|
||||
return new Iterable<ChunkHolder>() {
|
||||
@Override
|
||||
@@ -411,7 +413,7 @@ public final class ChunkHolderManager {
|
||||
public String getTicketDebugString(final long coordinate) {
|
||||
final ReentrantAreaLock.Node ticketLock = this.ticketLockArea.lock(CoordinateUtils.getChunkX(coordinate), CoordinateUtils.getChunkZ(coordinate));
|
||||
try {
|
||||
final SortedArraySet<Ticket<?>> tickets = this.tickets.get(coordinate);
|
||||
final SortedArraySet<Ticket> tickets = this.tickets.get(coordinate);
|
||||
|
||||
return tickets != null ? tickets.first().toString() : "no_ticket";
|
||||
} finally {
|
||||
@@ -421,8 +423,40 @@ public final class ChunkHolderManager {
|
||||
}
|
||||
}
|
||||
|
||||
public Long2ObjectOpenHashMap<SortedArraySet<Ticket<?>>> getTicketsCopy() {
|
||||
final Long2ObjectOpenHashMap<SortedArraySet<Ticket<?>>> ret = new Long2ObjectOpenHashMap<>();
|
||||
public boolean hasTickets() {
|
||||
return !this.tickets.isEmpty();
|
||||
}
|
||||
|
||||
public List<Ticket> getTicketsAt(final int chunkX, final int chunkZ) {
|
||||
final long key = CoordinateUtils.getChunkKey(chunkX, chunkZ);
|
||||
|
||||
if (!this.tickets.containsKey(key)) {
|
||||
// avoid contending lock
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
final ReentrantAreaLock.Node lock = this.ticketLockArea.lock(chunkX, chunkZ);
|
||||
try {
|
||||
final SortedArraySet<Ticket> tickets = this.tickets.get(key);
|
||||
|
||||
if (tickets == null) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
final List<Ticket> ret = new ArrayList<>(tickets.size());
|
||||
|
||||
for (final Ticket ticket : tickets) {
|
||||
ret.add(ticket);
|
||||
}
|
||||
|
||||
return ret;
|
||||
} finally {
|
||||
this.ticketLockArea.unlock(lock);
|
||||
}
|
||||
}
|
||||
|
||||
public Long2ObjectOpenHashMap<SortedArraySet<Ticket>> getTicketsCopy() {
|
||||
final Long2ObjectOpenHashMap<SortedArraySet<Ticket>> ret = new Long2ObjectOpenHashMap<>();
|
||||
final Long2ObjectOpenHashMap<LongArrayList> sections = new Long2ObjectOpenHashMap<>();
|
||||
final int sectionShift = this.taskScheduler.getChunkSystemLockShift();
|
||||
for (final PrimitiveIterator.OfLong iterator = this.tickets.keyIterator(); iterator.hasNext();) {
|
||||
@@ -451,12 +485,12 @@ public final class ChunkHolderManager {
|
||||
try {
|
||||
for (final LongIterator iterator2 = coordinates.iterator(); iterator2.hasNext();) {
|
||||
final long coord = iterator2.nextLong();
|
||||
final SortedArraySet<Ticket<?>> tickets = this.tickets.get(coord);
|
||||
final SortedArraySet<Ticket> tickets = this.tickets.get(coord);
|
||||
if (tickets == null) {
|
||||
// removed before we acquired lock
|
||||
continue;
|
||||
}
|
||||
ret.put(coord, ((ChunkSystemSortedArraySet<Ticket<?>>)tickets).moonrise$copy());
|
||||
ret.put(coord, ((ChunkSystemSortedArraySet<Ticket>)tickets).moonrise$copy());
|
||||
}
|
||||
} finally {
|
||||
this.ticketLockArea.unlock(ticketLock);
|
||||
@@ -474,16 +508,16 @@ public final class ChunkHolderManager {
|
||||
}
|
||||
}
|
||||
|
||||
private static int getTicketLevelAt(SortedArraySet<Ticket<?>> tickets) {
|
||||
private static int getTicketLevelAt(final SortedArraySet<Ticket> tickets) {
|
||||
return !tickets.isEmpty() ? tickets.first().getTicketLevel() : MAX_TICKET_LEVEL + 1;
|
||||
}
|
||||
|
||||
public <T> boolean addTicketAtLevel(final TicketType<T> type, final ChunkPos chunkPos, final int level,
|
||||
public <T> boolean addTicketAtLevel(final TicketType type, final ChunkPos chunkPos, final int level,
|
||||
final T identifier) {
|
||||
return this.addTicketAtLevel(type, CoordinateUtils.getChunkKey(chunkPos), level, identifier);
|
||||
}
|
||||
|
||||
public <T> boolean addTicketAtLevel(final TicketType<T> type, final int chunkX, final int chunkZ, final int level,
|
||||
public <T> boolean addTicketAtLevel(final TicketType type, final int chunkX, final int chunkZ, final int level,
|
||||
final T identifier) {
|
||||
return this.addTicketAtLevel(type, CoordinateUtils.getChunkKey(chunkX, chunkZ), level, identifier);
|
||||
}
|
||||
@@ -524,29 +558,29 @@ public final class ChunkHolderManager {
|
||||
|
||||
// supposed to return true if the ticket was added and did not replace another
|
||||
// but, we always return false if the ticket cannot be added
|
||||
public <T> boolean addTicketAtLevel(final TicketType<T> type, final long chunk, final int level, final T identifier) {
|
||||
public <T> boolean addTicketAtLevel(final TicketType type, final long chunk, final int level, final T identifier) {
|
||||
return this.addTicketAtLevel(type, chunk, level, identifier, true);
|
||||
}
|
||||
|
||||
<T> boolean addTicketAtLevel(final TicketType<T> type, final long chunk, final int level, final T identifier, final boolean lock) {
|
||||
final long removeDelay = type.timeout <= 0 ? NO_TIMEOUT_MARKER : type.timeout;
|
||||
<T> boolean addTicketAtLevel(final TicketType type, final long chunk, final int level, final T identifier, final boolean lock) {
|
||||
final long removeDelay = type.timeout() <= 0 ? NO_TIMEOUT_MARKER : type.timeout();
|
||||
if (level > MAX_TICKET_LEVEL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int chunkX = CoordinateUtils.getChunkX(chunk);
|
||||
final int chunkZ = CoordinateUtils.getChunkZ(chunk);
|
||||
final Ticket<T> ticket = new Ticket<>(type, level, identifier);
|
||||
((ChunkSystemTicket<T>)(Object)ticket).moonrise$setRemoveDelay(removeDelay);
|
||||
final Ticket ticket = new Ticket(type, level, removeDelay);
|
||||
((ChunkSystemTicket<T>)(Object)ticket).moonrise$setIdentifier(identifier);
|
||||
|
||||
final ReentrantAreaLock.Node ticketLock = lock ? this.ticketLockArea.lock(chunkX, chunkZ) : null;
|
||||
try {
|
||||
final SortedArraySet<Ticket<?>> ticketsAtChunk = this.tickets.computeIfAbsent(chunk, (final long keyInMap) -> {
|
||||
return SortedArraySet.create(4);
|
||||
final SortedArraySet<Ticket> ticketsAtChunk = this.tickets.computeIfAbsent(chunk, (final long keyInMap) -> {
|
||||
return (SortedArraySet)SortedArraySet.create(4);
|
||||
});
|
||||
|
||||
final int levelBefore = getTicketLevelAt(ticketsAtChunk);
|
||||
final Ticket<T> current = (Ticket<T>)((ChunkSystemSortedArraySet<Ticket<?>>)ticketsAtChunk).moonrise$replace(ticket);
|
||||
final Ticket current = (Ticket)((ChunkSystemSortedArraySet<Ticket>)ticketsAtChunk).moonrise$replace(ticket);
|
||||
final int levelAfter = getTicketLevelAt(ticketsAtChunk);
|
||||
|
||||
if (current != ticket) {
|
||||
@@ -563,6 +597,7 @@ public final class ChunkHolderManager {
|
||||
if (removeDelay != NO_TIMEOUT_MARKER) {
|
||||
this.addExpireCount(chunkX, chunkZ);
|
||||
}
|
||||
this.addTicketCounter(type, chunk);
|
||||
}
|
||||
|
||||
if (levelBefore != levelAfter) {
|
||||
@@ -577,36 +612,85 @@ public final class ChunkHolderManager {
|
||||
}
|
||||
}
|
||||
|
||||
public <T> boolean removeTicketAtLevel(final TicketType<T> type, final ChunkPos chunkPos, final int level, final T identifier) {
|
||||
private void addTicketCounter(final TicketType type, final long pos) {
|
||||
final long[] counterTypes = ((ChunkSystemTicketType<?>)(Object)type).moonrise$getCounterTypes();
|
||||
if (counterTypes.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (this.ticketCounters) {
|
||||
for (final long counterType : counterTypes) {
|
||||
final Long2IntOpenHashMap oldCounters = this.ticketCounters.get(counterType);
|
||||
final Long2IntOpenHashMap newCounters = oldCounters == null ? new Long2IntOpenHashMap() : oldCounters.clone();
|
||||
|
||||
newCounters.addTo(pos, 1);
|
||||
|
||||
this.ticketCounters.put(counterType, newCounters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void removeTicketCounter(final TicketType type, final long pos) {
|
||||
final long[] counterTypes = ((ChunkSystemTicketType<?>)(Object)type).moonrise$getCounterTypes();
|
||||
if (counterTypes.length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
synchronized (this.ticketCounters) {
|
||||
for (final long counterType : counterTypes) {
|
||||
final Long2IntOpenHashMap oldCounters = this.ticketCounters.get(counterType);
|
||||
final Long2IntOpenHashMap newCounters = oldCounters == null ? new Long2IntOpenHashMap() : oldCounters.clone();
|
||||
|
||||
final int currCount = newCounters.get(pos);
|
||||
if (currCount <= 0) {
|
||||
throw new IllegalStateException("Count must be > 0 at this stage");
|
||||
}
|
||||
if (currCount == 1) {
|
||||
newCounters.remove(pos);
|
||||
} else {
|
||||
newCounters.put(pos, currCount - 1);
|
||||
}
|
||||
|
||||
this.ticketCounters.put(counterType, newCounters);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Long2IntOpenHashMap getTicketCounters(final long counterType) {
|
||||
return this.ticketCounters.get(counterType);
|
||||
}
|
||||
|
||||
public <T> boolean removeTicketAtLevel(final TicketType type, final ChunkPos chunkPos, final int level, final T identifier) {
|
||||
return this.removeTicketAtLevel(type, CoordinateUtils.getChunkKey(chunkPos), level, identifier);
|
||||
}
|
||||
|
||||
public <T> boolean removeTicketAtLevel(final TicketType<T> type, final int chunkX, final int chunkZ, final int level, final T identifier) {
|
||||
public <T> boolean removeTicketAtLevel(final TicketType type, final int chunkX, final int chunkZ, final int level, final T identifier) {
|
||||
return this.removeTicketAtLevel(type, CoordinateUtils.getChunkKey(chunkX, chunkZ), level, identifier);
|
||||
}
|
||||
|
||||
public <T> boolean removeTicketAtLevel(final TicketType<T> type, final long chunk, final int level, final T identifier) {
|
||||
public <T> boolean removeTicketAtLevel(final TicketType type, final long chunk, final int level, final T identifier) {
|
||||
return this.removeTicketAtLevel(type, chunk, level, identifier, true);
|
||||
}
|
||||
|
||||
<T> boolean removeTicketAtLevel(final TicketType<T> type, final long chunk, final int level, final T identifier, final boolean lock) {
|
||||
<T> boolean removeTicketAtLevel(final TicketType type, final long chunk, final int level, final T identifier, final boolean lock) {
|
||||
if (level > MAX_TICKET_LEVEL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int chunkX = CoordinateUtils.getChunkX(chunk);
|
||||
final int chunkZ = CoordinateUtils.getChunkZ(chunk);
|
||||
final Ticket<T> probe = new Ticket<>(type, level, identifier);
|
||||
final Ticket probe = new Ticket(type, level, 0L);
|
||||
((ChunkSystemTicket<T>)(Object)probe).moonrise$setIdentifier(identifier);
|
||||
|
||||
final ReentrantAreaLock.Node ticketLock = lock ? this.ticketLockArea.lock(chunkX, chunkZ) : null;
|
||||
try {
|
||||
final SortedArraySet<Ticket<?>> ticketsAtChunk = this.tickets.get(chunk);
|
||||
final SortedArraySet<Ticket> ticketsAtChunk = this.tickets.get(chunk);
|
||||
if (ticketsAtChunk == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final int oldLevel = getTicketLevelAt(ticketsAtChunk);
|
||||
final Ticket<T> ticket = (Ticket<T>)((ChunkSystemSortedArraySet<Ticket<?>>)ticketsAtChunk).moonrise$removeAndGet(probe);
|
||||
final Ticket ticket = (Ticket)((ChunkSystemSortedArraySet<Ticket>)ticketsAtChunk).moonrise$removeAndGet(probe);
|
||||
|
||||
if (ticket == null) {
|
||||
return false;
|
||||
@@ -615,8 +699,7 @@ public final class ChunkHolderManager {
|
||||
final int newLevel = getTicketLevelAt(ticketsAtChunk);
|
||||
// we should not change the ticket levels while the target region may be ticking
|
||||
if (oldLevel != newLevel) {
|
||||
final Ticket<ChunkPos> unknownTicket = new Ticket<>(TicketType.UNKNOWN, level, new ChunkPos(chunk));
|
||||
((ChunkSystemTicket<ChunkPos>)(Object)unknownTicket).moonrise$setRemoveDelay(Math.max(1, TicketType.UNKNOWN.timeout));
|
||||
final Ticket unknownTicket = new Ticket(TicketType.UNKNOWN, level);
|
||||
if (ticketsAtChunk.add(unknownTicket)) {
|
||||
this.addExpireCount(chunkX, chunkZ);
|
||||
} else {
|
||||
@@ -629,6 +712,8 @@ public final class ChunkHolderManager {
|
||||
this.removeExpireCount(chunkX, chunkZ);
|
||||
}
|
||||
|
||||
this.removeTicketCounter(type, chunk);
|
||||
|
||||
return true;
|
||||
} finally {
|
||||
if (ticketLock != null) {
|
||||
@@ -638,8 +723,8 @@ public final class ChunkHolderManager {
|
||||
}
|
||||
|
||||
// atomic with respect to all add/remove/addandremove ticket calls for the given chunk
|
||||
public <T, V> void addAndRemoveTickets(final long chunk, final TicketType<T> addType, final int addLevel, final T addIdentifier,
|
||||
final TicketType<V> removeType, final int removeLevel, final V removeIdentifier) {
|
||||
public <T, V> void addAndRemoveTickets(final long chunk, final TicketType addType, final int addLevel, final T addIdentifier,
|
||||
final TicketType removeType, final int removeLevel, final V removeIdentifier) {
|
||||
final ReentrantAreaLock.Node ticketLock = this.ticketLockArea.lock(CoordinateUtils.getChunkX(chunk), CoordinateUtils.getChunkZ(chunk));
|
||||
try {
|
||||
this.addTicketAtLevel(addType, chunk, addLevel, addIdentifier, false);
|
||||
@@ -650,8 +735,8 @@ public final class ChunkHolderManager {
|
||||
}
|
||||
|
||||
// atomic with respect to all add/remove/addandremove ticket calls for the given chunk
|
||||
public <T, V> boolean addIfRemovedTicket(final long chunk, final TicketType<T> addType, final int addLevel, final T addIdentifier,
|
||||
final TicketType<V> removeType, final int removeLevel, final V removeIdentifier) {
|
||||
public <T, V> boolean addIfRemovedTicket(final long chunk, final TicketType addType, final int addLevel, final T addIdentifier,
|
||||
final TicketType removeType, final int removeLevel, final V removeIdentifier) {
|
||||
final ReentrantAreaLock.Node ticketLock = this.ticketLockArea.lock(CoordinateUtils.getChunkX(chunk), CoordinateUtils.getChunkZ(chunk));
|
||||
try {
|
||||
if (this.removeTicketAtLevel(removeType, chunk, removeLevel, removeIdentifier, false)) {
|
||||
@@ -664,7 +749,7 @@ public final class ChunkHolderManager {
|
||||
}
|
||||
}
|
||||
|
||||
public <T> void removeAllTicketsFor(final TicketType<T> ticketType, final int ticketLevel, final T ticketIdentifier) {
|
||||
public <T> void removeAllTicketsFor(final TicketType ticketType, final int ticketLevel, final T ticketIdentifier) {
|
||||
if (ticketLevel > MAX_TICKET_LEVEL) {
|
||||
return;
|
||||
}
|
||||
@@ -710,7 +795,7 @@ public final class ChunkHolderManager {
|
||||
|
||||
final int sectionShift = ((ChunkSystemServerLevel)this.world).moonrise$getRegionChunkShift();
|
||||
|
||||
final Predicate<Ticket<?>> expireNow = (final Ticket<?> ticket) -> {
|
||||
final Predicate<Ticket> expireNow = (final Ticket ticket) -> {
|
||||
long removeDelay = ((ChunkSystemTicket<?>)(Object)ticket).moonrise$getRemoveDelay();
|
||||
if (removeDelay == NO_TIMEOUT_MARKER) {
|
||||
return false;
|
||||
@@ -746,7 +831,7 @@ public final class ChunkHolderManager {
|
||||
final long chunkKey = entry.getLongKey();
|
||||
final int expireCount = entry.getIntValue();
|
||||
|
||||
final SortedArraySet<Ticket<?>> tickets = this.tickets.get(chunkKey);
|
||||
final SortedArraySet<Ticket> tickets = this.tickets.get(chunkKey);
|
||||
final int levelBefore = getTicketLevelAt(tickets);
|
||||
|
||||
final int sizeBefore = tickets.size();
|
||||
@@ -1164,7 +1249,7 @@ public final class ChunkHolderManager {
|
||||
this.removeChunkHolder(holder);
|
||||
} else {
|
||||
// add cooldown so the next unload check is not immediately next tick
|
||||
this.addTicketAtLevel(UNLOAD_COOLDOWN, CoordinateUtils.getChunkKey(holder.chunkX, holder.chunkZ), MAX_TICKET_LEVEL, Unit.INSTANCE, false);
|
||||
this.addTicketAtLevel(UNLOAD_COOLDOWN, CoordinateUtils.getChunkKey(holder.chunkX, holder.chunkZ), MAX_TICKET_LEVEL, null, false);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
@@ -1188,42 +1273,42 @@ public final class ChunkHolderManager {
|
||||
|
||||
public static record TicketOperation<T, V> (
|
||||
TicketOperationType op, long chunkCoord,
|
||||
TicketType<T> ticketType, int ticketLevel, T identifier,
|
||||
TicketType<V> ticketType2, int ticketLevel2, V identifier2
|
||||
TicketType ticketType, int ticketLevel, T identifier,
|
||||
TicketType ticketType2, int ticketLevel2, V identifier2
|
||||
) {
|
||||
|
||||
private TicketOperation(TicketOperationType op, long chunkCoord,
|
||||
TicketType<T> ticketType, int ticketLevel, T identifier) {
|
||||
TicketType ticketType, int ticketLevel, T identifier) {
|
||||
this(op, chunkCoord, ticketType, ticketLevel, identifier, null, 0, null);
|
||||
}
|
||||
|
||||
public static <T> TicketOperation<T, T> addOp(final ChunkPos chunk, final TicketType<T> type, final int ticketLevel, final T identifier) {
|
||||
public static <T> TicketOperation<T, T> addOp(final ChunkPos chunk, final TicketType type, final int ticketLevel, final T identifier) {
|
||||
return addOp(CoordinateUtils.getChunkKey(chunk), type, ticketLevel, identifier);
|
||||
}
|
||||
|
||||
public static <T> TicketOperation<T, T> addOp(final int chunkX, final int chunkZ, final TicketType<T> type, final int ticketLevel, final T identifier) {
|
||||
public static <T> TicketOperation<T, T> addOp(final int chunkX, final int chunkZ, final TicketType type, final int ticketLevel, final T identifier) {
|
||||
return addOp(CoordinateUtils.getChunkKey(chunkX, chunkZ), type, ticketLevel, identifier);
|
||||
}
|
||||
|
||||
public static <T> TicketOperation<T, T> addOp(final long chunk, final TicketType<T> type, final int ticketLevel, final T identifier) {
|
||||
public static <T> TicketOperation<T, T> addOp(final long chunk, final TicketType type, final int ticketLevel, final T identifier) {
|
||||
return new TicketOperation<>(TicketOperationType.ADD, chunk, type, ticketLevel, identifier);
|
||||
}
|
||||
|
||||
public static <T> TicketOperation<T, T> removeOp(final ChunkPos chunk, final TicketType<T> type, final int ticketLevel, final T identifier) {
|
||||
public static <T> TicketOperation<T, T> removeOp(final ChunkPos chunk, final TicketType type, final int ticketLevel, final T identifier) {
|
||||
return removeOp(CoordinateUtils.getChunkKey(chunk), type, ticketLevel, identifier);
|
||||
}
|
||||
|
||||
public static <T> TicketOperation<T, T> removeOp(final int chunkX, final int chunkZ, final TicketType<T> type, final int ticketLevel, final T identifier) {
|
||||
public static <T> TicketOperation<T, T> removeOp(final int chunkX, final int chunkZ, final TicketType type, final int ticketLevel, final T identifier) {
|
||||
return removeOp(CoordinateUtils.getChunkKey(chunkX, chunkZ), type, ticketLevel, identifier);
|
||||
}
|
||||
|
||||
public static <T> TicketOperation<T, T> removeOp(final long chunk, final TicketType<T> type, final int ticketLevel, final T identifier) {
|
||||
public static <T> TicketOperation<T, T> removeOp(final long chunk, final TicketType type, final int ticketLevel, final T identifier) {
|
||||
return new TicketOperation<>(TicketOperationType.REMOVE, chunk, type, ticketLevel, identifier);
|
||||
}
|
||||
|
||||
public static <T, V> TicketOperation<T, V> addIfRemovedOp(final long chunk,
|
||||
final TicketType<T> addType, final int addLevel, final T addIdentifier,
|
||||
final TicketType<V> removeType, final int removeLevel, final V removeIdentifier) {
|
||||
final TicketType addType, final int addLevel, final T addIdentifier,
|
||||
final TicketType removeType, final int removeLevel, final V removeIdentifier) {
|
||||
return new TicketOperation<>(
|
||||
TicketOperationType.ADD_IF_REMOVED, chunk, addType, addLevel, addIdentifier,
|
||||
removeType, removeLevel, removeIdentifier
|
||||
@@ -1231,8 +1316,8 @@ public final class ChunkHolderManager {
|
||||
}
|
||||
|
||||
public static <T, V> TicketOperation<T, V> addAndRemove(final long chunk,
|
||||
final TicketType<T> addType, final int addLevel, final T addIdentifier,
|
||||
final TicketType<V> removeType, final int removeLevel, final V removeIdentifier) {
|
||||
final TicketType addType, final int addLevel, final T addIdentifier,
|
||||
final TicketType removeType, final int removeLevel, final V removeIdentifier) {
|
||||
return new TicketOperation<>(
|
||||
TicketOperationType.ADD_AND_REMOVE, chunk, addType, addLevel, addIdentifier,
|
||||
removeType, removeLevel, removeIdentifier
|
||||
@@ -1391,11 +1476,11 @@ public final class ChunkHolderManager {
|
||||
final JsonArray allTicketsJson = new JsonArray();
|
||||
ret.add("tickets", allTicketsJson);
|
||||
|
||||
for (final Iterator<ConcurrentLong2ReferenceChainedHashTable.TableEntry<SortedArraySet<Ticket<?>>>> iterator = this.tickets.entryIterator();
|
||||
for (final Iterator<ConcurrentLong2ReferenceChainedHashTable.TableEntry<SortedArraySet<Ticket>>> iterator = this.tickets.entryIterator();
|
||||
iterator.hasNext();) {
|
||||
final ConcurrentLong2ReferenceChainedHashTable.TableEntry<SortedArraySet<Ticket<?>>> coordinateTickets = iterator.next();
|
||||
final ConcurrentLong2ReferenceChainedHashTable.TableEntry<SortedArraySet<Ticket>> coordinateTickets = iterator.next();
|
||||
final long coordinate = coordinateTickets.getKey();
|
||||
final SortedArraySet<Ticket<?>> tickets = coordinateTickets.getValue();
|
||||
final SortedArraySet<Ticket> tickets = coordinateTickets.getValue();
|
||||
|
||||
final JsonObject coordinateJson = new JsonObject();
|
||||
allTicketsJson.add(coordinateJson);
|
||||
@@ -1410,17 +1495,17 @@ public final class ChunkHolderManager {
|
||||
// directly over the set using the iterator
|
||||
// however, it also means we need to null-check the values, and there is a possibility that we _miss_ an
|
||||
// entry OR iterate over an entry multiple times
|
||||
for (final Object ticketUncasted : ((ChunkSystemSortedArraySet<Ticket<?>>)tickets).moonrise$copyBackingArray()) {
|
||||
for (final Object ticketUncasted : ((ChunkSystemSortedArraySet<Ticket>)tickets).moonrise$copyBackingArray()) {
|
||||
if (ticketUncasted == null) {
|
||||
continue;
|
||||
}
|
||||
final Ticket<?> ticket = (Ticket<?>)ticketUncasted;
|
||||
final Ticket ticket = (Ticket)ticketUncasted;
|
||||
final JsonObject ticketSerialized = new JsonObject();
|
||||
ticketsSerialized.add(ticketSerialized);
|
||||
|
||||
ticketSerialized.addProperty("type", ticket.getType().toString());
|
||||
ticketSerialized.addProperty("level", Integer.valueOf(ticket.getTicketLevel()));
|
||||
ticketSerialized.addProperty("identifier", Objects.toString(ticket.key));
|
||||
ticketSerialized.addProperty("identifier", Objects.toString(((ChunkSystemTicket<?>)(Object)ticket).moonrise$getIdentifier()));
|
||||
ticketSerialized.addProperty("remove_tick", Long.valueOf(((ChunkSystemTicket<?>)(Object)ticket).moonrise$getRemoveDelay()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.ChunkProgres
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.ChunkUpgradeGenericStatusTask;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.status.ChunkSystemChunkStep;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.util.ParallelSearchRadiusIteration;
|
||||
import com.google.gson.JsonArray;
|
||||
import com.google.gson.JsonObject;
|
||||
@@ -73,35 +74,35 @@ public final class ChunkTaskScheduler {
|
||||
LOGGER.info("Chunk system is using population gen parallelism: " + useParallelGen);
|
||||
}
|
||||
|
||||
public static final TicketType<Long> CHUNK_LOAD = TicketType.create("chunk_system:chunk_load", Long::compareTo);
|
||||
public static final TicketType CHUNK_LOAD = ChunkSystemTicketType.create("chunk_system:chunk_load", Long::compareTo);
|
||||
private static final AtomicLong CHUNK_LOAD_IDS = new AtomicLong();
|
||||
|
||||
public static Long getNextChunkLoadId() {
|
||||
return Long.valueOf(CHUNK_LOAD_IDS.getAndIncrement());
|
||||
}
|
||||
|
||||
public static final TicketType<Long> NON_FULL_CHUNK_LOAD = TicketType.create("chunk_system:non_full_load", Long::compareTo);
|
||||
public static final TicketType NON_FULL_CHUNK_LOAD = ChunkSystemTicketType.create("chunk_system:non_full_load", Long::compareTo);
|
||||
private static final AtomicLong NON_FULL_CHUNK_LOAD_IDS = new AtomicLong();
|
||||
|
||||
public static Long getNextNonFullLoadId() {
|
||||
return Long.valueOf(NON_FULL_CHUNK_LOAD_IDS.getAndIncrement());
|
||||
}
|
||||
|
||||
public static final TicketType<Long> ENTITY_LOAD = TicketType.create("chunk_system:entity_load", Long::compareTo);
|
||||
public static final TicketType ENTITY_LOAD = ChunkSystemTicketType.create("chunk_system:entity_load", Long::compareTo);
|
||||
private static final AtomicLong ENTITY_LOAD_IDS = new AtomicLong();
|
||||
|
||||
public static Long getNextEntityLoadId() {
|
||||
return Long.valueOf(ENTITY_LOAD_IDS.getAndIncrement());
|
||||
}
|
||||
|
||||
public static final TicketType<Long> POI_LOAD = TicketType.create("chunk_system:poi_load", Long::compareTo);
|
||||
public static final TicketType POI_LOAD = ChunkSystemTicketType.create("chunk_system:poi_load", Long::compareTo);
|
||||
private static final AtomicLong POI_LOAD_IDS = new AtomicLong();
|
||||
|
||||
public static Long getNextPoiLoadId() {
|
||||
return Long.valueOf(POI_LOAD_IDS.getAndIncrement());
|
||||
}
|
||||
|
||||
public static final TicketType<Long> CHUNK_RELIGHT = TicketType.create("starlight:chunk_relight", Long::compareTo);
|
||||
public static final TicketType CHUNK_RELIGHT = ChunkSystemTicketType.create("starlight:chunk_relight", Long::compareTo);
|
||||
private static final AtomicLong CHUNK_RELIGHT_IDS = new AtomicLong();
|
||||
|
||||
public static Long getNextChunkRelightId() {
|
||||
|
||||
@@ -70,7 +70,7 @@ public final class ChunkFullTask extends ChunkProgressionTask implements Runnabl
|
||||
this.chunkHolder.replaceProtoChunk(new ImposterProtoChunk(chunk, false));
|
||||
}
|
||||
|
||||
((ChunkSystemLevelChunk)chunk).moonrise$setChunkAndHolder(new ServerChunkCache.ChunkAndHolder(chunk, this.chunkHolder.vanillaChunkHolder));
|
||||
((ChunkSystemLevelChunk)chunk).moonrise$setChunkHolder(this.chunkHolder);
|
||||
|
||||
final NewChunkHolder chunkHolder = this.chunkHolder;
|
||||
|
||||
|
||||
@@ -6,4 +6,8 @@ public interface ChunkSystemTicket<T> {
|
||||
|
||||
public void moonrise$setRemoveDelay(final long removeDelay);
|
||||
|
||||
public T moonrise$getIdentifier();
|
||||
|
||||
public void moonrise$setIdentifier(final T identifier);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
package ca.spottedleaf.moonrise.patches.chunk_system.ticket;
|
||||
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
|
||||
public interface ChunkSystemTicketStorage {
|
||||
|
||||
public ChunkMap moonrise$getChunkMap();
|
||||
|
||||
public void moonrise$setChunkMap(final ChunkMap chunkMap);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package ca.spottedleaf.moonrise.patches.chunk_system.ticket;
|
||||
|
||||
import net.minecraft.server.level.TicketType;
|
||||
import java.util.Comparator;
|
||||
|
||||
public interface ChunkSystemTicketType<T> {
|
||||
|
||||
public static final long COUNTER_TYPE_FORCED = 0L;
|
||||
// used only by neoforge
|
||||
public static final long COUNTER_TYPER_NATURAL_SPAWNING_FORCED = 1L;
|
||||
|
||||
public static <T> TicketType create(final String name, final Comparator<T> identifierComparator) {
|
||||
return create(name, identifierComparator, 0L);
|
||||
}
|
||||
|
||||
public static <T> TicketType create(final String name, final Comparator<T> identifierComparator, final long timeout) {
|
||||
// note: cannot persist unless registered
|
||||
final TicketType ret = new TicketType(timeout, false, TicketType.TicketUse.LOADING_AND_SIMULATION);
|
||||
|
||||
((ChunkSystemTicketType<T>)(Object)ret).moonrise$setIdentifierComparator(identifierComparator);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public long moonrise$getId();
|
||||
|
||||
public Comparator<T> moonrise$getIdentifierComparator();
|
||||
|
||||
public void moonrise$setIdentifierComparator(final Comparator<T> comparator);
|
||||
|
||||
public long[] moonrise$getCounterTypes();
|
||||
|
||||
}
|
||||
@@ -3,5 +3,13 @@ package ca.spottedleaf.moonrise.patches.chunk_tick_iteration;
|
||||
public final class ChunkTickConstants {
|
||||
|
||||
public static final int PLAYER_SPAWN_TRACK_RANGE = 8;
|
||||
// the smallest distance on x/z is at 45 degrees, we need to subtract 0.5 since this is calculated from chunk center and not chunk perimeter
|
||||
// note: vanilla does not subtract 0.5 but the result is (luckily!) the same
|
||||
public static final int NARROW_SPAWN_TRACK_RANGE = (int)Math.floor(((double)PLAYER_SPAWN_TRACK_RANGE / Math.sqrt(2.0)) - 0.5);
|
||||
static {
|
||||
if (NARROW_SPAWN_TRACK_RANGE < 0) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,4 +13,6 @@ public interface ChunkTickDistanceManager {
|
||||
final SectionPos oldPos, final SectionPos newPos,
|
||||
final boolean oldIgnore, final boolean newIgnore);
|
||||
|
||||
public boolean moonrise$hasAnyNearbyNarrow(final int chunkX, final int chunkZ);
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import net.minecraft.world.level.chunk.LevelChunk;
|
||||
|
||||
public interface ChunkTickServerLevel {
|
||||
|
||||
public ReferenceList<ServerChunkCache.ChunkAndHolder> moonrise$getPlayerTickingChunks();
|
||||
public ReferenceList<LevelChunk> moonrise$getPlayerTickingChunks();
|
||||
|
||||
public void moonrise$markChunkForPlayerTicking(final LevelChunk chunk);
|
||||
|
||||
|
||||
@@ -2004,11 +2004,10 @@ public final class CollisionUtil {
|
||||
VoxelShape blockCollision = ((CollisionBlockState)blockData).moonrise$getConstantContextCollisionShape();
|
||||
|
||||
if (edgeCount == 0 || ((edgeCount != 1 || blockData.hasLargeCollisionShape()) && (edgeCount != 2 || blockData.getBlock() == Blocks.MOVING_PISTON))) {
|
||||
mutablePos.set(blockX, blockY, blockZ);
|
||||
if (useEntityCollisionShape) {
|
||||
mutablePos.set(blockX, blockY, blockZ);
|
||||
blockCollision = collisionShape.getCollisionShape(blockData, world, mutablePos);
|
||||
} else if (blockCollision == null) {
|
||||
mutablePos.set(blockX, blockY, blockZ);
|
||||
blockCollision = blockData.getCollisionShape(world, mutablePos, collisionShape);
|
||||
}
|
||||
|
||||
@@ -2020,7 +2019,6 @@ public final class CollisionUtil {
|
||||
}
|
||||
|
||||
if (predicate != null) {
|
||||
mutablePos.set(blockX, blockY, blockZ);
|
||||
if (!predicate.test(blockData, mutablePos)) {
|
||||
continue;
|
||||
}
|
||||
@@ -2046,7 +2044,6 @@ public final class CollisionUtil {
|
||||
}
|
||||
|
||||
if (predicate != null) {
|
||||
mutablePos.set(blockX, blockY, blockZ);
|
||||
if (!predicate.test(blockData, mutablePos)) {
|
||||
continue;
|
||||
}
|
||||
@@ -2126,7 +2123,7 @@ public final class CollisionUtil {
|
||||
private boolean delegated;
|
||||
|
||||
public LazyEntityCollisionContext(final Entity entity) {
|
||||
super(false, 0.0, null, null, entity);
|
||||
super(false, false, 0.0, null, null, entity);
|
||||
}
|
||||
|
||||
public static boolean useEntityCollisionShape(final Level world, final Entity entity) {
|
||||
@@ -2156,6 +2153,11 @@ public final class CollisionUtil {
|
||||
return this.getDelegate().isDescending();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isPlacement() {
|
||||
return this.getDelegate().isPlacement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAbove(final VoxelShape shape, final BlockPos pos, final boolean defaultValue) {
|
||||
return this.getDelegate().isAbove(shape, pos, defaultValue);
|
||||
|
||||
@@ -182,7 +182,7 @@ public abstract class StarLightEngine {
|
||||
for (int dx = -radius; dx <= radius; ++dx) {
|
||||
final int cx = centerChunkX + dx;
|
||||
final int cz = centerChunkZ + dz;
|
||||
final boolean isTwoRadius = Math.max(IntegerUtil.branchlessAbs(dx), IntegerUtil.branchlessAbs(dz)) == 2;
|
||||
final boolean isTwoRadius = Math.max(Math.abs(dx), Math.abs(dz)) == 2;
|
||||
final ChunkAccess chunk = (ChunkAccess)chunkProvider.getChunkForLighting(cx, cz);
|
||||
|
||||
if (chunk == null) {
|
||||
|
||||
@@ -9,6 +9,7 @@ import ca.spottedleaf.moonrise.common.util.WorldUtil;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunkStatus;
|
||||
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType;
|
||||
import ca.spottedleaf.moonrise.patches.starlight.chunk.StarlightChunk;
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.shorts.ShortCollection;
|
||||
@@ -39,10 +40,8 @@ import java.util.function.IntConsumer;
|
||||
|
||||
public final class StarLightInterface {
|
||||
|
||||
public static final TicketType<Long> CHUNK_WORK_TICKET = TicketType.create("starlight:chunk_work_ticket", Long::compareTo);
|
||||
public static final TicketType CHUNK_WORK_TICKET = ChunkSystemTicketType.create("starlight:chunk_work_ticket", Long::compareTo);
|
||||
public static final int LIGHT_TICKET_LEVEL = ChunkLevel.byStatus(ChunkStatus.LIGHT);
|
||||
// ticket level = ChunkLevel.byStatus(FullChunkStatus.FULL) - input
|
||||
public static final int REGION_LIGHT_TICKET_LEVEL = ChunkLevel.byStatus(FullChunkStatus.FULL) - LIGHT_TICKET_LEVEL;
|
||||
|
||||
/**
|
||||
* Can be {@code null}, indicating the light is all empty.
|
||||
|
||||
@@ -56,15 +56,18 @@ public final class SaveUtil {
|
||||
tag.putBoolean("isLightOn", false);
|
||||
}
|
||||
// diff end - store our tag for whether light data is init'd
|
||||
ChunkStatus status = ChunkStatus.byName(tag.getString("Status"));
|
||||
ChunkStatus status = tag.read("Status", ChunkStatus.CODEC).orElse(ChunkStatus.EMPTY);
|
||||
|
||||
CompoundTag[] sections = new CompoundTag[maxSection - minSection + 1];
|
||||
|
||||
ListTag sectionsStored = tag.getList("sections", 10);
|
||||
ListTag sectionsStored = tag.getListOrEmpty("sections");
|
||||
|
||||
for (int i = 0; i < sectionsStored.size(); ++i) {
|
||||
CompoundTag sectionStored = sectionsStored.getCompound(i);
|
||||
int k = sectionStored.getByte("Y");
|
||||
CompoundTag sectionStored = sectionsStored.getCompound(i).orElse(null);
|
||||
if (sectionStored == null) {
|
||||
continue;
|
||||
}
|
||||
int k = sectionStored.getByteOr("Y", (byte)0);
|
||||
|
||||
// strip light data
|
||||
sectionStored.remove("BlockLight");
|
||||
@@ -147,33 +150,38 @@ public final class SaveUtil {
|
||||
|
||||
|
||||
// start copy from the original method
|
||||
boolean lit = tag.get("isLightOn") != null && tag.getInt(STARLIGHT_VERSION_TAG) == STARLIGHT_LIGHT_VERSION;
|
||||
boolean lit = tag.get("isLightOn") != null && tag.getIntOr(STARLIGHT_VERSION_TAG, -1) == STARLIGHT_LIGHT_VERSION;
|
||||
boolean canReadSky = world.dimensionType().hasSkyLight();
|
||||
ChunkStatus status = ChunkStatus.byName(tag.getString("Status"));
|
||||
ChunkStatus status = tag.read("Status", ChunkStatus.CODEC).orElse(ChunkStatus.EMPTY);
|
||||
if (lit && status.isOrAfter(ChunkStatus.LIGHT)) { // diff - we add the status check here
|
||||
ListTag sections = tag.getList("sections", 10);
|
||||
ListTag sections = tag.getListOrEmpty("sections");
|
||||
|
||||
for (int i = 0; i < sections.size(); ++i) {
|
||||
CompoundTag sectionData = sections.getCompound(i);
|
||||
int y = sectionData.getByte("Y");
|
||||
CompoundTag sectionData = sections.getCompound(i).orElse(null);
|
||||
if (sectionData == null) {
|
||||
continue;
|
||||
}
|
||||
int y = sectionData.getByteOr("Y", (byte)0);
|
||||
|
||||
if (sectionData.contains("BlockLight", 7)) {
|
||||
final byte[] blockLight = sectionData.getByteArray("BlockLight").orElse(null);
|
||||
if (blockLight != null) {
|
||||
// this is where our diff is
|
||||
blockNibbles[y - minSection] = new SWMRNibbleArray(sectionData.getByteArray("BlockLight").clone(), sectionData.getInt(BLOCKLIGHT_STATE_TAG)); // clone for data safety
|
||||
blockNibbles[y - minSection] = new SWMRNibbleArray(blockLight.clone(), sectionData.getIntOr(BLOCKLIGHT_STATE_TAG, 0)); // clone for data safety
|
||||
} else {
|
||||
blockNibbles[y - minSection] = new SWMRNibbleArray(null, sectionData.getInt(BLOCKLIGHT_STATE_TAG));
|
||||
blockNibbles[y - minSection] = new SWMRNibbleArray(null, sectionData.getIntOr(BLOCKLIGHT_STATE_TAG, 0));
|
||||
}
|
||||
|
||||
if (canReadSky) {
|
||||
if (sectionData.contains("SkyLight", 7)) {
|
||||
final byte[] skyLight = sectionData.getByteArray("SkyLight").orElse(null);
|
||||
if (skyLight != null) {
|
||||
// we store under the same key so mod programs editing nbt
|
||||
// can still read the data, hopefully.
|
||||
// however, for compatibility we store chunks as unlit so vanilla
|
||||
// is forced to re-light them if it encounters our data. It's too much of a burden
|
||||
// to try and maintain compatibility with a broken and inferior skylight management system.
|
||||
skyNibbles[y - minSection] = new SWMRNibbleArray(sectionData.getByteArray("SkyLight").clone(), sectionData.getInt(SKYLIGHT_STATE_TAG)); // clone for data safety
|
||||
skyNibbles[y - minSection] = new SWMRNibbleArray(skyLight.clone(), sectionData.getIntOr(SKYLIGHT_STATE_TAG, 0)); // clone for data safety
|
||||
} else {
|
||||
skyNibbles[y - minSection] = new SWMRNibbleArray(null, sectionData.getInt(SKYLIGHT_STATE_TAG));
|
||||
skyNibbles[y - minSection] = new SWMRNibbleArray(null, sectionData.getIntOr(SKYLIGHT_STATE_TAG, 0));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,9 +194,8 @@ accessible class net/minecraft/server/level/ChunkMap$DistanceManager
|
||||
|
||||
# DistanceManager
|
||||
mutable field net/minecraft/server/level/DistanceManager playersPerChunk Lit/unimi/dsi/fastutil/longs/Long2ObjectMap;
|
||||
mutable field net/minecraft/server/level/DistanceManager tickets Lit/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap;
|
||||
mutable field net/minecraft/server/level/DistanceManager ticketTracker Lnet/minecraft/server/level/DistanceManager$ChunkTicketTracker;
|
||||
mutable field net/minecraft/server/level/DistanceManager tickingTicketsTracker Lnet/minecraft/server/level/TickingTracker;
|
||||
mutable field net/minecraft/server/level/DistanceManager loadingChunkTracker Lnet/minecraft/server/level/LoadingChunkTracker;
|
||||
mutable field net/minecraft/server/level/DistanceManager simulationChunkTracker Lnet/minecraft/server/level/SimulationChunkTracker;
|
||||
mutable field net/minecraft/server/level/DistanceManager playerTicketManager Lnet/minecraft/server/level/DistanceManager$PlayerTicketTracker;
|
||||
mutable field net/minecraft/server/level/DistanceManager chunksToUpdateFutures Ljava/util/Set;
|
||||
mutable field net/minecraft/server/level/DistanceManager ticketDispatcher Lnet/minecraft/server/level/ThrottlingChunkTaskDispatcher;
|
||||
@@ -205,10 +204,6 @@ mutable field net/minecraft/server/level/DistanceManager mainThreadExecutor Ljav
|
||||
mutable field net/minecraft/server/level/DistanceManager naturalSpawnChunkCounter Lnet/minecraft/server/level/DistanceManager$FixedPlayerDistanceChunkTracker;
|
||||
|
||||
|
||||
# DistanceManager$ChunkTicketTracker
|
||||
accessible class net/minecraft/server/level/DistanceManager$ChunkTicketTracker
|
||||
|
||||
|
||||
# DistanceManager$PlayerTicketTracker
|
||||
accessible class net/minecraft/server/level/DistanceManager$PlayerTicketTracker
|
||||
|
||||
@@ -217,11 +212,6 @@ accessible class net/minecraft/server/level/DistanceManager$PlayerTicketTracker
|
||||
accessible class net/minecraft/server/level/DistanceManager$FixedPlayerDistanceChunkTracker
|
||||
|
||||
|
||||
# Ticket
|
||||
accessible field net/minecraft/server/level/Ticket key Ljava/lang/Object;
|
||||
accessible field net/minecraft/server/level/TicketType timeout J
|
||||
|
||||
|
||||
# ServerChunkCache
|
||||
accessible method net/minecraft/server/level/ServerChunkCache runDistanceManagerUpdates ()Z
|
||||
accessible field net/minecraft/server/level/ServerChunkCache level Lnet/minecraft/server/level/ServerLevel;
|
||||
@@ -241,14 +231,6 @@ accessible class net/minecraft/server/level/ServerLevel$EntityCallbacks
|
||||
accessible method net/minecraft/server/level/ServerLevel$EntityCallbacks <init> (Lnet/minecraft/server/level/ServerLevel;)V
|
||||
|
||||
|
||||
# EntityStorage
|
||||
accessible method net/minecraft/world/level/chunk/storage/EntityStorage readChunkPos (Lnet/minecraft/nbt/CompoundTag;)Lnet/minecraft/world/level/ChunkPos;
|
||||
accessible method net/minecraft/world/level/chunk/storage/EntityStorage writeChunkPos (Lnet/minecraft/nbt/CompoundTag;Lnet/minecraft/world/level/ChunkPos;)V
|
||||
|
||||
# Ticket
|
||||
accessible method net/minecraft/server/level/Ticket <init> (Lnet/minecraft/server/level/TicketType;ILjava/lang/Object;)V
|
||||
|
||||
|
||||
# ChunkStorage
|
||||
accessible field net/minecraft/world/level/chunk/storage/ChunkStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker;
|
||||
mutable field net/minecraft/world/level/chunk/storage/ChunkStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker;
|
||||
@@ -285,11 +267,6 @@ accessible class net/minecraft/server/level/ChunkMap$TrackedEntity
|
||||
accessible field net/minecraft/server/level/ChunkMap$TrackedEntity serverEntity Lnet/minecraft/server/level/ServerEntity;
|
||||
|
||||
|
||||
# ServerChunkCache$ChunkAndHolder
|
||||
accessible class net/minecraft/server/level/ServerChunkCache$ChunkAndHolder
|
||||
accessible method net/minecraft/server/level/ServerChunkCache$ChunkAndHolder <init> (Lnet/minecraft/world/level/chunk/LevelChunk;Lnet/minecraft/server/level/ChunkHolder;)V
|
||||
|
||||
|
||||
# LevelLoadStatusManager$Status
|
||||
accessible class net/minecraft/client/multiplayer/LevelLoadStatusManager$Status
|
||||
|
||||
@@ -314,3 +291,15 @@ accessible class net/minecraft/world/level/LocalMobCapCalculator$MobCounts
|
||||
accessible class net/minecraft/world/level/chunk/storage/SectionStorage$PackedChunk
|
||||
# MDG requires we AT the constructor if we AT the class
|
||||
accessible method net/minecraft/world/level/chunk/storage/SectionStorage$PackedChunk <init> (Lit/unimi/dsi/fastutil/ints/Int2ObjectMap;Z)V
|
||||
|
||||
|
||||
# Ticket
|
||||
accessible method net/minecraft/server/level/Ticket <init> (Lnet/minecraft/server/level/TicketType;IJ)V
|
||||
|
||||
|
||||
# LoadingChunkTracker
|
||||
accessible class net/minecraft/server/level/LoadingChunkTracker
|
||||
|
||||
|
||||
# TicketStorage
|
||||
mutable field net/minecraft/world/level/TicketStorage tickets Lit/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap;
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
"chunk_system.ChunkStepMixin",
|
||||
"chunk_system.ChunkStorageMixin",
|
||||
"chunk_system.DistanceManagerMixin",
|
||||
"chunk_system.DynamicGameEventListenerMixin",
|
||||
"chunk_system.EntityGetterMixin",
|
||||
"chunk_system.EntityMixin",
|
||||
"chunk_system.EntityTickListMixin",
|
||||
@@ -51,6 +52,8 @@
|
||||
"chunk_system.StructureCheckMixin",
|
||||
"chunk_system.StructureTemplate$PaletteMixin",
|
||||
"chunk_system.TicketMixin",
|
||||
"chunk_system.TicketStorageMixin",
|
||||
"chunk_system.TicketTypeMixin",
|
||||
"chunk_tick_iteration.ChunkMapMixin",
|
||||
"chunk_tick_iteration.DistanceManagerMixin",
|
||||
"chunk_tick_iteration.ServerChunkCacheMixin",
|
||||
|
||||
Reference in New Issue
Block a user