Compare commits
6 Commits
v0.4.0-bet
...
v0.4.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
694dab69c0 | ||
|
|
0764327cba | ||
|
|
724b8ef20a | ||
|
|
0ea5e4dcf5 | ||
|
|
1f8e863c4b | ||
|
|
9d58071cf5 |
@@ -271,4 +271,9 @@ public final class FabricHooks extends BaseChunkSystemHooks implements PlatformH
|
|||||||
public long[] getCounterTypesUncached(final TicketType type) {
|
public long[] getCounterTypesUncached(final TicketType type) {
|
||||||
return type == TicketType.FORCED ? new long[] { ChunkSystemTicketType.COUNTER_TYPE_FORCED } : LongArrays.EMPTY_ARRAY;
|
return type == TicketType.FORCED ? new long[] { ChunkSystemTicketType.COUNTER_TYPE_FORCED } : LongArrays.EMPTY_ARRAY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean addTicketForEnderPearls() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ org.gradle.configuration-cache=true
|
|||||||
minecraft_version=1.21.6
|
minecraft_version=1.21.6
|
||||||
loader_version=0.16.14
|
loader_version=0.16.14
|
||||||
supported_minecraft_versions=1.21.6
|
supported_minecraft_versions=1.21.6
|
||||||
neoforge_version=21.6.5-beta
|
neoforge_version=21.6.11-beta
|
||||||
neoform_version=1.21.6-20250617.151856
|
neoform_version=1.21.6-20250617.151856
|
||||||
fabric_api_version=0.127.0+1.21.6
|
fabric_api_version=0.127.1+1.21.6
|
||||||
snakeyaml_version=2.3
|
snakeyaml_version=2.3
|
||||||
concurrentutil_version=0.0.3
|
concurrentutil_version=0.0.3
|
||||||
yamlconfig_version=1.0.2
|
yamlconfig_version=1.0.2
|
||||||
cloth_version=19.0.146
|
cloth_version=19.0.147
|
||||||
modmenu_version=15.0.0-beta.2
|
modmenu_version=15.0.0-beta.2
|
||||||
# set to false when modmenu/cloth is not updated for the current minecraft version
|
# set to false when modmenu/cloth is not updated for the current minecraft version
|
||||||
enable_gui=true
|
enable_gui=true
|
||||||
@@ -23,6 +23,6 @@ junit_version=5.11.3
|
|||||||
fabric_lithium_version=nhc57Td2
|
fabric_lithium_version=nhc57Td2
|
||||||
neo_lithium_version=P5VT33Jo
|
neo_lithium_version=P5VT33Jo
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
mod_version=0.4.0-beta.1
|
mod_version=0.4.0-beta.2
|
||||||
maven_group=ca.spottedleaf.moonrise
|
maven_group=ca.spottedleaf.moonrise
|
||||||
archives_base_name=moonrise
|
archives_base_name=moonrise
|
||||||
|
|||||||
@@ -286,4 +286,9 @@ public final class NeoForgeHooks extends BaseChunkSystemHooks implements Platfor
|
|||||||
|
|
||||||
return ret.toLongArray();
|
return ret.toLongArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean addTicketForEnderPearls() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,6 +102,8 @@ public interface PlatformHooks extends ChunkSystemHooks {
|
|||||||
|
|
||||||
public int modifyEntityTrackingRange(final Entity entity, final int currentRange);
|
public int modifyEntityTrackingRange(final Entity entity, final int currentRange);
|
||||||
|
|
||||||
|
public boolean addTicketForEnderPearls();
|
||||||
|
|
||||||
public static final class Holder {
|
public static final class Holder {
|
||||||
private Holder() {
|
private Holder() {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package ca.spottedleaf.moonrise.common.config.moonrise;
|
|||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.config.ui.ClothConfig;
|
import ca.spottedleaf.moonrise.common.config.ui.ClothConfig;
|
||||||
import ca.spottedleaf.moonrise.common.util.MoonriseCommon;
|
import ca.spottedleaf.moonrise.common.util.MoonriseCommon;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler;
|
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler;
|
||||||
import ca.spottedleaf.yamlconfig.InitialiseHook;
|
import ca.spottedleaf.yamlconfig.InitialiseHook;
|
||||||
import ca.spottedleaf.yamlconfig.annotation.Adaptable;
|
import ca.spottedleaf.yamlconfig.annotation.Adaptable;
|
||||||
@@ -38,7 +39,7 @@ public final class MoonriseConfig {
|
|||||||
|
|
||||||
|
|
||||||
@Adaptable
|
@Adaptable
|
||||||
public static final class Basic {
|
public static final class Basic implements InitialiseHook {
|
||||||
@Serializable(
|
@Serializable(
|
||||||
comment = """
|
comment = """
|
||||||
The maximum rate of chunks to send to any given player, per second. If this value is <= 0,
|
The maximum rate of chunks to send to any given player, per second. If this value is <= 0,
|
||||||
@@ -72,6 +73,20 @@ public final class MoonriseConfig {
|
|||||||
section = CHUNK_SYSTEM_SECTION
|
section = CHUNK_SYSTEM_SECTION
|
||||||
)
|
)
|
||||||
public double playerMaxGenRate = -1.0;
|
public double playerMaxGenRate = -1.0;
|
||||||
|
|
||||||
|
@Serializable(
|
||||||
|
comment = """
|
||||||
|
The delay before chunks are unloaded around players once they leave their view distance.
|
||||||
|
The Vanilla value is 0 ticks. Setting this value higher (i.e 5s) will allow pets to teleport
|
||||||
|
to their owners when they teleport.
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
public Duration playerChunkUnloadDelay = Duration.parse("0t");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialise() {
|
||||||
|
RegionizedPlayerChunkLoader.setUnloadDelay(this.playerChunkUnloadDelay.getTimeTicks());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable(
|
@Serializable(
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ public final class CoordinateUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static long getChunkKey(final Entity entity) {
|
public static long getChunkKey(final Entity entity) {
|
||||||
return ((Mth.lfloor(entity.getZ()) >> 4) << 32) | ((Mth.lfloor(entity.getX()) >> 4) & 0xFFFFFFFFL);
|
final ChunkPos pos = entity.chunkPosition();
|
||||||
|
return ((long)pos.z << 32) | (pos.x & 0xFFFFFFFFL);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long getChunkKey(final ChunkPos pos) {
|
public static long getChunkKey(final ChunkPos pos) {
|
||||||
|
|||||||
@@ -3,7 +3,10 @@ package ca.spottedleaf.moonrise.mixin.chunk_system;
|
|||||||
import ca.spottedleaf.moonrise.common.PlatformHooks;
|
import ca.spottedleaf.moonrise.common.PlatformHooks;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType;
|
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType;
|
||||||
import net.minecraft.server.level.TicketType;
|
import net.minecraft.server.level.TicketType;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Mutable;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
@@ -14,6 +17,11 @@ import java.util.concurrent.atomic.AtomicLong;
|
|||||||
@Mixin(TicketType.class)
|
@Mixin(TicketType.class)
|
||||||
abstract class TicketTypeMixin<T> implements ChunkSystemTicketType<T> {
|
abstract class TicketTypeMixin<T> implements ChunkSystemTicketType<T> {
|
||||||
|
|
||||||
|
@Final
|
||||||
|
@Shadow
|
||||||
|
@Mutable
|
||||||
|
private long timeout;
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private static AtomicLong ID_GENERATOR;
|
private static AtomicLong ID_GENERATOR;
|
||||||
|
|
||||||
@@ -66,4 +74,9 @@ abstract class TicketTypeMixin<T> implements ChunkSystemTicketType<T> {
|
|||||||
|
|
||||||
return this.counterTypes = PlatformHooks.get().getCounterTypesUncached((TicketType)(Object)this);
|
return this.counterTypes = PlatformHooks.get().getCounterTypesUncached((TicketType)(Object)this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void moonrise$setTimeout(final long to) {
|
||||||
|
this.timeout = to;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
package ca.spottedleaf.moonrise.mixin.serverlist;
|
package ca.spottedleaf.moonrise.mixin.serverlist;
|
||||||
|
|
||||||
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
|
import net.minecraft.client.multiplayer.resolver.ServerAddress;
|
||||||
import net.minecraft.client.multiplayer.resolver.ServerAddressResolver;
|
import net.minecraft.client.multiplayer.resolver.ServerAddressResolver;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
@Mixin(ServerAddressResolver.class)
|
@Mixin(ServerAddressResolver.class)
|
||||||
@@ -20,19 +23,18 @@ interface ServerAddressResolverMixin {
|
|||||||
"lambda$static$0"
|
"lambda$static$0"
|
||||||
},
|
},
|
||||||
at = @At(
|
at = @At(
|
||||||
value = "INVOKE",
|
value = "NEW",
|
||||||
target = "Ljava/net/InetAddress;getByName(Ljava/lang/String;)Ljava/net/InetAddress;"
|
target = "(Ljava/net/InetAddress;I)Ljava/net/InetSocketAddress;"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
private static InetAddress eliminateRDNS(final String name) throws UnknownHostException {
|
private static InetSocketAddress eliminateRDNS(InetAddress addr, final int port,
|
||||||
final InetAddress ret = InetAddress.getByName(name);
|
@Local(ordinal = 0, argsOnly = true) final ServerAddress serverAddress) throws UnknownHostException {
|
||||||
|
final byte[] address = addr.getAddress();
|
||||||
final byte[] address = ret.getAddress();
|
|
||||||
if (address != null) {
|
if (address != null) {
|
||||||
// pass name to prevent rDNS
|
// pass name to prevent rDNS
|
||||||
return InetAddress.getByAddress(name, address);
|
addr = InetAddress.getByAddress(serverAddress.getHost(), address);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return new InetSocketAddress(addr, port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,8 +45,7 @@ public final class ClientEntityLookup extends EntityLookup {
|
|||||||
final boolean ticking = this.tickingChunks.contains(CoordinateUtils.getChunkKey(chunkX, chunkZ));
|
final boolean ticking = this.tickingChunks.contains(CoordinateUtils.getChunkKey(chunkX, chunkZ));
|
||||||
|
|
||||||
final ChunkEntitySlices ret = new ChunkEntitySlices(
|
final ChunkEntitySlices ret = new ChunkEntitySlices(
|
||||||
this.world, chunkX, chunkZ,
|
this.world, chunkX, chunkZ, ticking ? FullChunkStatus.ENTITY_TICKING : FullChunkStatus.FULL, null,
|
||||||
ticking ? FullChunkStatus.ENTITY_TICKING : FullChunkStatus.FULL, null,
|
|
||||||
WorldUtil.getMinSection(this.world), WorldUtil.getMaxSection(this.world)
|
WorldUtil.getMinSection(this.world), WorldUtil.getMaxSection(this.world)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,14 @@ import ca.spottedleaf.moonrise.common.util.TickThread;
|
|||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.ChunkEntitySlices;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.ChunkEntitySlices;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.EntityLookup;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.EntityLookup;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType;
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.server.level.TicketType;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.projectile.ThrownEnderpearl;
|
||||||
import net.minecraft.world.level.entity.LevelCallback;
|
import net.minecraft.world.level.entity.LevelCallback;
|
||||||
|
|
||||||
public final class ServerEntityLookup extends EntityLookup {
|
public final class ServerEntityLookup extends EntityLookup {
|
||||||
@@ -19,6 +24,13 @@ public final class ServerEntityLookup extends EntityLookup {
|
|||||||
private final ServerLevel serverWorld;
|
private final ServerLevel serverWorld;
|
||||||
public final ReferenceList<Entity> trackerEntities = new ReferenceList<>(EMPTY_ENTITY_ARRAY); // Moonrise - entity tracker
|
public final ReferenceList<Entity> trackerEntities = new ReferenceList<>(EMPTY_ENTITY_ARRAY); // Moonrise - entity tracker
|
||||||
|
|
||||||
|
// Vanilla does not increment ticket timeouts if the chunk is progressing in generation. They made this change in 1.21.6 so that the ender pearl
|
||||||
|
// ticket does not expire if the chunk fails to generate before the timeout expires. Rather than blindly adjusting the entire system behavior
|
||||||
|
// to fix this small issue, we instead add non-expirable tickets here to keep ender pearls ticking. This is how the original feature should have
|
||||||
|
// been implemented, but I don't think Vanilla has proper entity add/remove hooks like we do. Fixes MC-297591
|
||||||
|
private static final TicketType ENDER_PEARL_TICKER = ChunkSystemTicketType.create("chunk_system:ender_pearl_ticker", null);
|
||||||
|
private final Long2IntOpenHashMap enderPearlChunkCount = new Long2IntOpenHashMap();
|
||||||
|
|
||||||
public ServerEntityLookup(final ServerLevel world, final LevelCallback<Entity> worldCallback) {
|
public ServerEntityLookup(final ServerLevel world, final LevelCallback<Entity> worldCallback) {
|
||||||
super(world, worldCallback);
|
super(world, worldCallback);
|
||||||
this.serverWorld = world;
|
this.serverWorld = world;
|
||||||
@@ -63,6 +75,10 @@ public final class ServerEntityLookup extends EntityLookup {
|
|||||||
if (entity instanceof ServerPlayer player) {
|
if (entity instanceof ServerPlayer player) {
|
||||||
((ChunkSystemServerLevel)this.serverWorld).moonrise$getNearbyPlayers().tickPlayer(player);
|
((ChunkSystemServerLevel)this.serverWorld).moonrise$getNearbyPlayers().tickPlayer(player);
|
||||||
}
|
}
|
||||||
|
if (entity instanceof ThrownEnderpearl enderpearl && (oldSectionX != newSectionX || oldSectionZ != newSectionZ)) {
|
||||||
|
this.removeEnderPearl(CoordinateUtils.getChunkKey(oldSectionX, oldSectionZ));
|
||||||
|
this.addEnderPearl(CoordinateUtils.getChunkKey(newSectionX, newSectionZ));
|
||||||
|
}
|
||||||
PlatformHooks.get().entityMove(
|
PlatformHooks.get().entityMove(
|
||||||
entity,
|
entity,
|
||||||
CoordinateUtils.getChunkSectionKey(oldSectionX, oldSectionY, oldSectionZ),
|
CoordinateUtils.getChunkSectionKey(oldSectionX, oldSectionY, oldSectionZ),
|
||||||
@@ -75,6 +91,9 @@ public final class ServerEntityLookup extends EntityLookup {
|
|||||||
if (entity instanceof ServerPlayer player) {
|
if (entity instanceof ServerPlayer player) {
|
||||||
((ChunkSystemServerLevel)this.serverWorld).moonrise$getNearbyPlayers().addPlayer(player);
|
((ChunkSystemServerLevel)this.serverWorld).moonrise$getNearbyPlayers().addPlayer(player);
|
||||||
}
|
}
|
||||||
|
if (entity instanceof ThrownEnderpearl enderpearl) {
|
||||||
|
this.addEnderPearl(CoordinateUtils.getChunkKey(enderpearl.chunkPosition()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -82,6 +101,9 @@ public final class ServerEntityLookup extends EntityLookup {
|
|||||||
if (entity instanceof ServerPlayer player) {
|
if (entity instanceof ServerPlayer player) {
|
||||||
((ChunkSystemServerLevel)this.serverWorld).moonrise$getNearbyPlayers().removePlayer(player);
|
((ChunkSystemServerLevel)this.serverWorld).moonrise$getNearbyPlayers().removePlayer(player);
|
||||||
}
|
}
|
||||||
|
if (entity instanceof ThrownEnderpearl enderpearl) {
|
||||||
|
this.removeEnderPearl(CoordinateUtils.getChunkKey(enderpearl.chunkPosition()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -112,4 +134,23 @@ public final class ServerEntityLookup extends EntityLookup {
|
|||||||
protected boolean screenEntity(final Entity entity, final boolean fromDisk, final boolean event) {
|
protected boolean screenEntity(final Entity entity, final boolean fromDisk, final boolean event) {
|
||||||
return PlatformHooks.get().screenEntity(this.serverWorld, entity, fromDisk, event);
|
return PlatformHooks.get().screenEntity(this.serverWorld, entity, fromDisk, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addEnderPearl(final long coordinate) {
|
||||||
|
final int oldCount = this.enderPearlChunkCount.addTo(coordinate, 1);
|
||||||
|
if (oldCount != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
((ChunkSystemServerLevel)this.serverWorld).moonrise$getChunkTaskScheduler().chunkHolderManager
|
||||||
|
.addTicketAtLevel(ENDER_PEARL_TICKER, coordinate, ChunkHolderManager.ENTITY_TICKING_TICKET_LEVEL, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeEnderPearl(final long coordinate) {
|
||||||
|
final int oldCount = this.enderPearlChunkCount.addTo(coordinate, -1);
|
||||||
|
if (oldCount != 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.enderPearlChunkCount.remove(coordinate);
|
||||||
|
((ChunkSystemServerLevel)this.serverWorld).moonrise$getChunkTaskScheduler().chunkHolderManager
|
||||||
|
.removeTicketAtLevel(ENDER_PEARL_TICKER, coordinate, ChunkHolderManager.ENTITY_TICKING_TICKET_LEVEL, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,12 +47,16 @@ import java.util.function.Function;
|
|||||||
public final class RegionizedPlayerChunkLoader {
|
public final class RegionizedPlayerChunkLoader {
|
||||||
|
|
||||||
public static final TicketType PLAYER_TICKET = ChunkSystemTicketType.create("chunk_system:player_ticket", Long::compareTo);
|
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 TicketType PLAYER_TICKET_DELAYED = ChunkSystemTicketType.create("chunk_system:player_ticket_delayed", Long::compareTo, 1L);
|
||||||
|
|
||||||
public static final int GENERATED_TICKET_LEVEL = ChunkHolderManager.FULL_LOADED_TICKET_LEVEL;
|
public static final int GENERATED_TICKET_LEVEL = ChunkHolderManager.FULL_LOADED_TICKET_LEVEL;
|
||||||
public static final int LOADED_TICKET_LEVEL = ChunkTaskScheduler.getTicketLevel(ChunkStatus.EMPTY);
|
public static final int LOADED_TICKET_LEVEL = ChunkTaskScheduler.getTicketLevel(ChunkStatus.EMPTY);
|
||||||
public static final int TICK_TICKET_LEVEL = ChunkHolderManager.ENTITY_TICKING_TICKET_LEVEL;
|
public static final int TICK_TICKET_LEVEL = ChunkHolderManager.ENTITY_TICKING_TICKET_LEVEL;
|
||||||
|
|
||||||
|
public static void setUnloadDelay(final long ticks) {
|
||||||
|
((ChunkSystemTicketType)(Object)PLAYER_TICKET_DELAYED).moonrise$setTimeout(Math.max(1, ticks));
|
||||||
|
}
|
||||||
|
|
||||||
public static final class ViewDistanceHolder {
|
public static final class ViewDistanceHolder {
|
||||||
|
|
||||||
private volatile ViewDistances viewDistances;
|
private volatile ViewDistances viewDistances;
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package ca.spottedleaf.moonrise.patches.chunk_system.scheduling;
|
package ca.spottedleaf.moonrise.patches.chunk_system.scheduling;
|
||||||
|
|
||||||
|
import ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue;
|
||||||
import ca.spottedleaf.concurrentutil.lock.ReentrantAreaLock;
|
import ca.spottedleaf.concurrentutil.lock.ReentrantAreaLock;
|
||||||
import ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable;
|
import ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable;
|
||||||
import ca.spottedleaf.concurrentutil.util.Priority;
|
import ca.spottedleaf.concurrentutil.util.Priority;
|
||||||
@@ -82,6 +83,7 @@ public final class ChunkHolderManager {
|
|||||||
private long currentTick;
|
private long currentTick;
|
||||||
|
|
||||||
private final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = new ArrayDeque<>();
|
private final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = new ArrayDeque<>();
|
||||||
|
private final MultiThreadedQueue<NewChunkHolder> offThreadPendingFullLoadUpdate = new MultiThreadedQueue<>();
|
||||||
private final ObjectRBTreeSet<NewChunkHolder> autoSaveQueue = new ObjectRBTreeSet<>((final NewChunkHolder c1, final NewChunkHolder c2) -> {
|
private final ObjectRBTreeSet<NewChunkHolder> autoSaveQueue = new ObjectRBTreeSet<>((final NewChunkHolder c1, final NewChunkHolder c2) -> {
|
||||||
if (c1 == c2) {
|
if (c1 == c2) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -112,20 +114,20 @@ public final class ChunkHolderManager {
|
|||||||
this.unloadQueue = new ChunkUnloadQueue(((ChunkSystemServerLevel)world).moonrise$getRegionChunkShift());
|
this.unloadQueue = new ChunkUnloadQueue(((ChunkSystemServerLevel)world).moonrise$getRegionChunkShift());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean processTicketUpdates(final int posX, final int posZ) {
|
public boolean processTicketUpdates(final int chunkX, final int chunkZ) {
|
||||||
final int ticketShift = ThreadedTicketLevelPropagator.SECTION_SHIFT;
|
final int ticketShift = ThreadedTicketLevelPropagator.SECTION_SHIFT;
|
||||||
final int ticketMask = (1 << ticketShift) - 1;
|
final int ticketMask = (1 << ticketShift) - 1;
|
||||||
final List<ChunkProgressionTask> scheduledTasks = new ArrayList<>();
|
final List<ChunkProgressionTask> scheduledTasks = new ArrayList<>();
|
||||||
final List<NewChunkHolder> changedFullStatus = new ArrayList<>();
|
final List<NewChunkHolder> changedFullStatus = new ArrayList<>();
|
||||||
final boolean ret;
|
final boolean ret;
|
||||||
final ReentrantAreaLock.Node ticketLock = this.ticketLockArea.lock(
|
final ReentrantAreaLock.Node ticketLock = this.ticketLockArea.lock(
|
||||||
((posX >> ticketShift) - 1) << ticketShift,
|
((chunkX >> ticketShift) - 1) << ticketShift,
|
||||||
((posZ >> ticketShift) - 1) << ticketShift,
|
((chunkZ >> ticketShift) - 1) << ticketShift,
|
||||||
(((posX >> ticketShift) + 1) << ticketShift) | ticketMask,
|
(((chunkX >> ticketShift) + 1) << ticketShift) | ticketMask,
|
||||||
(((posZ >> ticketShift) + 1) << ticketShift) | ticketMask
|
(((chunkZ >> ticketShift) + 1) << ticketShift) | ticketMask
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
ret = this.processTicketUpdatesNoLock(posX >> ticketShift, posZ >> ticketShift, scheduledTasks, changedFullStatus);
|
ret = this.processTicketUpdatesNoLock(chunkX >> ticketShift, chunkZ >> ticketShift, scheduledTasks, changedFullStatus);
|
||||||
} finally {
|
} finally {
|
||||||
this.ticketLockArea.unlock(ticketLock);
|
this.ticketLockArea.unlock(ticketLock);
|
||||||
}
|
}
|
||||||
@@ -805,6 +807,9 @@ public final class ChunkHolderManager {
|
|||||||
return removeDelay <= 0L;
|
return removeDelay <= 0L;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
final List<ChunkProgressionTask> scheduledTasks = new ArrayList<>();
|
||||||
|
final List<NewChunkHolder> changedFullStatus = new ArrayList<>();
|
||||||
|
|
||||||
for (final PrimitiveIterator.OfLong iterator = this.sectionToChunkToExpireCount.keyIterator(); iterator.hasNext();) {
|
for (final PrimitiveIterator.OfLong iterator = this.sectionToChunkToExpireCount.keyIterator(); iterator.hasNext();) {
|
||||||
final long sectionKey = iterator.nextLong();
|
final long sectionKey = iterator.nextLong();
|
||||||
|
|
||||||
@@ -813,9 +818,16 @@ public final class ChunkHolderManager {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final int lowerChunkX = CoordinateUtils.getChunkX(sectionKey) << sectionShift;
|
||||||
|
final int lowerChunkZ = CoordinateUtils.getChunkZ(sectionKey) << sectionShift;
|
||||||
|
|
||||||
|
final int ticketShift = ThreadedTicketLevelPropagator.SECTION_SHIFT;
|
||||||
|
final int ticketMask = (1 << ticketShift) - 1;
|
||||||
final ReentrantAreaLock.Node ticketLock = this.ticketLockArea.lock(
|
final ReentrantAreaLock.Node ticketLock = this.ticketLockArea.lock(
|
||||||
CoordinateUtils.getChunkX(sectionKey) << sectionShift,
|
((lowerChunkX >> ticketShift) - 1) << ticketShift,
|
||||||
CoordinateUtils.getChunkZ(sectionKey) << sectionShift
|
((lowerChunkZ >> ticketShift) - 1) << ticketShift,
|
||||||
|
(((lowerChunkX >> ticketShift) + 1) << ticketShift) | ticketMask,
|
||||||
|
(((lowerChunkZ >> ticketShift) + 1) << ticketShift) | ticketMask
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -862,9 +874,23 @@ public final class ChunkHolderManager {
|
|||||||
if (chunkToExpireCount.isEmpty()) {
|
if (chunkToExpireCount.isEmpty()) {
|
||||||
this.sectionToChunkToExpireCount.remove(sectionKey);
|
this.sectionToChunkToExpireCount.remove(sectionKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In order to prevent a race condition where an off-thread invokes processTicketUpdates(), we need to process ticket updates here
|
||||||
|
// so that we catch any additions to the changed full status list. If an off-thread were to process tickets here, it would not be guaranteed
|
||||||
|
// that it would be added to the full changed status set by the end of the call - possibly allowing ticket level decreases to be processed
|
||||||
|
// outside of this call, which is not an intended or expected of this chunk system.
|
||||||
|
this.processTicketUpdatesNoLock(lowerChunkX >> ThreadedTicketLevelPropagator.SECTION_SHIFT, lowerChunkZ >> ThreadedTicketLevelPropagator.SECTION_SHIFT, scheduledTasks, changedFullStatus);
|
||||||
} finally {
|
} finally {
|
||||||
this.ticketLockArea.unlock(ticketLock);
|
this.ticketLockArea.unlock(ticketLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.addChangedStatuses(changedFullStatus);
|
||||||
|
changedFullStatus.clear(); // clear for next loop iteration
|
||||||
|
|
||||||
|
for (int i = 0, len = scheduledTasks.size(); i < len; ++i) {
|
||||||
|
scheduledTasks.get(i).schedule();
|
||||||
|
}
|
||||||
|
scheduledTasks.clear(); // clear for next loop iteration
|
||||||
}
|
}
|
||||||
|
|
||||||
this.processTicketUpdates();
|
this.processTicketUpdates();
|
||||||
@@ -1091,14 +1117,9 @@ public final class ChunkHolderManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!TickThread.isTickThread()) {
|
if (!TickThread.isTickThread()) {
|
||||||
this.taskScheduler.scheduleChunkTask(() -> {
|
// These will be handled on the next ServerChunkCache$MainThreadExecutor#pollTask, as it runs the distance manager update
|
||||||
final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = ChunkHolderManager.this.pendingFullLoadUpdate;
|
// which will invoke processTicketUpdates
|
||||||
for (int i = 0, len = changedFullStatus.size(); i < len; ++i) {
|
this.offThreadPendingFullLoadUpdate.addAll(changedFullStatus);
|
||||||
pendingFullLoadUpdate.add(changedFullStatus.get(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
ChunkHolderManager.this.processPendingFullUpdate();
|
|
||||||
}, Priority.HIGHEST);
|
|
||||||
} else {
|
} else {
|
||||||
final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = this.pendingFullLoadUpdate;
|
final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = this.pendingFullLoadUpdate;
|
||||||
for (int i = 0, len = changedFullStatus.size(); i < len; ++i) {
|
for (int i = 0, len = changedFullStatus.size(); i < len; ++i) {
|
||||||
@@ -1379,36 +1400,20 @@ public final class ChunkHolderManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean processTicketUpdates() {
|
public boolean processTicketUpdates() {
|
||||||
return this.processTicketUpdates(true, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final ThreadLocal<List<ChunkProgressionTask>> CURRENT_TICKET_UPDATE_SCHEDULING = new ThreadLocal<>();
|
|
||||||
|
|
||||||
static List<ChunkProgressionTask> getCurrentTicketUpdateScheduling() {
|
|
||||||
return CURRENT_TICKET_UPDATE_SCHEDULING.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean processTicketUpdates(final boolean processFullUpdates, List<ChunkProgressionTask> scheduledTasks) {
|
|
||||||
if (BLOCK_TICKET_UPDATES.get() == Boolean.TRUE) {
|
if (BLOCK_TICKET_UPDATES.get() == Boolean.TRUE) {
|
||||||
throw new IllegalStateException("Cannot update ticket level while unloading chunks or updating entity manager");
|
throw new IllegalStateException("Cannot update ticket level while unloading chunks or updating entity manager");
|
||||||
}
|
}
|
||||||
if (!PlatformHooks.get().allowAsyncTicketUpdates() && !TickThread.isTickThread()) {
|
final boolean isTickThread = TickThread.isTickThread();
|
||||||
|
|
||||||
|
if (!PlatformHooks.get().allowAsyncTicketUpdates() && isTickThread) {
|
||||||
TickThread.ensureTickThread("Cannot asynchronously process ticket updates");
|
TickThread.ensureTickThread("Cannot asynchronously process ticket updates");
|
||||||
}
|
}
|
||||||
|
|
||||||
List<NewChunkHolder> changedFullStatus = null;
|
|
||||||
|
|
||||||
final boolean isTickThread = TickThread.isTickThread();
|
|
||||||
|
|
||||||
boolean ret = false;
|
boolean ret = false;
|
||||||
final boolean canProcessFullUpdates = processFullUpdates & isTickThread;
|
|
||||||
final boolean canProcessScheduling = scheduledTasks == null;
|
|
||||||
|
|
||||||
if (this.ticketLevelPropagator.hasPendingUpdates()) {
|
if (this.ticketLevelPropagator.hasPendingUpdates()) {
|
||||||
if (scheduledTasks == null) {
|
final List<ChunkProgressionTask> scheduledTasks = new ArrayList<>();
|
||||||
scheduledTasks = new ArrayList<>();
|
final List<NewChunkHolder> changedFullStatus = new ArrayList<>();
|
||||||
}
|
|
||||||
changedFullStatus = new ArrayList<>();
|
|
||||||
|
|
||||||
this.blockTicketUpdates();
|
this.blockTicketUpdates();
|
||||||
try {
|
try {
|
||||||
@@ -1419,27 +1424,42 @@ public final class ChunkHolderManager {
|
|||||||
} finally {
|
} finally {
|
||||||
this.unblockTicketUpdates(Boolean.FALSE);
|
this.unblockTicketUpdates(Boolean.FALSE);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (changedFullStatus != null) {
|
|
||||||
this.addChangedStatuses(changedFullStatus);
|
this.addChangedStatuses(changedFullStatus);
|
||||||
}
|
|
||||||
|
|
||||||
if (canProcessScheduling && scheduledTasks != null) {
|
|
||||||
for (int i = 0, len = scheduledTasks.size(); i < len; ++i) {
|
for (int i = 0, len = scheduledTasks.size(); i < len; ++i) {
|
||||||
scheduledTasks.get(i).schedule();
|
scheduledTasks.get(i).schedule();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canProcessFullUpdates) {
|
if (isTickThread) {
|
||||||
ret |= this.processPendingFullUpdate();
|
ret |= this.processPendingFullUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final ThreadLocal<List<ChunkProgressionTask>> CURRENT_TICKET_UPDATE_SCHEDULING = new ThreadLocal<>();
|
||||||
|
|
||||||
|
static List<ChunkProgressionTask> getCurrentTicketUpdateScheduling() {
|
||||||
|
return CURRENT_TICKET_UPDATE_SCHEDULING.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// only call on tick thread
|
||||||
|
private void processOffThreadFullUpdates() {
|
||||||
|
final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = this.pendingFullLoadUpdate;
|
||||||
|
final MultiThreadedQueue<NewChunkHolder> offThreadPendingFullLoadUpdate = this.offThreadPendingFullLoadUpdate;
|
||||||
|
|
||||||
|
NewChunkHolder toUpdate;
|
||||||
|
while ((toUpdate = offThreadPendingFullLoadUpdate.poll()) != null) {
|
||||||
|
pendingFullLoadUpdate.add(toUpdate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// only call on tick thread
|
// only call on tick thread
|
||||||
private boolean processPendingFullUpdate() {
|
private boolean processPendingFullUpdate() {
|
||||||
|
this.processOffThreadFullUpdates();
|
||||||
|
|
||||||
final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = this.pendingFullLoadUpdate;
|
final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = this.pendingFullLoadUpdate;
|
||||||
|
|
||||||
boolean ret = false;
|
boolean ret = false;
|
||||||
|
|||||||
@@ -30,4 +30,5 @@ public interface ChunkSystemTicketType<T> {
|
|||||||
|
|
||||||
public long[] moonrise$getCounterTypes();
|
public long[] moonrise$getCounterTypes();
|
||||||
|
|
||||||
|
public void moonrise$setTimeout(final long to);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user