Compare commits

...

18 Commits

Author SHA1 Message Date
Spottedleaf
a33ac1dc01 Implement PlatformHooks#addTicketForEnderPearls
Allows implementing Paper's legacy ender pearl behavior config
option.
2025-06-20 20:24:15 -07:00
Spottedleaf
da21aeca85 Set version to 0.4.0-SNAPSHOT 2025-06-20 19:21:54 -07:00
Spottedleaf
694dab69c0 Set version to 0.4.0-beta.2 2025-06-20 18:55:15 -07:00
Spottedleaf
0764327cba Do not allow ticket level decreases to be processed asynchronously
Note: This cannot happen on the Fabric/NeoForge versions since
async ticket level processing is not allowed, but can happen on
Paper. This change is made here so that Paper can
remain in sync.

Ticket level decreases may be handled asynchronously when the
off-thread invokes processTicketUpdates() when the main thread
is running ChunkHolderManager#tick(). This is because the ticket
update is queued during tick(), but not executed (invoking
processTicketUpdates) until after releasing the ticket lock.
This creates a small window for an off-thread to invoke
processTicketUpdates() and steal the update.

When the update is stolen, the full chunk status update (if any)
will be eventually queued to execute via the chunk task queue.
If the chunk queue is processed during the server tick at any
point other than the ChunkHolderManager tick, then any ticket
level decrease will violate an important invariant in the
Moonrise chunk system: ticket level decreases only occur during
ChunkHolderManager tick. This invariant exists to make interfacing
with the chunk system easier, especially working with off-thread
contexts.

This change is specifically made to work towards fixing
https://github.com/PaperMC/Folia/issues/363
2025-06-20 18:53:29 -07:00
Spottedleaf
724b8ef20a Fix incompatibility with "Fast IP Ping"
Inject in a different place to prevent the mixin from failing to
apply. It looks like we do essentially the same logic anyways.
2025-06-20 18:52:50 -07:00
Spottedleaf
0ea5e4dcf5 Add chunk unload delay config option
The default config option is no unload delay, so that
it maintains parity with Vanilla.

Fixes https://github.com/Tuinity/Moonrise/issues/115
2025-06-20 14:03:28 -07:00
Spottedleaf
1f8e863c4b Fix MC-297591
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 to keep
ender pearls ticking.
2025-06-20 13:00:53 -07:00
Spottedleaf
9d58071cf5 Set version to 0.4.0-SNAPSHOT 2025-06-18 11:12:12 -07:00
Spottedleaf
303d763167 Set version to 0.4.0-beta.1 2025-06-18 11:08:41 -07:00
Spottedleaf
9e3a55f7bc Update cloth config api, re-enable GUI 2025-06-18 10:31:09 -07:00
Spottedleaf
aef2b81d6e Implement WaypointTransmitter#isChunkVisible
The Vanilla chunk tracker on Moonrise always returns false. We need
to redirect to Moonrise's chunk loader.
2025-06-17 17:42:53 -07:00
Spottedleaf
0451444abf Update to 1.21.6
We are awaiting cloth config for a release.

We also need to make a fix for MC-297591, as we revert Mojang's solution.
Mojang's solution makes the rest of the chunk system's timing with
tickets unpredictable, which is almost certainly too large of a change
on its own. Surely, the ender pearl code could be modified to fix
this properly.
2025-06-17 09:33:11 -07:00
Spottedleaf
9a4078966d Fix infinite loop in RegionFile IO
If an exception is thrown during decompress then the read process
would be started again, which of course would eventually throw in
the decompress process.
2025-06-09 02:28:34 -07:00
Jason Penilla
b2a7a92c74 - Uncomment neoforge config screen, it doesn't crash unless you try to use it
- Don't register gui source set when gui is disabled
2025-06-03 13:50:58 -07:00
Jason Penilla
30b011246c Allow starting fabric mod without ModMenu/Cloth working 2025-06-03 13:41:33 -07:00
Jason Penilla
91455be558 Downgrade MDG
Something broke with ATs
2025-06-03 13:35:20 -07:00
Jason Penilla
41ccbb2611 Update Gradle & plugins, use NeoForge PR repo 2025-06-03 13:12:39 -07:00
Spottedleaf
b312be2921 Preliminary work to update to 1.16.2-pre1
I don't see many changes to areas we affect. Waiting on
modmenu/cloth to update as well for more testing.

HappyGhast is a new hard colliding entity.
2025-06-03 11:54:35 -07:00
36 changed files with 336 additions and 111 deletions

View File

@@ -6,6 +6,12 @@ plugins {
id 'maven-publish'
}
boolean gui = enable_gui == "true"
if (gui) {
sourceSets.create("gui")
loom.createRemapConfigurations(sourceSets.gui)
}
dependencies {
minecraft "com.mojang:minecraft:${project.minecraft_version}"
mappings loom.officialMojangMappings()
@@ -20,9 +26,16 @@ dependencies {
libs("ca.spottedleaf:yamlconfig:${rootProject.yamlconfig_version}") { setTransitive(false) }
libs("org.yaml:snakeyaml:${rootProject.snakeyaml_version}")
modImplementation "me.shedaniel.cloth:cloth-config-fabric:${rootProject.cloth_version}"
include "me.shedaniel.cloth:cloth-config-fabric:${rootProject.cloth_version}"
modImplementation "com.terraformersmc:modmenu:${rootProject.modmenu_version}"
if (gui) {
guiCompileOnly(project(":"))
runtimeOnly(sourceSets.gui.output)
shadow(sourceSets.gui.output)
modGuiImplementation "me.shedaniel.cloth:cloth-config-fabric:${rootProject.cloth_version}"
modRuntimeOnly "me.shedaniel.cloth:cloth-config-fabric:${rootProject.cloth_version}"
include "me.shedaniel.cloth:cloth-config-fabric:${rootProject.cloth_version}"
modGuiImplementation "com.terraformersmc:modmenu:${rootProject.modmenu_version}"
modRuntimeOnly "com.terraformersmc:modmenu:${rootProject.modmenu_version}"
}
modImplementation platform(fabricApiLibs.bom)
modImplementation fabricApiLibs.command.api.v2
@@ -31,6 +44,14 @@ dependencies {
include fabricApiLibs.base
}
if (gui) {
afterEvaluate {
configurations.guiCompileOnly {
extendsFrom configurations.getByName("minecraftNamedCompile")
}
}
}
tasks.processResources {
def properties = [
"version": project.version,

View File

@@ -6,6 +6,7 @@ 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.logging.LogUtils;
import com.mojang.serialization.Dynamic;
import it.unimi.dsi.fastutil.longs.LongArrays;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents;
@@ -18,6 +19,7 @@ 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.util.ProblemReporter;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.boss.EnderDragonPart;
import net.minecraft.world.level.BlockGetter;
@@ -31,7 +33,9 @@ import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.chunk.status.ChunkStatusTasks;
import net.minecraft.world.level.chunk.storage.SerializableChunkData;
import net.minecraft.world.level.entity.EntityTypeTest;
import net.minecraft.world.level.storage.TagValueInput;
import net.minecraft.world.phys.AABB;
import org.slf4j.Logger;
import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;
@@ -40,6 +44,8 @@ public final class FabricHooks extends BaseChunkSystemHooks implements PlatformH
private static final boolean HAS_FABRIC_LIFECYCLE_EVENTS = FabricLoader.getInstance().isModLoaded("fabric-lifecycle-events-v1");
private static final Logger LOGGER = LogUtils.getLogger();
@Override
public String getBrand() {
return "Moonrise";
@@ -251,7 +257,9 @@ public final class FabricHooks extends BaseChunkSystemHooks implements PlatformH
@Override
public void postLoadProtoChunk(final ServerLevel world, final ProtoChunk chunk) {
ChunkStatusTasks.postLoadProtoChunk(world, chunk.getEntities());
try (final ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(chunk.problemPath(), LOGGER)) {
ChunkStatusTasks.postLoadProtoChunk(world, TagValueInput.create(scopedCollector, world.registryAccess(), chunk.getEntities()));
}
}
@Override
@@ -263,4 +271,9 @@ public final class FabricHooks extends BaseChunkSystemHooks implements PlatformH
public long[] getCounterTypesUncached(final TicketType type) {
return type == TicketType.FORCED ? new long[] { ChunkSystemTicketType.COUNTER_TYPE_FORCED } : LongArrays.EMPTY_ARRAY;
}
@Override
public boolean addTicketForEnderPearls(final ServerLevel world) {
return true;
}
}

View File

@@ -36,7 +36,7 @@
"accessWidener": "moonrise.accesswidener",
"depends": {
"fabricloader": ">=${loader_version}",
"minecraft": ">1.21.4 <1.21.6",
"minecraft": ">1.21.5 <1.21.7",
"fabric-command-api-v2": "*"
},
"custom": {

View File

@@ -4,23 +4,25 @@ org.gradle.parallel=true
org.gradle.caching=true
org.gradle.configuration-cache=true
# Fabric Properties
# check these on https://modmuss50.me/fabric.html
minecraft_version=1.21.5
# check these on https://fabricmc.net/develop/
minecraft_version=1.21.6
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
supported_minecraft_versions=1.21.6
neoforge_version=21.6.11-beta
neoform_version=1.21.6-20250617.151856
fabric_api_version=0.127.1+1.21.6
snakeyaml_version=2.3
concurrentutil_version=0.0.3
yamlconfig_version=1.0.2
cloth_version=18.0.145
modmenu_version=14.0.0-rc.2
cloth_version=19.0.147
modmenu_version=15.0.0-beta.2
# set to false when modmenu/cloth is not updated for the current minecraft version
enable_gui=true
junit_version=5.11.3
# version ids from modrinth
fabric_lithium_version=nhc57Td2
neo_lithium_version=P5VT33Jo
# Mod Properties
mod_version=0.3.0-SNAPSHOT
mod_version=0.4.0-SNAPSHOT
maven_group=ca.spottedleaf.moonrise
archives_base_name=moonrise

Binary file not shown.

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

6
gradlew vendored
View File

@@ -114,7 +114,7 @@ case "$( uname )" in #(
NONSTOP* ) nonstop=true ;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
CLASSPATH="\\\"\\\""
# Determine the Java command to use to start the JVM.
@@ -205,7 +205,7 @@ fi
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Collect all arguments for the java command:
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
# and any embedded shellness will be escaped.
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
# treated as '${Hostname}' itself on the command line.
@@ -213,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
set -- \
"-Dorg.gradle.appname=$APP_BASE_NAME" \
-classpath "$CLASSPATH" \
org.gradle.wrapper.GradleWrapperMain \
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
"$@"
# Stop when "xargs" is not available.

4
gradlew.bat vendored
View File

@@ -70,11 +70,11 @@ goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
set CLASSPATH=
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
:end
@rem End local scope for the variables with windows NT shell

View File

@@ -7,6 +7,7 @@ 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.logging.LogUtils;
import com.mojang.serialization.Dynamic;
import it.unimi.dsi.fastutil.longs.LongArrayList;
import net.minecraft.core.BlockPos;
@@ -17,6 +18,7 @@ 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.util.ProblemReporter;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.ChunkPos;
@@ -30,6 +32,7 @@ import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.chunk.status.ChunkStatusTasks;
import net.minecraft.world.level.chunk.storage.SerializableChunkData;
import net.minecraft.world.level.entity.EntityTypeTest;
import net.minecraft.world.level.storage.TagValueInput;
import net.minecraft.world.phys.AABB;
import net.neoforged.neoforge.common.CommonHooks;
import net.neoforged.neoforge.common.NeoForge;
@@ -38,12 +41,15 @@ import net.neoforged.neoforge.event.EventHooks;
import net.neoforged.neoforge.event.entity.EntityJoinLevelEvent;
import net.neoforged.neoforge.event.level.ChunkDataEvent;
import net.neoforged.neoforge.event.level.ChunkEvent;
import org.slf4j.Logger;
import java.util.Collection;
import java.util.List;
import java.util.function.Predicate;
public final class NeoForgeHooks extends BaseChunkSystemHooks implements PlatformHooks {
private static final Logger LOGGER = LogUtils.getLogger();
@Override
public String getBrand() {
return "Moonrise";
@@ -257,7 +263,9 @@ public final class NeoForgeHooks extends BaseChunkSystemHooks implements Platfor
@Override
public void postLoadProtoChunk(final ServerLevel world, final ProtoChunk chunk) {
ChunkStatusTasks.postLoadProtoChunk(world, chunk.getEntities());
try (final ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(chunk.problemPath(), LOGGER)) {
ChunkStatusTasks.postLoadProtoChunk(world, TagValueInput.create(scopedCollector, world.registryAccess(), chunk.getEntities()));
}
}
@Override
@@ -278,4 +286,9 @@ public final class NeoForgeHooks extends BaseChunkSystemHooks implements Platfor
return ret.toLongArray();
}
@Override
public boolean addTicketForEnderPearls(final ServerLevel world) {
return true;
}
}

View File

@@ -28,7 +28,7 @@ side = "BOTH"
[[dependencies.moonrise]]
modId = "minecraft"
type = "required"
versionRange = "(1.21.4,1.21.6)"
versionRange = "(1.21.5,1.21.7)"
ordering = "NONE"
side = "BOTH"

View File

@@ -22,7 +22,7 @@ pluginManagement {
}
plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "0.9.0"
id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
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

View File

@@ -102,6 +102,8 @@ public interface PlatformHooks extends ChunkSystemHooks {
public int modifyEntityTrackingRange(final Entity entity, final int currentRange);
public boolean addTicketForEnderPearls(final ServerLevel world);
public static final class Holder {
private Holder() {
}

View File

@@ -2,6 +2,7 @@ package ca.spottedleaf.moonrise.common.config.moonrise;
import ca.spottedleaf.moonrise.common.config.ui.ClothConfig;
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.yamlconfig.InitialiseHook;
import ca.spottedleaf.yamlconfig.annotation.Adaptable;
@@ -38,7 +39,7 @@ public final class MoonriseConfig {
@Adaptable
public static final class Basic {
public static final class Basic implements InitialiseHook {
@Serializable(
comment = """
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
)
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(

View File

@@ -16,7 +16,8 @@ public final class CoordinateUtils {
}
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) {

View File

@@ -607,6 +607,22 @@ abstract class ServerLevelMixin extends Level implements ChunkSystemServerLevel,
this.moonrise$getEntityLookup().addWorldGenChunkEntities(stream.toList(), null); // TODO
}
/**
* @reason Not needed in new chunk system, also avoid accessing old entity manager
* @author Spottedleaf
*/
@Redirect(
method = {
"method_72080",
"lambda$waitForChunkAndEntities$21"
},
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/level/entity/PersistentEntitySectionManager;processPendingLoads()V"
)
)
private void redirectWaitForChunks(final PersistentEntitySectionManager<Entity> instance) {}
/**
* @reason Level close now handles this
* @author Spottedleaf

View File

@@ -15,8 +15,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ServerPlayer.class)
abstract class ServerPlayerMixin extends Player implements ChunkSystemServerPlayer {
public ServerPlayerMixin(Level level, BlockPos blockPos, float f, GameProfile gameProfile) {
super(level, blockPos, f, gameProfile);
public ServerPlayerMixin(final Level p_250508_, final GameProfile p_252153_) {
super(p_250508_, p_252153_);
}
@Unique

View File

@@ -29,6 +29,7 @@ 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.BiPredicate;
import java.util.function.Predicate;
@Mixin(TicketStorage.class)
@@ -193,8 +194,8 @@ abstract class TicketStorageMixin extends SavedData implements ChunkSystemTicket
* @author Spottedleaf
*/
@Overwrite
public void purgeStaleTickets() {
((ChunkSystemServerLevel)this.chunkMap.level).moonrise$getChunkTaskScheduler().chunkHolderManager.tick();
public void purgeStaleTickets(final ChunkMap chunkMap) {
((ChunkSystemServerLevel)chunkMap.level).moonrise$getChunkTaskScheduler().chunkHolderManager.tick();
this.setDirty();
}
@@ -208,11 +209,11 @@ abstract class TicketStorageMixin extends SavedData implements ChunkSystemTicket
method = "deactivateTicketsOnClosing",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/level/TicketStorage;removeTicketIf(Ljava/util/function/Predicate;Lit/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap;)V"
target = "Lnet/minecraft/world/level/TicketStorage;removeTicketIf(Ljava/util/function/BiPredicate;Lit/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap;)V"
)
)
private void avoidRemovingTicketsOnShutdown(final TicketStorage instance,
final Predicate<Ticket> predicate,
final BiPredicate<Long, Ticket> predicate,
final Long2ObjectOpenHashMap<List<Ticket>> tickets) {}
/**
@@ -220,7 +221,7 @@ abstract class TicketStorageMixin extends SavedData implements ChunkSystemTicket
* @author Spottedleaf
*/
@Overwrite
public void removeTicketIf(final Predicate<Ticket> predicate, final Long2ObjectOpenHashMap<List<Ticket>> into) {
public void removeTicketIf(final BiPredicate<Long, Ticket> predicate, final Long2ObjectOpenHashMap<List<Ticket>> into) {
throw new UnsupportedOperationException();
}

View File

@@ -3,7 +3,10 @@ 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.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Mutable;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@@ -14,6 +17,11 @@ import java.util.concurrent.atomic.AtomicLong;
@Mixin(TicketType.class)
abstract class TicketTypeMixin<T> implements ChunkSystemTicketType<T> {
@Final
@Shadow
@Mutable
private long timeout;
@Unique
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);
}
@Override
public final void moonrise$setTimeout(final long to) {
this.timeout = to;
}
}

View File

@@ -0,0 +1,25 @@
package ca.spottedleaf.moonrise.mixin.chunk_system;
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
import ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer;
import ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.waypoints.Waypoint;
import net.minecraft.world.waypoints.WaypointTransmitter;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
@Mixin(WaypointTransmitter.class)
interface WaypointTransmitterMixin extends Waypoint {
/**
* @reason Redirect to the new player chunk loader, as the Vanilla chunk tracker is set to empty on Moonrise
* @author Spottedleaf
*/
@Overwrite
public static boolean isChunkVisible(final ChunkPos pos, final ServerPlayer player) {
final RegionizedPlayerChunkLoader.PlayerChunkLoaderData playerChunkLoader = ((ChunkSystemServerPlayer)player).moonrise$getChunkLoader();
return playerChunkLoader != null && playerChunkLoader.getSentChunksRaw().contains(CoordinateUtils.getChunkKey(pos));
}
}

View File

@@ -59,7 +59,7 @@ interface EntityGetterMixin {
continue;
}
if ((entity == null && otherEntity.canBeCollidedWith()) || (entity != null && entity.canCollideWith(otherEntity))) {
if ((entity == null && otherEntity.canBeCollidedWith(entity)) || (entity != null && entity.canCollideWith(otherEntity))) {
ret.add(Shapes.create(otherEntity.getBoundingBox()));
}
}

View File

@@ -1,10 +1,13 @@
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 org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.UnknownHostException;
@Mixin(ServerAddressResolver.class)
@@ -15,24 +18,23 @@ interface ServerAddressResolverMixin {
* @author Spottedleaf
*/
@Redirect(
method = {
"method_36903",
"lambda$static$0"
},
at = @At(
value = "INVOKE",
target = "Ljava/net/InetAddress;getByName(Ljava/lang/String;)Ljava/net/InetAddress;"
)
method = {
"method_36903",
"lambda$static$0"
},
at = @At(
value = "NEW",
target = "(Ljava/net/InetAddress;I)Ljava/net/InetSocketAddress;"
)
)
private static InetAddress eliminateRDNS(final String name) throws UnknownHostException {
final InetAddress ret = InetAddress.getByName(name);
final byte[] address = ret.getAddress();
private static InetSocketAddress eliminateRDNS(InetAddress addr, final int port,
@Local(ordinal = 0, argsOnly = true) final ServerAddress serverAddress) throws UnknownHostException {
final byte[] address = addr.getAddress();
if (address != null) {
// pass name to prevent rDNS
return InetAddress.getByAddress(name, address);
addr = InetAddress.getByAddress(serverAddress.getHost(), address);
}
return ret;
return new InetSocketAddress(addr, port);
}
}

View File

@@ -15,7 +15,7 @@ public final class ChunkSystemConverters {
private static final int DEFAULT_ENTITY_CHUNK_DATA_VERSION = -1;
private static int getCurrentVersion() {
return SharedConstants.getCurrentVersion().getDataVersion().getVersion();
return SharedConstants.getCurrentVersion().dataVersion().version();
}
private static int getDataVersion(final CompoundTag data, final int dfl) {

View File

@@ -3,6 +3,7 @@ package ca.spottedleaf.moonrise.patches.chunk_system.entity;
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkData;
import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.animal.HappyGhast;
import net.minecraft.world.entity.monster.Shulker;
import net.minecraft.world.entity.vehicle.AbstractMinecart;
import net.minecraft.world.entity.vehicle.Boat;
@@ -13,7 +14,7 @@ public interface ChunkSystemEntity {
// for mods to override
public default boolean moonrise$isHardCollidingUncached() {
return this instanceof Boat || this instanceof AbstractMinecart || this instanceof Shulker || ((Entity)this).canBeCollidedWith();
return this instanceof Boat || this instanceof AbstractMinecart || this instanceof Shulker || this instanceof HappyGhast || ((Entity)this).canBeCollidedWith(null);
}
public FullChunkStatus moonrise$getChunkStatus();

View File

@@ -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;

View File

@@ -5,6 +5,7 @@ import ca.spottedleaf.moonrise.common.list.EntityList;
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkData;
import ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity;
import com.google.common.collect.ImmutableList;
import com.mojang.logging.LogUtils;
import it.unimi.dsi.fastutil.objects.Reference2ObjectMap;
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
import net.minecraft.nbt.CompoundTag;
@@ -14,6 +15,7 @@ import net.minecraft.nbt.Tag;
import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.Mth;
import net.minecraft.util.ProblemReporter;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntitySpawnReason;
import net.minecraft.world.entity.EntityType;
@@ -21,9 +23,14 @@ import net.minecraft.world.entity.boss.EnderDragonPart;
import net.minecraft.world.entity.boss.enderdragon.EnderDragon;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.storage.EntityStorage;
import net.minecraft.world.level.entity.Visibility;
import net.minecraft.world.level.storage.TagValueInput;
import net.minecraft.world.level.storage.TagValueOutput;
import net.minecraft.world.level.storage.ValueInput;
import net.minecraft.world.phys.AABB;
import org.slf4j.Logger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
@@ -32,6 +39,8 @@ import java.util.function.Predicate;
public final class ChunkEntitySlices {
private static final Logger LOGGER = LogUtils.getLogger();
public final int minSection;
public final int maxSection;
public final int chunkX;
@@ -74,9 +83,12 @@ public final class ChunkEntitySlices {
this.chunkData = chunkData;
}
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.getListOrEmpty("Entities"), world, EntitySpawnReason.LOAD).collect(ImmutableList.toImmutableList());
public static List<Entity> readEntities(final ServerLevel world, final ChunkPos pos, final CompoundTag compoundTag) {
try (final ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(ChunkAccess.problemPath(pos), LOGGER)) {
ValueInput valueinput = TagValueInput.create(scopedCollector, world.registryAccess(), compoundTag);
// TODO check this and below on update for format changes
return EntityType.loadEntitiesRecursive(valueinput.childrenListOrEmpty("Entities"), world, EntitySpawnReason.LOAD).collect(ImmutableList.toImmutableList());
}
}
// Paper start - rewrite chunk system
@@ -104,12 +116,22 @@ public final class ChunkEntitySlices {
}
final ListTag entitiesTag = new ListTag();
for (final Entity entity : PlatformHooks.get().modifySavedEntities(world, chunkPos.x, chunkPos.z, entities)) {
CompoundTag compoundTag = new CompoundTag();
if (entity.save(compoundTag)) {
entitiesTag.add(compoundTag);
try (final ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(ChunkAccess.problemPath(chunkPos), LOGGER)) {
for (final Entity entity : PlatformHooks.get().modifySavedEntities(world, chunkPos.x, chunkPos.z, entities)) {
final TagValueOutput savedEntity = TagValueOutput.createWithContext(
scopedCollector.forChild(entity.problemPath()), entity.registryAccess()
);
try {
if (entity.save(savedEntity)) {
entitiesTag.add(savedEntity.buildResult());
}
} catch (final Exception ex) {
LOGGER.error("Entity type " + entity.getType() + " failed to serialize", ex);
}
}
}
final CompoundTag ret = NbtUtils.addCurrentDataVersion(new CompoundTag());
ret.put("Entities", entitiesTag);
ret.store("Position", ChunkPos.CODEC, chunkPos);

View File

@@ -45,8 +45,7 @@ public final class ClientEntityLookup extends EntityLookup {
final boolean ticking = this.tickingChunks.contains(CoordinateUtils.getChunkKey(chunkX, chunkZ));
final ChunkEntitySlices ret = new ChunkEntitySlices(
this.world, chunkX, chunkZ,
ticking ? FullChunkStatus.ENTITY_TICKING : FullChunkStatus.FULL, null,
this.world, chunkX, chunkZ, ticking ? FullChunkStatus.ENTITY_TICKING : FullChunkStatus.FULL, null,
WorldUtil.getMinSection(this.world), WorldUtil.getMaxSection(this.world)
);

View File

@@ -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.entity.ChunkEntitySlices;
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.ServerPlayer;
import net.minecraft.server.level.TicketType;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.projectile.ThrownEnderpearl;
import net.minecraft.world.level.entity.LevelCallback;
public final class ServerEntityLookup extends EntityLookup {
@@ -19,9 +24,18 @@ public final class ServerEntityLookup extends EntityLookup {
private final ServerLevel serverWorld;
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();
private final boolean keepEnderPearlsTicking;
public ServerEntityLookup(final ServerLevel world, final LevelCallback<Entity> worldCallback) {
super(world, worldCallback);
this.serverWorld = world;
this.keepEnderPearlsTicking = PlatformHooks.get().addTicketForEnderPearls(world);
}
@Override
@@ -63,6 +77,10 @@ public final class ServerEntityLookup extends EntityLookup {
if (entity instanceof ServerPlayer 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(
entity,
CoordinateUtils.getChunkSectionKey(oldSectionX, oldSectionY, oldSectionZ),
@@ -75,6 +93,9 @@ public final class ServerEntityLookup extends EntityLookup {
if (entity instanceof ServerPlayer player) {
((ChunkSystemServerLevel)this.serverWorld).moonrise$getNearbyPlayers().addPlayer(player);
}
if (entity instanceof ThrownEnderpearl enderpearl) {
this.addEnderPearl(CoordinateUtils.getChunkKey(enderpearl.chunkPosition()));
}
}
@Override
@@ -82,6 +103,9 @@ public final class ServerEntityLookup extends EntityLookup {
if (entity instanceof ServerPlayer player) {
((ChunkSystemServerLevel)this.serverWorld).moonrise$getNearbyPlayers().removePlayer(player);
}
if (entity instanceof ThrownEnderpearl enderpearl) {
this.removeEnderPearl(CoordinateUtils.getChunkKey(enderpearl.chunkPosition()));
}
}
@Override
@@ -112,4 +136,31 @@ public final class ServerEntityLookup extends EntityLookup {
protected boolean screenEntity(final Entity entity, final boolean fromDisk, final boolean event) {
return PlatformHooks.get().screenEntity(this.serverWorld, entity, fromDisk, event);
}
private void addEnderPearl(final long coordinate) {
if (!this.keepEnderPearlsTicking) {
return;
}
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) {
if (!this.keepEnderPearlsTicking) {
return;
}
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);
}
}

View File

@@ -119,7 +119,7 @@ public final class PoiChunk {
final CompoundTag sections = new CompoundTag();
ret.put("Sections", sections);
ret.putInt("DataVersion", SharedConstants.getCurrentVersion().getDataVersion().getVersion());
ret.putInt("DataVersion", SharedConstants.getCurrentVersion().dataVersion().version());
final ServerLevel world = this.world;
final int chunkX = this.chunkX;

View File

@@ -47,12 +47,16 @@ import java.util.function.Function;
public final class RegionizedPlayerChunkLoader {
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 LOADED_TICKET_LEVEL = ChunkTaskScheduler.getTicketLevel(ChunkStatus.EMPTY);
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 {
private volatile ViewDistances viewDistances;
@@ -147,7 +151,7 @@ public final class RegionizedPlayerChunkLoader {
}
public static int getAPITickViewDistance(final ServerPlayer player) {
final ServerLevel level = player.serverLevel();
final ServerLevel level = player.level();
final PlayerChunkLoaderData data = ((ChunkSystemServerPlayer)player).moonrise$getChunkLoader();
if (data == null) {
return ((ChunkSystemServerLevel)level).moonrise$getPlayerChunkLoader().getAPITickDistance();
@@ -156,7 +160,7 @@ public final class RegionizedPlayerChunkLoader {
}
public static int getAPIViewDistance(final ServerPlayer player) {
final ServerLevel level = player.serverLevel();
final ServerLevel level = player.level();
final PlayerChunkLoaderData data = ((ChunkSystemServerPlayer)player).moonrise$getChunkLoader();
if (data == null) {
return ((ChunkSystemServerLevel)level).moonrise$getPlayerChunkLoader().getAPIViewDistance();
@@ -166,7 +170,7 @@ public final class RegionizedPlayerChunkLoader {
}
public static int getAPISendViewDistance(final ServerPlayer player) {
final ServerLevel level = player.serverLevel();
final ServerLevel level = player.level();
final PlayerChunkLoaderData data = ((ChunkSystemServerPlayer)player).moonrise$getChunkLoader();
if (data == null) {
return ((ChunkSystemServerLevel)level).moonrise$getPlayerChunkLoader().getAPISendViewDistance();

View File

@@ -1,5 +1,6 @@
package ca.spottedleaf.moonrise.patches.chunk_system.scheduling;
import ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue;
import ca.spottedleaf.concurrentutil.lock.ReentrantAreaLock;
import ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable;
import ca.spottedleaf.concurrentutil.util.Priority;
@@ -82,6 +83,7 @@ public final class ChunkHolderManager {
private long currentTick;
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) -> {
if (c1 == c2) {
return 0;
@@ -112,20 +114,20 @@ public final class ChunkHolderManager {
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 ticketMask = (1 << ticketShift) - 1;
final List<ChunkProgressionTask> scheduledTasks = new ArrayList<>();
final List<NewChunkHolder> changedFullStatus = new ArrayList<>();
final boolean ret;
final ReentrantAreaLock.Node ticketLock = this.ticketLockArea.lock(
((posX >> ticketShift) - 1) << ticketShift,
((posZ >> ticketShift) - 1) << ticketShift,
(((posX >> ticketShift) + 1) << ticketShift) | ticketMask,
(((posZ >> ticketShift) + 1) << ticketShift) | ticketMask
((chunkX >> ticketShift) - 1) << ticketShift,
((chunkZ >> ticketShift) - 1) << ticketShift,
(((chunkX >> ticketShift) + 1) << ticketShift) | ticketMask,
(((chunkZ >> ticketShift) + 1) << ticketShift) | ticketMask
);
try {
ret = this.processTicketUpdatesNoLock(posX >> ticketShift, posZ >> ticketShift, scheduledTasks, changedFullStatus);
ret = this.processTicketUpdatesNoLock(chunkX >> ticketShift, chunkZ >> ticketShift, scheduledTasks, changedFullStatus);
} finally {
this.ticketLockArea.unlock(ticketLock);
}
@@ -805,6 +807,9 @@ public final class ChunkHolderManager {
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();) {
final long sectionKey = iterator.nextLong();
@@ -813,9 +818,16 @@ public final class ChunkHolderManager {
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(
CoordinateUtils.getChunkX(sectionKey) << sectionShift,
CoordinateUtils.getChunkZ(sectionKey) << sectionShift
((lowerChunkX >> ticketShift) - 1) << ticketShift,
((lowerChunkZ >> ticketShift) - 1) << ticketShift,
(((lowerChunkX >> ticketShift) + 1) << ticketShift) | ticketMask,
(((lowerChunkZ >> ticketShift) + 1) << ticketShift) | ticketMask
);
try {
@@ -862,9 +874,23 @@ public final class ChunkHolderManager {
if (chunkToExpireCount.isEmpty()) {
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 {
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();
@@ -1091,14 +1117,9 @@ public final class ChunkHolderManager {
return;
}
if (!TickThread.isTickThread()) {
this.taskScheduler.scheduleChunkTask(() -> {
final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = ChunkHolderManager.this.pendingFullLoadUpdate;
for (int i = 0, len = changedFullStatus.size(); i < len; ++i) {
pendingFullLoadUpdate.add(changedFullStatus.get(i));
}
ChunkHolderManager.this.processPendingFullUpdate();
}, Priority.HIGHEST);
// These will be handled on the next ServerChunkCache$MainThreadExecutor#pollTask, as it runs the distance manager update
// which will invoke processTicketUpdates
this.offThreadPendingFullLoadUpdate.addAll(changedFullStatus);
} else {
final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = this.pendingFullLoadUpdate;
for (int i = 0, len = changedFullStatus.size(); i < len; ++i) {
@@ -1379,36 +1400,20 @@ public final class ChunkHolderManager {
}
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) {
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");
}
List<NewChunkHolder> changedFullStatus = null;
final boolean isTickThread = TickThread.isTickThread();
boolean ret = false;
final boolean canProcessFullUpdates = processFullUpdates & isTickThread;
final boolean canProcessScheduling = scheduledTasks == null;
if (this.ticketLevelPropagator.hasPendingUpdates()) {
if (scheduledTasks == null) {
scheduledTasks = new ArrayList<>();
}
changedFullStatus = new ArrayList<>();
final List<ChunkProgressionTask> scheduledTasks = new ArrayList<>();
final List<NewChunkHolder> changedFullStatus = new ArrayList<>();
this.blockTicketUpdates();
try {
@@ -1419,27 +1424,42 @@ public final class ChunkHolderManager {
} finally {
this.unblockTicketUpdates(Boolean.FALSE);
}
}
if (changedFullStatus != null) {
this.addChangedStatuses(changedFullStatus);
}
if (canProcessScheduling && scheduledTasks != null) {
for (int i = 0, len = scheduledTasks.size(); i < len; ++i) {
scheduledTasks.get(i).schedule();
}
}
if (canProcessFullUpdates) {
if (isTickThread) {
ret |= this.processPendingFullUpdate();
}
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
private boolean processPendingFullUpdate() {
this.processOffThreadFullUpdates();
final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = this.pendingFullLoadUpdate;
boolean ret = false;

View File

@@ -117,9 +117,11 @@ public final class NewChunkHolder {
if (!transientChunk) {
if (entityChunk != null) {
final List<Entity> entities = ChunkEntitySlices.readEntities(this.world, entityChunk);
final ChunkPos pos = new ChunkPos(this.chunkX, this.chunkZ);
((ChunkSystemServerLevel)this.world).moonrise$getEntityLookup().addEntityChunkEntities(entities, new ChunkPos(this.chunkX, this.chunkZ));
final List<Entity> entities = ChunkEntitySlices.readEntities(this.world, pos, entityChunk);
((ChunkSystemServerLevel)this.world).moonrise$getEntityLookup().addEntityChunkEntities(entities, pos);
}
}

View File

@@ -30,4 +30,5 @@ public interface ChunkSystemTicketType<T> {
public long[] moonrise$getCounterTypes();
public void moonrise$setTimeout(final long to);
}

View File

@@ -2091,7 +2091,7 @@ public final class CollisionUtil {
continue;
}
if ((entity == null && otherEntity.canBeCollidedWith()) || (entity != null && entity.canCollideWith(otherEntity))) {
if ((entity == null && otherEntity.canBeCollidedWith(entity)) || (entity != null && entity.canCollideWith(otherEntity))) {
if (checkOnly) {
return true;
} else {

View File

@@ -177,7 +177,7 @@ accessible method net/minecraft/server/network/PlayerChunkSender sendChunk (Lnet
# ChunkStatusTasks
accessible method net/minecraft/world/level/chunk/status/ChunkStatusTasks postLoadProtoChunk (Lnet/minecraft/server/level/ServerLevel;Ljava/util/List;)V
accessible method net/minecraft/world/level/chunk/status/ChunkStatusTasks postLoadProtoChunk (Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/level/storage/ValueInput$ValueInputList;)V
accessible method net/minecraft/world/level/chunk/status/ChunkStatusTasks light (Lnet/minecraft/world/level/chunk/status/WorldGenContext;Lnet/minecraft/world/level/chunk/status/ChunkStep;Lnet/minecraft/util/StaticCache2D;Lnet/minecraft/world/level/chunk/ChunkAccess;)Ljava/util/concurrent/CompletableFuture;

View File

@@ -54,6 +54,7 @@
"chunk_system.TicketMixin",
"chunk_system.TicketStorageMixin",
"chunk_system.TicketTypeMixin",
"chunk_system.WaypointTransmitterMixin",
"chunk_tick_iteration.ChunkMapMixin",
"chunk_tick_iteration.DistanceManagerMixin",
"chunk_tick_iteration.ServerChunkCacheMixin",
@@ -144,5 +145,5 @@
},
"overwrites": {
"conformVisibility": true
}
}
}