Compare commits

..

32 Commits

Author SHA1 Message Date
Spottedleaf
6841805446 Set version to 0.1.0-beta.13 2025-06-09 02:13:51 -07:00
Spottedleaf
eb20846213 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:12:01 -07:00
Spottedleaf
66a0850ac9 Set version to 0.1.0-SNAPSHOT 2025-02-24 20:59:03 -08:00
Spottedleaf
9a16a91fb8 Set version to 0.1.0-beta.12 2025-02-24 20:52:25 -08:00
Jason Penilla
580041a1a1 Clear lastSection on game event listener removal (fixes #87) (backport of #99) 2025-02-24 17:40:26 -07:00
Spottedleaf
fb31d0e1f7 Set version to 0.1.0-SNAPSHOT 2025-01-27 08:20:45 -08:00
Spottedleaf
0b2070d781 Set version to 0.1.0-beta.11 2025-01-27 08:12:17 -08:00
Spottedleaf
30a79469e3 Correctly retrun true for empty input shapes in EntityGetter#isUnobstructed
Vanilla will return true for empty shapes, so we should as well.
2025-01-27 07:59:20 -08:00
Jason Penilla
254b331259 Exclude transitive deps provided by Minecraft 2024-12-04 10:19:20 -07:00
Jason Penilla
a21c44ad31 Use libraries from Paper repo (#82)
* Use YamlConfig from Paper repo

* Add comment to settings

* Use ConcurrentUtil from Paper repo and use release of YamlConfig

* Use ConcurrentUtil release
2024-12-03 20:33:24 -07:00
Spottedleaf
77ba4a4584 Throw when sync loading chunks after shutdown
The caller would block indefinitely if a sync load is requested
during shutdown. Rather than block indefinitely, we should throw
an exception to indicate to the caller that the chunk system is
unable to process requests.
2024-12-03 20:32:14 -07:00
Spottedleaf
a510acbd78 Set version to 0.1.0-SNAPSHOT 2024-12-01 15:57:47 -08:00
Spottedleaf
6fdc3cb1df Set version to 0.1.0-beta.10 2024-12-01 15:52:36 -08:00
Spottedleaf
04e2b976ac Fix several off-by-one errors in view distance calculations
1. For NearbyPlayers, we need to be using the view distance, and
   not the load distance (which is +1 of the view distance).
2. Correctly clamp tick distance to view distance. Since
   load distance is +1 of view distance, we need to subtract
   one from the load distance when clamping.

Additionally, add checks inside ViewDistances to ensure that
the inputs are in range to catch future errors.
2024-12-01 15:23:59 -08:00
Spottedleaf
bd938e6e35 Clamp simulation distance
Values above MAX_VIEW_DISTANCE do not make sense to configure,
as it is clamped to the load view distance.
2024-12-01 14:24:33 -08:00
Spottedleaf
3624d261f8 Adjust constant collision shape determination
Our previous hack did not actually catch every case. For now,
it will only assume a constant collision shape of EMPTY for
air blocks.

Fixes https://github.com/PaperMC/Paper/issues/11697
2024-12-01 13:33:31 -08:00
Spottedleaf
6c75d6935e Force LazyEntityCollisionContext#getEntity() to delegate
By delegating when the entity is retrieved, we can correctly catch
cases where the collision method is inspecting some entity state.
2024-12-01 13:33:14 -08:00
Spottedleaf
e40c40613d Only call config initialisers if reload succeeded 2024-12-01 13:33:01 -08:00
Jason Penilla
84e7106762 Disable immediate loading screen closure by default 2024-11-26 15:53:44 -07:00
Spottedleaf
0218cb5979 Move YamlConfig to own project 2024-11-25 09:39:41 -08:00
Jason Penilla
7d0d5a56dd Back to 0.1.0-SNAPSHOT 2024-11-17 11:32:05 -07:00
Jason Penilla
4597f04a6d 0.1.0-beta.9 2024-11-17 10:56:53 -07:00
Jason Penilla
20764890a7 Update lithium, NeoForge, loom 2024-11-16 17:37:11 -07:00
Jason Penilla
f719abdb64 Update NeoForge lithium overrides 2024-11-16 17:35:43 -07:00
Jason Penilla
0dce47bba6 Apply FerriteCore config overrides automatically
New versions of FC added this mechanism

closes #66
2024-11-05 16:13:46 -07:00
Jason Penilla
47584ceee1 Use declaration order for state holder property iteration
Mostly an aesthetic change for serialization, should not have any impact on performance or correctness.
2024-10-27 18:32:42 -07:00
Jason Penilla
2fc858a683 Back to 0.1.0-SNAPSHOT 2024-10-26 11:05:51 -07:00
Jason Penilla
68ea18bc51 0.1.0-beta.8 2024-10-26 11:03:18 -07:00
Jason Penilla
9944946b29 Update Fabric API and call ServerChunkEvents.CHUNK_GENERATE 2024-10-26 09:54:34 -07:00
Jason Penilla
ec1120ed10 Back to 0.1.0-SNAPSHOT 2024-10-24 11:48:08 -07:00
Jason Penilla
8040c7a264 0.1.0-beta.7 2024-10-24 11:40:46 -07:00
Jason Penilla
a9e36795e5 fabric: fix crash when fabric-lifecycle-events-v1 not present 2024-10-23 18:32:06 -07:00
148 changed files with 3042 additions and 3817 deletions

3
.gitignore vendored
View File

@@ -116,6 +116,3 @@ run/
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
!gradle-wrapper.jar
ConcurrentUtil/
YamlConfig/

View File

@@ -12,13 +12,13 @@ Fabric/NeoForge mod for optimising performance of the integrated (singleplayer/L
Moonrise aims to optimise the game *without changing Vanilla behavior*. If you find that there are changes to Vanilla behavior,
please open an issue.
Moonrise is an official port of several important [Paper](https://github.com/PaperMC/Paper/)
Moonrise ports several important [Paper](https://github.com/PaperMC/Paper/)
patches. Listed below are notable patches:
- [Starlight](https://github.com/PaperMC/Starlight/)
- Chunk system rewrite
- Collision optimisations
- Entity tracker optimisations
- Random ticking optimisations
- [Starlight](https://github.com/PaperMC/Starlight/)
## Known Compatibility Issues
| Mod | Status |

View File

@@ -1,53 +1,41 @@
import me.modmuss50.mpp.ReleaseType
plugins {
id("java-library")
id("net.neoforged.moddev")
id("me.modmuss50.mod-publish-plugin") version "0.8.4" apply false
id("xyz.jpenilla.quiet-architectury-loom")
id("me.modmuss50.mod-publish-plugin") version "0.7.2" apply false
}
extensions.create("runConfigCommon", RunConfigCommon.class)
def getGitCommit = providers.exec {
commandLine 'git', 'rev-parse', '--short', 'HEAD'
}.standardOutput.getAsText().map { it.trim() }
def aw2at = Aw2AtTask.configureDefault(
getProject(),
layout.projectDirectory.file("src/main/resources/moonrise.accesswidener").getAsFile(),
sourceSets.main
)
neoForge {
neoFormVersion = neoform_version
validateAccessTransformers = true
accessTransformers.files.setFrom(aw2at.flatMap { t -> t.getOutputFile() })
/*
* Gets the version name from the latest Git tag
*/
// https://stackoverflow.com/questions/28498688/gradle-script-to-autoversion-and-include-the-commit-hash-in-android
def getGitCommit = { ->
def stdout = new ByteArrayOutputStream()
exec {
commandLine 'git', 'rev-parse', '--short', 'HEAD'
standardOutput = stdout
}
return stdout.toString().trim()
}
runConfigCommon {
systemProperties.put "mixin.debug", "true"
systemProperties.put "Moonrise.MaxViewDistance", "128"
}
dependencies {
compileOnly "net.fabricmc:sponge-mixin:0.15.4+mixin.0.8.7"
compileOnly "io.github.llamalad7:mixinextras-common:0.4.1"
// work around minecraft (MDG) forcing ASM 9.3 which is incompatible with the above deps...
components.withModule("net.neoforged:minecraft-dependencies", RemoveAsmConstraint.class)
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
api("ca.spottedleaf:concurrentutil:${rootProject.concurrentutil_version}") { setTransitive(false) }
api("ca.spottedleaf:yamlconfig:${rootProject.yamlconfig_version}") { setTransitive(false) }
api("org.yaml:snakeyaml:${rootProject.snakeyaml_version}")
// todo: does cloth publish a platform-agnostic jar in mojang mappings?
compileOnly "me.shedaniel.cloth:cloth-config-neoforge:${rootProject.cloth_version}"
modImplementation "me.shedaniel.cloth:cloth-config:${rootProject.cloth_version}"
}
File awFile = file("src/main/resources/moonrise.accesswidener")
allprojects {
group = rootProject.maven_group
version = rootProject.mod_version + "+" + getGitCommit.get()
version = rootProject.mod_version + "+" + getGitCommit()
plugins.apply("java-library")
plugins.apply("xyz.jpenilla.quiet-architectury-loom")
java {
withSourcesJar()
@@ -57,30 +45,26 @@ allprojects {
}
}
dependencies {
testImplementation "org.junit.jupiter:junit-jupiter:${rootProject.junit_version}"
testRuntimeOnly 'org.junit.platform:junit-platform-launcher'
}
tasks.test {
useJUnitPlatform()
}
repositories {
maven {
url = "https://repo.papermc.io/repository/maven-public/"
url "https://repo.papermc.io/repository/maven-public/"
mavenContent {
includeGroup("ca.spottedleaf")
}
}
maven {
url = "https://api.modrinth.com/maven"
url "https://api.modrinth.com/maven"
mavenContent {
includeGroup("maven.modrinth")
}
}
maven { url = "https://maven.shedaniel.me/" }
maven { url = "https://maven.terraformersmc.com/releases/" }
maven { url "https://maven.shedaniel.me/" }
maven { url "https://maven.terraformersmc.com/releases/" }
}
dependencies {
minecraft "com.mojang:minecraft:${project.minecraft_version}"
mappings loom.officialMojangMappings()
}
// make build reproducible
@@ -98,22 +82,31 @@ allprojects {
rename { "${it}_${rootProject.base.archivesName.get()}"}
}
}
loom {
accessWidenerPath = awFile
mixin {
useLegacyMixinAp = false
}
}
}
subprojects {
plugins.apply("me.modmuss50.mod-publish-plugin")
plugins.apply 'java-library'
plugins.apply 'com.gradleup.shadow'
loom.mods {
main {
sourceSet("main")
sourceSet("main", project.rootProject)
}
}
loom.runs.all {
ideConfigGenerated true
// property "mixin.debug", "true"
}
configurations.create("libs")
configurations.shadow {
extendsFrom(configurations.libs)
}
configurations.implementation {
extendsFrom(configurations.libs)
}
plugins.apply("me.modmuss50.mod-publish-plugin")
publishMods {
file = remapJar.archiveFile
if (project.version.contains("-beta.")) {
type = ReleaseType.BETA
} else {
@@ -137,7 +130,20 @@ subprojects {
}
// Setup a run with lithium for compatibility testing
sourceSets.create("lithium")
configurations.create("lithium")
loom {
createRemapConfigurations(sourceSets.lithium)
runs {
register("lithiumClient") {
client()
property "mixin.debug", "true"
}
}
}
tasks.named("runLithiumClient", net.fabricmc.loom.task.RunGameTask.class) {
getClasspath().from(configurations.modRuntimeClasspathLithiumMapped)
}
dependencies {
String coordinates = "maven.modrinth:lithium:"
if (getProject().name == "Moonrise-NeoForge") {
@@ -145,6 +151,10 @@ subprojects {
} else {
coordinates += rootProject.fabric_lithium_version
}
lithium coordinates
modLithiumRuntimeOnly coordinates
}
}
loom.runs.all {
ideConfigGenerated false
}

View File

@@ -1,11 +0,0 @@
repositories {
gradlePluginPortal()
mavenCentral()
maven("https://maven.fabricmc.net/")
maven("https://maven.architectury.dev/")
}
dependencies {
implementation("net.fabricmc:access-widener:2.1.0")
implementation("dev.architectury:at:1.0.1")
}

View File

@@ -1,152 +0,0 @@
import dev.architectury.at.AccessChange;
import dev.architectury.at.AccessTransform;
import dev.architectury.at.AccessTransformSet;
import dev.architectury.at.ModifierChange;
import dev.architectury.at.io.AccessTransformFormat;
import dev.architectury.at.io.AccessTransformFormats;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.io.StringWriter;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.List;
import javax.inject.Inject;
import net.fabricmc.accesswidener.AccessWidenerReader;
import net.fabricmc.accesswidener.AccessWidenerVisitor;
import org.cadixdev.bombe.type.signature.MethodSignature;
import org.gradle.api.DefaultTask;
import org.gradle.api.Project;
import org.gradle.api.file.ProjectLayout;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.tasks.CacheableTask;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.PathSensitive;
import org.gradle.api.tasks.PathSensitivity;
import org.gradle.api.tasks.SourceSet;
import org.gradle.api.tasks.TaskAction;
import org.gradle.api.tasks.TaskProvider;
@CacheableTask
public abstract class Aw2AtTask extends DefaultTask {
@InputFile
@PathSensitive(PathSensitivity.NONE)
public abstract RegularFileProperty getInputFile();
@OutputFile
public abstract RegularFileProperty getOutputFile();
@Inject
public abstract ProjectLayout getLayout();
public static TaskProvider<Aw2AtTask> configureDefault(
final Project project,
final File awFile,
final SourceSet sourceSet
) {
final TaskProvider<Aw2AtTask> aw2at = project.getTasks().register("aw2at", Aw2AtTask.class, task -> {
task.getOutputFile().set(project.getLayout().getBuildDirectory().file("aw2at/files/accesstransformer.cfg"));
task.getInputFile().set(awFile);
});
final TaskProvider<CopyTask> copyTask = project.getTasks().register("copyAt", CopyTask.class, copy -> {
copy.getInputFile().set(aw2at.flatMap(Aw2AtTask::getOutputFile));
copy.getOutputDirectory().set(project.getLayout().getBuildDirectory().dir("aw2at/dir"));
copy.getDestination().set("META-INF/accesstransformer.cfg");
});
sourceSet.resources(resources -> {
resources.srcDir(copyTask.flatMap(CopyTask::getOutputDirectory));
});
return aw2at;
}
@TaskAction
public void run() {
try (final BufferedReader reader = Files.newBufferedReader(this.getInputFile().get().getAsFile().toPath())) {
final AccessTransformSet accessTransformSet = toAccessTransformSet(reader);
Files.deleteIfExists(this.getOutputFile().get().getAsFile().toPath());
Files.createDirectories(this.getOutputFile().get().getAsFile().toPath().getParent());
writeLF(AccessTransformFormats.FML, this.getOutputFile().get().getAsFile().toPath(), accessTransformSet);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
private static void writeLF(final AccessTransformFormat format, final Path path, final AccessTransformSet at) throws IOException {
final StringWriter stringWriter = new StringWriter();
final BufferedWriter writer = new BufferedWriter(stringWriter);
format.write(writer, at);
writer.close();
final List<String> lines = Arrays.stream(stringWriter.toString()
// unify line endings
.replace("\r\n", "\n")
.split("\n"))
// skip blank lines
.filter(it -> !it.isBlank())
// sort
.sorted()
.toList();
Files.writeString(path, String.join("\n", lines));
}
// Below methods are heavily based on architectury-loom Aw2At class (MIT licensed)
/*
MIT License
Copyright (c) 2016 FabricMC
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
public static AccessTransformSet toAccessTransformSet(final BufferedReader reader) throws IOException {
AccessTransformSet atSet = AccessTransformSet.create();
new AccessWidenerReader(new AccessWidenerVisitor() {
@Override
public void visitClass(final String name, final AccessWidenerReader.AccessType access, final boolean transitive) {
atSet.getOrCreateClass(name).merge(toAt(access));
}
@Override
public void visitMethod(final String owner, final String name, final String descriptor, final AccessWidenerReader.AccessType access, final boolean transitive) {
atSet.getOrCreateClass(owner).mergeMethod(MethodSignature.of(name, descriptor), toAt(access));
}
@Override
public void visitField(final String owner, final String name, final String descriptor, final AccessWidenerReader.AccessType access, final boolean transitive) {
atSet.getOrCreateClass(owner).mergeField(name, toAt(access));
}
}).read(reader);
return atSet;
}
public static AccessTransform toAt(final AccessWidenerReader.AccessType access) {
return switch (access) {
case ACCESSIBLE -> AccessTransform.of(AccessChange.PUBLIC);
case EXTENDABLE, MUTABLE -> AccessTransform.of(AccessChange.PUBLIC, ModifierChange.REMOVE);
};
}
}

View File

@@ -1,44 +0,0 @@
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Comparator;
import java.util.stream.Stream;
import org.gradle.api.DefaultTask;
import org.gradle.api.file.DirectoryProperty;
import org.gradle.api.file.RegularFileProperty;
import org.gradle.api.provider.Property;
import org.gradle.api.tasks.Input;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.OutputDirectory;
import org.gradle.api.tasks.TaskAction;
public abstract class CopyTask extends DefaultTask {
@InputFile
public abstract RegularFileProperty getInputFile();
@Input
public abstract Property<String> getDestination();
@OutputDirectory
public abstract DirectoryProperty getOutputDirectory();
@TaskAction
public void run() {
final Path outputDirPath = this.getOutputDirectory().get().getAsFile().toPath();
try {
try (final Stream<Path> walk = Files.walk(outputDirPath)) {
for (final Path path : walk.sorted(Comparator.reverseOrder()).toList()) {
Files.delete(path);
}
}
final Path destFile = outputDirPath.resolve(this.getDestination().get());
Files.createDirectories(destFile.getParent());
Files.copy(this.getInputFile().get().getAsFile().toPath(), destFile);
} catch (final IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -1,24 +0,0 @@
import java.util.Objects;
import org.gradle.api.artifacts.CacheableRule;
import org.gradle.api.artifacts.ComponentMetadataContext;
import org.gradle.api.artifacts.ComponentMetadataRule;
@CacheableRule
public abstract class RemoveAsmConstraint implements ComponentMetadataRule {
@Override
public void execute(final ComponentMetadataContext ctx) {
ctx.getDetails().allVariants(variants -> {
variants.withDependencies(deps -> {
deps.forEach(dep -> {
if (Objects.equals(dep.getGroup(), "org.ow2.asm")) {
if (dep.getVersionConstraint().getStrictVersion() != null) {
dep.version(v -> {
v.require(v.getStrictVersion());
});
}
}
});
});
});
}
}

View File

@@ -1,5 +0,0 @@
import org.gradle.api.provider.MapProperty;
public abstract class RunConfigCommon {
public abstract MapProperty<String, String> getSystemProperties();
}

View File

@@ -1,20 +1,21 @@
import java.util.stream.Collectors
import net.fabricmc.loom.util.gradle.SourceSetHelper
plugins {
id("quiet-fabric-loom")
id("xyz.jpenilla.quiet-architectury-loom")
id 'maven-publish'
id 'com.gradleup.shadow'
}
configurations.create("libs")
configurations.shadow {
extendsFrom(configurations.libs)
}
configurations.implementation {
extendsFrom(configurations.libs)
}
dependencies {
minecraft "com.mojang:minecraft:${project.minecraft_version}"
mappings loom.officialMojangMappings()
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
testImplementation "net.fabricmc:fabric-loader-junit:${project.loader_version}"
add('shadow', project([path: ":", configuration: "namedElements"]))
runtimeOnly(project(":").sourceSets.main.output)
shadow(project(":"))
compileOnly(project(":"))
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
libs("ca.spottedleaf:concurrentutil:${rootProject.concurrentutil_version}") { setTransitive(false) }
libs("ca.spottedleaf:yamlconfig:${rootProject.yamlconfig_version}") { setTransitive(false) }
@@ -22,29 +23,23 @@ dependencies {
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}"
modImplementation "com.terraformersmc:modmenu:11.0.1"
modImplementation platform(fabricApiLibs.bom)
modImplementation fabricApiLibs.command.api.v2
modImplementation fabricApiLibs.lifecycle.events.v1
include fabricApiLibs.command.api.v2
include fabricApiLibs.base
}
tasks.processResources {
def properties = [
"version": project.version,
"minecraft_version": minecraft_version,
"loader_version": loader_version,
"mod_version": mod_version
]
inputs.properties(properties)
processResources {
inputs.property "version", project.version
filesMatching("fabric.mod.json") {
expand properties
expand "version": project.version, "minecraft_version": minecraft_version, "loader_version": loader_version, "mod_version": mod_version
}
}
tasks.shadowJar {
shadowJar {
archiveClassifier = "dev-all"
destinationDirectory = layout.buildDirectory.dir("libs")
configurations = [project.configurations.shadow]
@@ -54,7 +49,6 @@ tasks.shadowJar {
}
publishMods {
file = remapJar.archiveFile
modLoaders = ["fabric"]
modrinth {
@@ -72,52 +66,3 @@ publishMods {
)
}
}
loom {
accessWidenerPath.set(getRootProject().file("src/main/resources/moonrise.accesswidener"))
mixin {
useLegacyMixinAp = false
}
runs.configureEach {
ideConfigGenerated true
}
mods {
main {
sourceSet("main")
sourceSet("main", project.rootProject)
}
}
}
tasks.test {
def classPathGroups = SourceSetHelper.getClasspath(loom.mods.main, getProject()).stream()
.map(File.&getAbsolutePath)
.collect(Collectors.joining(File.pathSeparator))
systemProperty("fabric.classPathGroups", classPathGroups)
}
afterEvaluate {
loom.runs.configureEach { cfg ->
runConfigCommon.systemProperties.get().each {
cfg.property it.key, it.value
}
}
}
// Setup a run with lithium for compatibility testing
sourceSets.create("lithium")
loom {
createRemapConfigurations(sourceSets.lithium)
runs {
register("lithiumClient") {
client()
}
}
}
configurations.modLithiumRuntimeOnly {
extendsFrom configurations.lithium
}
tasks.named("runLithiumClient", net.fabricmc.loom.task.RunGameTask.class) {
getClasspath().from(configurations.modRuntimeClasspathLithiumMapped)
}

View File

@@ -1,45 +1,50 @@
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 ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder;
import net.fabricmc.fabric.api.event.Event;
import net.fabricmc.fabric.api.event.EventFactory;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps;
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;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Explosion;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ImposterProtoChunk;
import net.minecraft.world.level.chunk.LevelChunk;
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.phys.AABB;
import java.util.Collection;
import net.minecraft.world.phys.Vec3;
import java.util.List;
import java.util.function.Predicate;
public final class FabricHooks extends BaseChunkSystemHooks implements PlatformHooks {
public final class FabricHooks implements PlatformHooks {
private static final boolean HAS_FABRIC_LIFECYCLE_EVENTS = FabricLoader.getInstance().isModLoaded("fabric-lifecycle-events-v1");
public interface OnExplosionDetonate {
void onExplosion(final Level world, final Explosion explosion, final List<Entity> possiblyAffecting, final double diameter);
}
public static final Event<OnExplosionDetonate> ON_EXPLOSION_DETONATE = EventFactory.createArrayBacked(
OnExplosionDetonate.class,
listeners -> (final Level world, final Explosion explosion, final List<Entity> possiblyAffecting, final double diameter) -> {
for (int i = 0; i < listeners.length; i++) {
listeners[i].onExplosion(world, explosion, possiblyAffecting, diameter);
}
}
);
@Override
public String getBrand() {
return "Moonrise";
@@ -57,6 +62,16 @@ public final class FabricHooks extends BaseChunkSystemHooks implements PlatformH
};
}
@Override
public void onExplosion(final Level world, final Explosion explosion, final List<Entity> possiblyAffecting, final double diameter) {
ON_EXPLOSION_DETONATE.invoker().onExplosion(world, explosion, possiblyAffecting, diameter);
}
@Override
public Vec3 modifyExplosionKnockback(final Level world, final Explosion explosion, final Entity entity, final Vec3 original) {
return original;
}
@Override
public boolean hasCurrentlyLoadingChunk() {
return false;
@@ -75,7 +90,7 @@ public final class FabricHooks extends BaseChunkSystemHooks implements PlatformH
@Override
public void chunkFullStatusComplete(final LevelChunk newChunk, final ProtoChunk original) {
if (HAS_FABRIC_LIFECYCLE_EVENTS) {
ServerChunkEvents.CHUNK_LOAD.invoker().onChunkLoad((ServerLevel)newChunk.getLevel(), newChunk);
ServerChunkEvents.CHUNK_LOAD.invoker().onChunkLoad((ServerLevel) newChunk.getLevel(), newChunk);
if (!(original instanceof ImposterProtoChunk)) {
ServerChunkEvents.CHUNK_GENERATE.invoker().onChunkGenerate((ServerLevel)newChunk.getLevel(), newChunk);
}
@@ -88,19 +103,19 @@ public final class FabricHooks extends BaseChunkSystemHooks implements PlatformH
}
@Override
public void onChunkHolderTicketChange(final ServerLevel world, final ChunkHolder holder, final int oldLevel, final int newLevel) {
public void onChunkHolderTicketChange(final ServerLevel world, final NewChunkHolder holder, final int oldLevel, final int newLevel) {
}
@Override
public void chunkUnloadFromWorld(final LevelChunk chunk) {
if (HAS_FABRIC_LIFECYCLE_EVENTS) {
ServerChunkEvents.CHUNK_UNLOAD.invoker().onChunkUnload((ServerLevel)chunk.getLevel(), chunk);
ServerChunkEvents.CHUNK_UNLOAD.invoker().onChunkUnload((ServerLevel) chunk.getLevel(), chunk);
}
}
@Override
public void chunkSyncSave(final ServerLevel world, final ChunkAccess chunk, final SerializableChunkData data) {
public void chunkSyncSave(final ServerLevel world, final ChunkAccess chunk, final CompoundTag data) {
}
@@ -117,43 +132,13 @@ public final class FabricHooks extends BaseChunkSystemHooks implements PlatformH
@Override
public void addToGetEntities(final Level world, final Entity entity, final AABB boundingBox, final Predicate<? super Entity> predicate,
final List<Entity> into) {
final Collection<EnderDragonPart> parts = world.dragonParts();
if (parts.isEmpty()) {
return;
}
for (final EnderDragonPart part : parts) {
if (part != entity && part.getBoundingBox().intersects(boundingBox) && (predicate == null || predicate.test(part))) {
into.add(part);
}
}
}
@Override
public <T extends Entity> void addToGetEntities(final Level world, final EntityTypeTest<Entity, T> entityTypeTest, final AABB boundingBox,
final Predicate<? super T> predicate, final List<? super T> into, final int maxCount) {
if (into.size() >= maxCount) {
// fix neoforge issue: do not add if list is already full
return;
}
final Collection<EnderDragonPart> parts = world.dragonParts();
if (parts.isEmpty()) {
return;
}
for (final EnderDragonPart part : parts) {
if (!part.getBoundingBox().intersects(boundingBox)) {
continue;
}
final T casted = (T)entityTypeTest.tryCast(part);
if (casted != null && (predicate == null || predicate.test(casted))) {
into.add(casted);
if (into.size() >= maxCount) {
break;
}
}
}
}
@Override
@@ -202,12 +187,12 @@ public final class FabricHooks extends BaseChunkSystemHooks implements PlatformH
}
@Override
public long configAutoSaveInterval(final ServerLevel world) {
public long configAutoSaveInterval() {
return ConfigHolder.getConfig().chunkSaving.autoSaveInterval.getTimeTicks();
}
@Override
public int configMaxAutoSavePerTick(final ServerLevel world) {
public int configMaxAutoSavePerTick() {
return ConfigHolder.getConfig().chunkSaving.maxAutoSaveChunksPerTick;
}
@@ -215,52 +200,4 @@ public final class FabricHooks extends BaseChunkSystemHooks implements PlatformH
public boolean configFixMC159283() {
return ConfigHolder.getConfig().bugFixes.fixMC159283;
}
@Override
public boolean forceNoSave(final ChunkAccess chunk) {
return false;
}
@Override
public CompoundTag convertNBT(final DSL.TypeReference type, final DataFixer dataFixer, final CompoundTag nbt,
final int fromVersion, final int toVersion) {
return (CompoundTag)dataFixer.update(
type, new Dynamic<>(NbtOps.INSTANCE, nbt), fromVersion, toVersion
).getValue();
}
@Override
public boolean hasMainChunkLoadHook() {
return false;
}
@Override
public void mainChunkLoad(final ChunkAccess chunk, final SerializableChunkData chunkData) {
}
@Override
public List<Entity> modifySavedEntities(final ServerLevel world, final int chunkX, final int chunkZ, final List<Entity> entities) {
return entities;
}
@Override
public void unloadEntity(final Entity entity) {
entity.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK);
}
@Override
public void postLoadProtoChunk(final ServerLevel world, final ProtoChunk chunk) {
ChunkStatusTasks.postLoadProtoChunk(world, chunk.getEntities());
}
@Override
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;
}
}

View File

@@ -0,0 +1,33 @@
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);
}
}

View File

@@ -36,12 +36,13 @@
"accessWidener": "moonrise.accesswidener",
"depends": {
"fabricloader": ">=${loader_version}",
"minecraft": ">1.21.4 <1.21.6",
"minecraft": ">=1.21 <=1.21.1",
"fabric-command-api-v2": "*"
},
"custom": {
"lithium:options": {
"mixin.ai.poi": false,
"mixin.alloc.chunk_ticking": false,
"mixin.alloc.deep_passengers": false,
"mixin.alloc.entity_tracker": false,
"mixin.block.flatten_states": false,
@@ -65,6 +66,7 @@
"mixin.world.block_entity_ticking": false,
"mixin.world.chunk_access": false,
"mixin.world.explosions.block_raycast": false,
"mixin.world.explosions.cache_exposure": false,
"mixin.world.temperature_cache": false,
"mixin.world.tick_scheduler": false
},

View File

@@ -2,6 +2,7 @@
"parent": "moonrise.mixins.json",
"package": "ca.spottedleaf.moonrise.fabric.mixin",
"mixins": [
"chunk_system.FabricDistanceManagerMixin",
"chunk_system.FabricMinecraftServerMixin",
"chunk_system.FabricServerLevelMixin",
"collisions.EntityMixin"

View File

@@ -1,20 +0,0 @@
package ca.spottedleaf.moonrise.fabric;
import net.minecraft.SharedConstants;
import net.minecraft.server.Bootstrap;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.spongepowered.asm.mixin.MixinEnvironment;
class MixinAuditTest {
@BeforeAll
static void beforeAll() {
SharedConstants.tryDetectVersion();
Bootstrap.bootStrap();
}
@Test
void auditMixins() {
MixinEnvironment.getCurrentEnvironment().audit();
}
}

View File

@@ -1,26 +1,20 @@
# Done to increase the memory available to gradle.
org.gradle.jvmargs=-Xmx2G
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.configuration-cache=true
org.gradle.daemon=false
# Fabric Properties
# check these on https://modmuss50.me/fabric.html
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
minecraft_version=1.21.1
supported_minecraft_versions=1.21,1.21.1
loader_version=0.16.5
neoforge_version=21.1.79
snakeyaml_version=2.3
concurrentutil_version=0.0.3
concurrentutil_version=0.0.2
yamlconfig_version=1.0.2
cloth_version=18.0.145
modmenu_version=14.0.0-rc.2
junit_version=5.11.3
cloth_version=15.0.128
# version ids from modrinth
fabric_lithium_version=nhc57Td2
neo_lithium_version=P5VT33Jo
fabric_lithium_version=frXUdgvL
neo_lithium_version=KhdehJ6l
# Mod Properties
mod_version=0.3.0-beta.1
mod_version=0.1.0-beta.13
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.9-all.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

3
gradlew vendored
View File

@@ -86,7 +86,8 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum

View File

@@ -1,10 +1,9 @@
import java.nio.file.Files
import java.nio.file.StandardCopyOption
import net.neoforged.moddevgradle.internal.RunGameTask
import net.fabricmc.loom.util.aw2at.Aw2At
plugins {
id("net.neoforged.moddev")
id("xyz.jpenilla.quiet-architectury-loom")
id 'maven-publish'
id 'com.gradleup.shadow'
}
repositories {
@@ -14,66 +13,32 @@ repositories {
}
}
def aw2at = Aw2AtTask.configureDefault(
getProject(),
rootProject.layout.projectDirectory.file("src/main/resources/moonrise.accesswidener").getAsFile(),
sourceSets.main
)
neoForge {
version = rootProject.neoforge_version
validateAccessTransformers = true
accessTransformers.files.setFrom(aw2at.flatMap { t -> t.getOutputFile() })
mods {
moonrise {
sourceSet sourceSets.main
sourceSet rootProject.sourceSets.main
}
}
runs {
client {
client()
}
server {
server()
}
}
unitTest {
enable()
testedMod = mods.moonrise
}
configurations.implementation {
extendsFrom(configurations.shadow)
}
dependencies {
runtimeOnly(project(":").sourceSets.main.output)
shadow(project(":"))
compileOnly(project(":"))
add('shadow', project([path: ":", configuration: "namedElements"]))
neoForge "net.neoforged:neoforge:${rootProject.neoforge_version}"
libs("ca.spottedleaf:concurrentutil:${rootProject.concurrentutil_version}") { setTransitive(false) }
libs("ca.spottedleaf:yamlconfig:${rootProject.yamlconfig_version}") { setTransitive(false) }
additionalRuntimeClasspath libs("org.yaml:snakeyaml:${rootProject.snakeyaml_version}")
shadow("ca.spottedleaf:concurrentutil:${rootProject.concurrentutil_version}") { setTransitive(false) }
shadow("ca.spottedleaf:yamlconfig:${rootProject.yamlconfig_version}") { setTransitive(false) }
shadow("org.yaml:snakeyaml:${rootProject.snakeyaml_version}")
forgeExtra("org.yaml:snakeyaml:${rootProject.snakeyaml_version}")
implementation "me.shedaniel.cloth:cloth-config-neoforge:${rootProject.cloth_version}"
jarJar "me.shedaniel.cloth:cloth-config-neoforge:${rootProject.cloth_version}"
modImplementation "me.shedaniel.cloth:cloth-config-neoforge:${rootProject.cloth_version}"
include "me.shedaniel.cloth:cloth-config-neoforge:${rootProject.cloth_version}"
}
tasks.processResources {
def properties = [
"version": project.version,
"minecraft_version": minecraft_version,
"mod_version": mod_version
]
inputs.properties(properties)
processResources {
inputs.property "version", project.version
filesMatching("META-INF/neoforge.mods.toml") {
expand properties
expand "version": project.version, "minecraft_version": minecraft_version, "loader_version": loader_version, "mod_version": mod_version
}
}
tasks.jar {
archiveClassifier = "dev"
}
tasks.shadowJar {
shadowJar {
archiveClassifier = "dev-all"
destinationDirectory = layout.buildDirectory.dir("libs")
configurations = [project.configurations.shadow]
@@ -82,20 +47,9 @@ tasks.shadowJar {
relocate 'org.yaml.snakeyaml', 'ca.spottedleaf.moonrise.libs.org.yaml.snakeyaml'
}
tasks.register("productionJar", Zip.class) {
archiveClassifier = ""
archiveExtension = "jar"
destinationDirectory = layout.buildDirectory.dir("libs")
from(tasks.jarJar)
from(zipTree(tasks.shadowJar.archiveFile))
}
tasks.assemble {
dependsOn tasks.productionJar
}
Aw2At.setup(getProject(), tasks.remapJar)
publishMods {
file = productionJar.archiveFile
modLoaders = ["neoforge"]
modrinth {
@@ -113,42 +67,3 @@ publishMods {
)
}
}
afterEvaluate {
neoForge.runs.configureEach { cfg ->
runConfigCommon.systemProperties.get().each {
cfg.systemProperties.put it.key, it.value
}
}
}
// Setup a run with lithium for compatibility testing
neoForge {
runs {
lithiumClient {
client()
disableIdeRun()
}
}
}
tasks.withType(RunGameTask).configureEach {
if (name == "runLithiumClient") {
return
}
def out = gameDirectory.get().getAsFile().toPath().resolve("mods/lithium-tmp.jar")
doFirst {
Files.deleteIfExists(out)
}
}
def lithium = configurations.lithium
tasks.runLithiumClient {
def out = gameDirectory.get().getAsFile().toPath().resolve("mods/lithium-tmp.jar")
doFirst {
for (File file in lithium) {
Files.copy(file.toPath(), out, StandardCopyOption.REPLACE_EXISTING)
}
}
doLast {
Files.deleteIfExists(out)
}
}

View File

@@ -0,0 +1 @@
loom.platform=neoforge

View File

@@ -1,36 +1,28 @@
package ca.spottedleaf.moonrise.neoforge;
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 ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps;
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;
import net.minecraft.world.level.EmptyBlockGetter;
import net.minecraft.world.level.Explosion;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ImposterProtoChunk;
import net.minecraft.world.level.chunk.LevelChunk;
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.phys.AABB;
import net.minecraft.world.phys.Vec3;
import net.neoforged.neoforge.common.CommonHooks;
import net.neoforged.neoforge.common.NeoForge;
import net.neoforged.neoforge.entity.PartEntity;
@@ -38,11 +30,10 @@ 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 java.util.Collection;
import java.util.List;
import java.util.function.Predicate;
public final class NeoForgeHooks extends BaseChunkSystemHooks implements PlatformHooks {
public final class NeoForgeHooks implements PlatformHooks {
@Override
public String getBrand() {
@@ -61,6 +52,16 @@ public final class NeoForgeHooks extends BaseChunkSystemHooks implements Platfor
};
}
@Override
public void onExplosion(final Level world, final Explosion explosion, final List<Entity> possiblyAffecting, final double diameter) {
EventHooks.onExplosionDetonate(world, explosion, possiblyAffecting, diameter);
}
@Override
public Vec3 modifyExplosionKnockback(final Level world, final Explosion explosion, final Entity entity, final Vec3 original) {
return EventHooks.getExplosionKnockback(world, explosion, entity, original);
}
@Override
public boolean hasCurrentlyLoadingChunk() {
return true;
@@ -87,12 +88,10 @@ public final class NeoForgeHooks extends BaseChunkSystemHooks implements Platfor
}
@Override
public void onChunkHolderTicketChange(final ServerLevel world, final ChunkHolder holder, final int oldLevel, final int newLevel) {
final ChunkPos pos = holder.getPos();
public void onChunkHolderTicketChange(final ServerLevel world, final NewChunkHolder holder, final int oldLevel, final int newLevel) {
EventHooks.fireChunkTicketLevelUpdated(
world, CoordinateUtils.getChunkKey(pos.x, pos.z),
oldLevel, newLevel, holder
world, CoordinateUtils.getChunkKey(holder.chunkX, holder.chunkZ),
oldLevel, newLevel, holder.vanillaChunkHolder
);
}
@@ -102,7 +101,7 @@ public final class NeoForgeHooks extends BaseChunkSystemHooks implements Platfor
}
@Override
public void chunkSyncSave(final ServerLevel world, final ChunkAccess chunk, final SerializableChunkData data) {
public void chunkSyncSave(final ServerLevel world, final ChunkAccess chunk, final CompoundTag data) {
NeoForge.EVENT_BUS.post(new ChunkDataEvent.Save(chunk, world, data));
}
@@ -119,12 +118,7 @@ public final class NeoForgeHooks extends BaseChunkSystemHooks implements Platfor
@Override
public void addToGetEntities(final Level world, final Entity entity, final AABB boundingBox, final Predicate<? super Entity> predicate,
final List<Entity> into) {
final Collection<PartEntity<?>> parts = world.dragonParts();
if (parts.isEmpty()) {
return;
}
for (final PartEntity<?> part : parts) {
for (final PartEntity<?> part : world.getPartEntities()) {
if (part != entity && part.getBoundingBox().intersects(boundingBox) && (predicate == null || predicate.test(part))) {
into.add(part);
}
@@ -139,18 +133,9 @@ public final class NeoForgeHooks extends BaseChunkSystemHooks implements Platfor
return;
}
final Collection<PartEntity<?>> parts = world.dragonParts();
if (parts.isEmpty()) {
return;
}
for (final PartEntity<?> part : parts) {
if (!part.getBoundingBox().intersects(boundingBox)) {
continue;
}
for (final PartEntity<?> part : world.getPartEntities()) {
final T casted = (T)entityTypeTest.tryCast(part);
if (casted != null && (predicate == null || predicate.test(casted))) {
if (casted != null && casted.getBoundingBox().intersects(boundingBox) && (predicate == null || predicate.test(casted))) {
into.add(casted);
if (into.size() >= maxCount) {
break;
@@ -208,12 +193,12 @@ public final class NeoForgeHooks extends BaseChunkSystemHooks implements Platfor
}
@Override
public long configAutoSaveInterval(final ServerLevel world) {
public long configAutoSaveInterval() {
return ConfigHolder.getConfig().chunkSaving.autoSaveInterval.getTimeTicks();
}
@Override
public int configMaxAutoSavePerTick(final ServerLevel world) {
public int configMaxAutoSavePerTick() {
return ConfigHolder.getConfig().chunkSaving.maxAutoSaveChunksPerTick;
}
@@ -221,61 +206,4 @@ public final class NeoForgeHooks extends BaseChunkSystemHooks implements Platfor
public boolean configFixMC159283() {
return ConfigHolder.getConfig().bugFixes.fixMC159283;
}
@Override
public boolean forceNoSave(final ChunkAccess chunk) {
return false;
}
@Override
public CompoundTag convertNBT(final DSL.TypeReference type, final DataFixer dataFixer, final CompoundTag nbt,
final int fromVersion, final int toVersion) {
return (CompoundTag)dataFixer.update(
type, new Dynamic<>(NbtOps.INSTANCE, nbt), fromVersion, toVersion
).getValue();
}
@Override
public boolean hasMainChunkLoadHook() {
return true;
}
@Override
public void mainChunkLoad(final ChunkAccess chunk, final SerializableChunkData chunkData) {
NeoForge.EVENT_BUS.post(new ChunkDataEvent.Load(chunk, chunkData));
}
@Override
public List<Entity> modifySavedEntities(final ServerLevel world, final int chunkX, final int chunkZ, final List<Entity> entities) {
return entities;
}
@Override
public void unloadEntity(final Entity entity) {
entity.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK);
}
@Override
public void postLoadProtoChunk(final ServerLevel world, final ProtoChunk chunk) {
ChunkStatusTasks.postLoadProtoChunk(world, chunk.getEntities());
}
@Override
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();
}
}

View File

@@ -0,0 +1,87 @@
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);
}
}

View File

@@ -1,69 +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.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));
}
}

View File

@@ -28,7 +28,7 @@ side = "BOTH"
[[dependencies.moonrise]]
modId = "minecraft"
type = "required"
versionRange = "(1.21.4,1.21.6)"
versionRange = "[1.21,1.21.2)"
ordering = "NONE"
side = "BOTH"
@@ -57,6 +57,7 @@ config = "moonrise-neoforge.mixins.json"
["lithium:options"]
"mixin.ai.poi" = false
"mixin.alloc.chunk_ticking" = false
"mixin.alloc.deep_passengers" = false
"mixin.alloc.entity_tracker" = false
"mixin.block.flatten_states" = false
@@ -80,5 +81,6 @@ config = "moonrise-neoforge.mixins.json"
"mixin.world.block_entity_ticking" = false
"mixin.world.chunk_access" = false
"mixin.world.explosions.block_raycast" = false
"mixin.world.explosions.cache_exposure" = false
"mixin.world.temperature_cache" = false
"mixin.world.tick_scheduler" = false

View File

@@ -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": [

View File

@@ -1,17 +0,0 @@
package ca.spottedleaf.moonrise.neoforge;
import org.junit.jupiter.api.Test;
import org.spongepowered.asm.mixin.MixinEnvironment;
class MixinAuditTest {
@Test
void auditMixins() {
final ClassLoader old = Thread.currentThread().getContextClassLoader();
try {
Thread.currentThread().setContextClassLoader(MixinAuditTest.class.getClassLoader());
MixinEnvironment.getCurrentEnvironment().audit();
} finally {
Thread.currentThread().setContextClassLoader(old);
}
}
}

View File

@@ -13,6 +13,7 @@ pluginManagement {
maven {
name = 'jmp'
url = 'https://repo.jpenilla.xyz/snapshots'
mavenContent { snapshotsOnly() }
}
maven {
name = 'architectury'
@@ -22,10 +23,9 @@ pluginManagement {
}
plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "0.9.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
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
id("xyz.jpenilla.quiet-architectury-loom") version "1.7.300" apply false
id 'com.gradleup.shadow' version '8.3.0' apply false
}
dependencyResolutionManagement {
@@ -37,7 +37,7 @@ dependencyResolutionManagement {
}
versionCatalogs {
create("fabricApiLibs") {
from("net.fabricmc.fabric-api:fabric-api-catalog:${fabric_api_version}")
from("net.fabricmc.fabric-api:fabric-api-catalog:0.107.0+1.21.1")
}
}
}

View File

@@ -1,30 +1,28 @@
package ca.spottedleaf.moonrise.common;
import ca.spottedleaf.moonrise.common.util.ChunkSystemHooks;
import com.mojang.datafixers.DSL;
import com.mojang.datafixers.DataFixer;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
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.world.entity.Entity;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Explosion;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.chunk.storage.SerializableChunkData;
import net.minecraft.world.level.entity.EntityTypeTest;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import java.util.List;
import java.util.ServiceLoader;
import java.util.function.Predicate;
public interface PlatformHooks extends ChunkSystemHooks {
public interface PlatformHooks {
public static PlatformHooks get() {
return Holder.INSTANCE;
}
@@ -35,6 +33,10 @@ public interface PlatformHooks extends ChunkSystemHooks {
public Predicate<BlockState> maybeHasLightEmission();
public void onExplosion(final Level world, final Explosion explosion, final List<Entity> possiblyAffecting, final double diameter);
public Vec3 modifyExplosionKnockback(final Level world, final Explosion explosion, final Entity entity, final Vec3 original);
public boolean hasCurrentlyLoadingChunk();
public LevelChunk getCurrentlyLoadingChunk(final GenerationChunkHolder holder);
@@ -45,11 +47,11 @@ public interface PlatformHooks extends ChunkSystemHooks {
public boolean allowAsyncTicketUpdates();
public void onChunkHolderTicketChange(final ServerLevel world, final ChunkHolder holder, final int oldLevel, final int newLevel);
public void onChunkHolderTicketChange(final ServerLevel world, final NewChunkHolder holder, final int oldLevel, final int newLevel);
public void chunkUnloadFromWorld(final LevelChunk chunk);
public void chunkSyncSave(final ServerLevel world, final ChunkAccess chunk, final SerializableChunkData data);
public void chunkSyncSave(final ServerLevel world, final ChunkAccess chunk, final CompoundTag data);
public void onChunkWatch(final ServerLevel world, final LevelChunk chunk, final ServerPlayer player);
@@ -64,6 +66,8 @@ public interface PlatformHooks extends ChunkSystemHooks {
public void entityMove(final Entity entity, final long oldSection, final long newSection);
public boolean screenEntity(final ServerLevel world, final Entity entity, final boolean fromDisk, final boolean event);
public boolean configFixMC224294();
public boolean configAutoConfigSendDistance();
@@ -78,30 +82,12 @@ public interface PlatformHooks extends ChunkSystemHooks {
public int configPlayerMaxConcurrentGens();
public long configAutoSaveInterval(final ServerLevel world);
public long configAutoSaveInterval();
public int configMaxAutoSavePerTick(final ServerLevel world);
public int configMaxAutoSavePerTick();
public boolean configFixMC159283();
// support for CB chunk mustNotSave
public boolean forceNoSave(final ChunkAccess chunk);
public CompoundTag convertNBT(final DSL.TypeReference type, final DataFixer dataFixer, final CompoundTag nbt,
final int fromVersion, final int toVersion);
public boolean hasMainChunkLoadHook();
public void mainChunkLoad(final ChunkAccess chunk, final SerializableChunkData chunkData);
public List<Entity> modifySavedEntities(final ServerLevel world, final int chunkX, final int chunkZ, final List<Entity> entities);
public void unloadEntity(final Entity entity);
public void postLoadProtoChunk(final ServerLevel world, final ProtoChunk chunk);
public int modifyEntityTrackingRange(final Entity entity, final int currentRange);
public static final class Holder {
private Holder() {
}

View File

@@ -2,7 +2,6 @@ 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;
@@ -22,34 +21,15 @@ public final class IteratorSafeOrderedReferenceSet<E> {
private int iteratorCount;
public IteratorSafeOrderedReferenceSet() {
this(Object.class);
}
public IteratorSafeOrderedReferenceSet(final Class<? super E> arrComponent) {
this(16, 0.75f, 16, 0.2, arrComponent);
this(16, 0.75f, 16, 0.2);
}
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[])Array.newInstance(arrComponent, arrayCapacity);
}
// includes null (gravestone) elements
public E[] getListRaw() {
return this.listElements;
}
// includes null (gravestone) elements
public int getListSize() {
return this.listSize;
this.listElements = (E[])new Object[arrayCapacity];
}
/*
@@ -101,7 +81,7 @@ public final class IteratorSafeOrderedReferenceSet<E> {
public int createRawIterator() {
++this.iteratorCount;
if (this.indexMap.isEmpty()) {
return Integer.MAX_VALUE;
return -1;
} else {
return this.firstInvalidIndex == 0 ? this.indexMap.getInt(this.indexMap.firstKey()) : 0;
}
@@ -116,7 +96,7 @@ public final class IteratorSafeOrderedReferenceSet<E> {
}
}
return Integer.MAX_VALUE;
return -1;
}
public void finishRawIterator() {
@@ -225,6 +205,10 @@ 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();

View File

@@ -1,9 +1,9 @@
package ca.spottedleaf.moonrise.common.misc;
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.MoonriseConstants;
import ca.spottedleaf.moonrise.common.util.ChunkSystem;
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel;
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkData;
import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickConstants;
@@ -121,8 +121,8 @@ public final class NearbyPlayers {
players[NearbyMapType.GENERAL.ordinal()].update(chunk.x, chunk.z, GENERAL_AREA_VIEW_DISTANCE);
players[NearbyMapType.GENERAL_SMALL.ordinal()].update(chunk.x, chunk.z, GENERAL_SMALL_VIEW_DISTANCE);
players[NearbyMapType.GENERAL_REALLY_SMALL.ordinal()].update(chunk.x, chunk.z, GENERAL_REALLY_SMALL_VIEW_DISTANCE);
players[NearbyMapType.TICK_VIEW_DISTANCE.ordinal()].update(chunk.x, chunk.z, PlatformHooks.get().getTickViewDistance(player));
players[NearbyMapType.VIEW_DISTANCE.ordinal()].update(chunk.x, chunk.z, PlatformHooks.get().getViewDistance(player));
players[NearbyMapType.TICK_VIEW_DISTANCE.ordinal()].update(chunk.x, chunk.z, ChunkSystem.getTickViewDistance(player));
players[NearbyMapType.VIEW_DISTANCE.ordinal()].update(chunk.x, chunk.z, ChunkSystem.getViewDistance(player));
players[NearbyMapType.SPAWN_RANGE.ordinal()].update(chunk.x, chunk.z, ChunkTickConstants.PLAYER_SPAWN_TRACK_RANGE); // Moonrise - chunk tick iteration
}

View File

@@ -1,8 +1,7 @@
package ca.spottedleaf.moonrise.common.misc;
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
import ca.spottedleaf.concurrentutil.util.IntPairUtil;
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
import it.unimi.dsi.fastutil.longs.LongSet;
import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap;
import it.unimi.dsi.fastutil.objects.ReferenceSet;
@@ -15,24 +14,16 @@ public final class PositionCountingAreaMap<T> {
return this.counters.keySet();
}
public LongSet getPositions() {
return this.positions.keySet();
}
public int getTotalPositions() {
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(CoordinateUtils.getChunkKey(toX, toZ));
return this.positions.containsKey(IntPairUtil.key(toX, toZ));
}
public int getObjectsNear(final int toX, final int toZ) {
return this.positions.get(CoordinateUtils.getChunkKey(toX, toZ));
return this.positions.get(IntPairUtil.key(toX, toZ));
}
public boolean add(final T parameter, final int toX, final int toZ, final int distance) {
@@ -89,12 +80,12 @@ public final class PositionCountingAreaMap<T> {
@Override
protected void addCallback(final T parameter, final int toX, final int toZ) {
PositionCountingAreaMap.this.positions.addTo(CoordinateUtils.getChunkKey(toX, toZ), 1);
PositionCountingAreaMap.this.positions.addTo(IntPairUtil.key(toX, toZ), 1);
}
@Override
protected void removeCallback(final T parameter, final int toX, final int toZ) {
final long key = CoordinateUtils.getChunkKey(toX, toZ);
final long key = IntPairUtil.key(toX, toZ);
if (PositionCountingAreaMap.this.positions.addTo(key, -1) == 1) {
PositionCountingAreaMap.this.positions.remove(key);
}

View File

@@ -1,5 +1,7 @@
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;
@@ -97,8 +99,8 @@ public abstract class SingleUserAreaMap<T> {
final int dx = toX - fromX;
final int dz = toZ - fromZ;
final int totalX = Math.abs(fromX - toX);
final int totalZ = Math.abs(fromZ - toZ);
final int totalX = IntegerUtil.branchlessAbs(fromX - toX);
final int totalZ = IntegerUtil.branchlessAbs(fromZ - toZ);
if (Math.max(totalX, totalZ) > (2 * Math.max(newViewDistance, oldViewDistance))) {
// teleported
@@ -118,7 +120,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(Math.abs(currX - toX), Math.abs(currZ - toZ)) > newViewDistance) {
if (Math.max(IntegerUtil.branchlessAbs(currX - toX), IntegerUtil.branchlessAbs(currZ - toZ)) > newViewDistance) {
this.removeCallback(parameter, currX, currZ);
}
}
@@ -134,7 +136,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(Math.abs(currX - fromX), Math.abs(currZ - fromZ)) > oldViewDistance) {
if (Math.max(IntegerUtil.branchlessAbs(currX - fromX), IntegerUtil.branchlessAbs(currZ - fromZ)) > oldViewDistance) {
this.addCallback(parameter, currX, currZ);
}
}

View File

@@ -1,176 +0,0 @@
package ca.spottedleaf.moonrise.common.util;
import ca.spottedleaf.concurrentutil.util.Priority;
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk;
import ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader;
import ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemServerChunkCache;
import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickServerLevel;
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.progress.ChunkProgressListener;
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;
public abstract class BaseChunkSystemHooks implements ChunkSystemHooks {
@Override
public void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run) {
this.scheduleChunkTask(level, chunkX, chunkZ, run, Priority.NORMAL);
}
@Override
public void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run, final Priority priority) {
((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().scheduleChunkTask(chunkX, chunkZ, run, priority);
}
@Override
public void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final boolean gen,
final ChunkStatus toStatus, final boolean addTicket, final Priority priority,
final Consumer<ChunkAccess> onComplete) {
((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().scheduleChunkLoad(chunkX, chunkZ, gen, toStatus, addTicket, priority, onComplete);
}
@Override
public void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final ChunkStatus toStatus,
final boolean addTicket, final Priority priority, final Consumer<ChunkAccess> onComplete) {
((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().scheduleChunkLoad(chunkX, chunkZ, toStatus, addTicket, priority, onComplete);
}
@Override
public void scheduleTickingState(final ServerLevel level, final int chunkX, final int chunkZ,
final FullChunkStatus toStatus, final boolean addTicket,
final Priority priority, final Consumer<LevelChunk> onComplete) {
((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().scheduleTickingState(chunkX, chunkZ, toStatus, addTicket, priority, onComplete);
}
@Override
public List<ChunkHolder> getVisibleChunkHolders(final ServerLevel level) {
return ((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().chunkHolderManager.getOldChunkHolders();
}
@Override
public List<ChunkHolder> getUpdatingChunkHolders(final ServerLevel level) {
return ((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().chunkHolderManager.getOldChunkHolders();
}
@Override
public int getVisibleChunkHolderCount(final ServerLevel level) {
return ((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().chunkHolderManager.size();
}
@Override
public int getUpdatingChunkHolderCount(final ServerLevel level) {
return ((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().chunkHolderManager.size();
}
@Override
public boolean hasAnyChunkHolders(final ServerLevel level) {
return this.getUpdatingChunkHolderCount(level) != 0;
}
@Override
public void onChunkHolderCreate(final ServerLevel level, final ChunkHolder holder) {
}
@Override
public void onChunkHolderDelete(final ServerLevel level, final ChunkHolder holder) {
// Update progress listener for LevelLoadingScreen
final ChunkProgressListener progressListener = level.getChunkSource().chunkMap.progressListener;
if (progressListener != null) {
this.scheduleChunkTask(level, holder.getPos().x, holder.getPos().z, () -> {
progressListener.onStatusChange(holder.getPos(), null);
});
}
}
@Override
public void onChunkPreBorder(final LevelChunk chunk, final ChunkHolder holder) {
((ChunkSystemServerChunkCache)((ServerLevel)chunk.getLevel()).getChunkSource())
.moonrise$setFullChunk(chunk.getPos().x, chunk.getPos().z, chunk);
}
@Override
public void onChunkBorder(final LevelChunk chunk, final ChunkHolder holder) {
((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(chunk);
}
@Override
public void onChunkPostNotBorder(final LevelChunk chunk, final ChunkHolder holder) {
((ChunkSystemServerChunkCache)((ServerLevel)chunk.getLevel()).getChunkSource())
.moonrise$setFullChunk(chunk.getPos().x, chunk.getPos().z, null);
}
@Override
public void onChunkTicking(final LevelChunk chunk, final ChunkHolder holder) {
((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();
}
@Override
public void onChunkNotTicking(final LevelChunk chunk, final ChunkHolder holder) {
((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(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(chunk);
((ChunkTickServerLevel)(ServerLevel)chunk.getLevel()).moonrise$removeChunkForPlayerTicking(chunk); // Moonrise - chunk tick iteration
}
@Override
public ChunkHolder getUnloadingChunkHolder(final ServerLevel level, final int chunkX, final int chunkZ) {
return null;
}
@Override
public int getSendViewDistance(final ServerPlayer player) {
return RegionizedPlayerChunkLoader.getAPISendViewDistance(player);
}
@Override
public int getViewDistance(final ServerPlayer player) {
return RegionizedPlayerChunkLoader.getAPIViewDistance(player);
}
@Override
public int getTickViewDistance(final ServerPlayer player) {
return RegionizedPlayerChunkLoader.getAPITickViewDistance(player);
}
@Override
public void addPlayerToDistanceMaps(final ServerLevel world, final ServerPlayer player) {
((ChunkSystemServerLevel)world).moonrise$getPlayerChunkLoader().addPlayer(player);
}
@Override
public void removePlayerFromDistanceMaps(final ServerLevel world, final ServerPlayer player) {
((ChunkSystemServerLevel)world).moonrise$getPlayerChunkLoader().removePlayer(player);
}
@Override
public void updateMaps(final ServerLevel world, final ServerPlayer player) {
((ChunkSystemServerLevel)world).moonrise$getPlayerChunkLoader().updatePlayer(player);
}
}

View File

@@ -0,0 +1,176 @@
package ca.spottedleaf.moonrise.common.util;
import ca.spottedleaf.concurrentutil.util.Priority;
import ca.spottedleaf.moonrise.common.PlatformHooks;
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk;
import ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader;
import ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemServerChunkCache;
import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickServerLevel;
import com.mojang.logging.LogUtils;
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.progress.ChunkProgressListener;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import org.slf4j.Logger;
import java.util.List;
import java.util.function.Consumer;
public final class ChunkSystem {
private static final Logger LOGGER = LogUtils.getLogger();
public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run) {
scheduleChunkTask(level, chunkX, chunkZ, run, Priority.NORMAL);
}
public static void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run, final Priority priority) {
((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().scheduleChunkTask(chunkX, chunkZ, run, priority);
}
public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final boolean gen,
final ChunkStatus toStatus, final boolean addTicket, final Priority priority,
final Consumer<ChunkAccess> onComplete) {
((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().scheduleChunkLoad(chunkX, chunkZ, gen, toStatus, addTicket, priority, onComplete);
}
public static void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final ChunkStatus toStatus,
final boolean addTicket, final Priority priority, final Consumer<ChunkAccess> onComplete) {
((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().scheduleChunkLoad(chunkX, chunkZ, toStatus, addTicket, priority, onComplete);
}
public static void scheduleTickingState(final ServerLevel level, final int chunkX, final int chunkZ,
final FullChunkStatus toStatus, final boolean addTicket,
final Priority priority, final Consumer<LevelChunk> onComplete) {
((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().scheduleTickingState(chunkX, chunkZ, toStatus, addTicket, priority, onComplete);
}
public static List<ChunkHolder> getVisibleChunkHolders(final ServerLevel level) {
return ((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().chunkHolderManager.getOldChunkHolders();
}
public static List<ChunkHolder> getUpdatingChunkHolders(final ServerLevel level) {
return ((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().chunkHolderManager.getOldChunkHolders();
}
public static int getVisibleChunkHolderCount(final ServerLevel level) {
return ((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().chunkHolderManager.size();
}
public static int getUpdatingChunkHolderCount(final ServerLevel level) {
return ((ChunkSystemServerLevel)level).moonrise$getChunkTaskScheduler().chunkHolderManager.size();
}
public static boolean hasAnyChunkHolders(final ServerLevel level) {
return getUpdatingChunkHolderCount(level) != 0;
}
public static boolean screenEntity(final ServerLevel level, final Entity entity, final boolean fromDisk, final boolean event) {
if (!PlatformHooks.get().screenEntity(level, entity, fromDisk, event)) {
return false;
}
return true;
}
public static void onChunkHolderCreate(final ServerLevel level, final ChunkHolder holder) {
}
public static void onChunkHolderDelete(final ServerLevel level, final ChunkHolder holder) {
// Update progress listener for LevelLoadingScreen
final ChunkProgressListener progressListener = level.getChunkSource().chunkMap.progressListener;
if (progressListener != null) {
ChunkSystem.scheduleChunkTask(level, holder.getPos().x, holder.getPos().z, () -> {
progressListener.onStatusChange(holder.getPos(), null);
});
}
}
public static void onChunkPreBorder(final LevelChunk chunk, final ChunkHolder holder) {
((ChunkSystemServerChunkCache)((ServerLevel)chunk.getLevel()).getChunkSource())
.moonrise$setFullChunk(chunk.getPos().x, chunk.getPos().z, chunk);
}
public static void onChunkBorder(final LevelChunk chunk, final ChunkHolder holder) {
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getLoadedChunks().add(
((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder()
);
}
public static void onChunkNotBorder(final LevelChunk chunk, final ChunkHolder holder) {
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getLoadedChunks().remove(
((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder()
);
}
public static void onChunkPostNotBorder(final LevelChunk chunk, final ChunkHolder holder) {
((ChunkSystemServerChunkCache)((ServerLevel)chunk.getLevel()).getChunkSource())
.moonrise$setFullChunk(chunk.getPos().x, chunk.getPos().z, null);
}
public static void onChunkTicking(final LevelChunk chunk, final ChunkHolder holder) {
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getTickingChunks().add(
((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder()
);
if (!((ChunkSystemLevelChunk)chunk).moonrise$isPostProcessingDone()) {
chunk.postProcessGeneration();
}
((ServerLevel)chunk.getLevel()).startTickingChunk(chunk);
((ServerLevel)chunk.getLevel()).getChunkSource().chunkMap.tickingGenerated.incrementAndGet();
((ChunkTickServerLevel)(ServerLevel)chunk.getLevel()).moonrise$markChunkForPlayerTicking(chunk); // Moonrise - chunk tick iteration
}
public static 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
}
public static void onChunkEntityTicking(final LevelChunk chunk, final ChunkHolder holder) {
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getEntityTickingChunks().add(
((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder()
);
}
public static void onChunkNotEntityTicking(final LevelChunk chunk, final ChunkHolder holder) {
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getEntityTickingChunks().remove(
((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder()
);
}
public static ChunkHolder getUnloadingChunkHolder(final ServerLevel level, final int chunkX, final int chunkZ) {
return null;
}
public static int getSendViewDistance(final ServerPlayer player) {
return RegionizedPlayerChunkLoader.getAPISendViewDistance(player);
}
public static int getViewDistance(final ServerPlayer player) {
return RegionizedPlayerChunkLoader.getAPIViewDistance(player);
}
public static int getTickViewDistance(final ServerPlayer player) {
return RegionizedPlayerChunkLoader.getAPITickViewDistance(player);
}
public static void addPlayerToDistanceMaps(final ServerLevel world, final ServerPlayer player) {
((ChunkSystemServerLevel)world).moonrise$getPlayerChunkLoader().addPlayer(player);
}
public static void removePlayerFromDistanceMaps(final ServerLevel world, final ServerPlayer player) {
((ChunkSystemServerLevel)world).moonrise$getPlayerChunkLoader().removePlayer(player);
}
public static void updateMaps(final ServerLevel world, final ServerPlayer player) {
((ChunkSystemServerLevel)world).moonrise$getPlayerChunkLoader().updatePlayer(player);
}
private ChunkSystem() {}
}

View File

@@ -1,80 +0,0 @@
package ca.spottedleaf.moonrise.common.util;
import ca.spottedleaf.concurrentutil.util.Priority;
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;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import java.util.List;
import java.util.function.Consumer;
public interface ChunkSystemHooks {
public void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run);
public void scheduleChunkTask(final ServerLevel level, final int chunkX, final int chunkZ, final Runnable run, final Priority priority);
public void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final boolean gen,
final ChunkStatus toStatus, final boolean addTicket, final Priority priority,
final Consumer<ChunkAccess> onComplete);
public void scheduleChunkLoad(final ServerLevel level, final int chunkX, final int chunkZ, final ChunkStatus toStatus,
final boolean addTicket, final Priority priority, final Consumer<ChunkAccess> onComplete);
public void scheduleTickingState(final ServerLevel level, final int chunkX, final int chunkZ,
final FullChunkStatus toStatus, final boolean addTicket,
final Priority priority, final Consumer<LevelChunk> onComplete);
public List<ChunkHolder> getVisibleChunkHolders(final ServerLevel level);
public List<ChunkHolder> getUpdatingChunkHolders(final ServerLevel level);
public int getVisibleChunkHolderCount(final ServerLevel level);
public int getUpdatingChunkHolderCount(final ServerLevel level);
public boolean hasAnyChunkHolders(final ServerLevel level);
public boolean screenEntity(final ServerLevel level, final Entity entity, final boolean fromDisk, final boolean event);
public void onChunkHolderCreate(final ServerLevel level, final ChunkHolder holder);
public void onChunkHolderDelete(final ServerLevel level, final ChunkHolder holder);
public void onChunkPreBorder(final LevelChunk chunk, final ChunkHolder holder);
public void onChunkBorder(final LevelChunk chunk, final ChunkHolder holder);
public void onChunkNotBorder(final LevelChunk chunk, final ChunkHolder holder);
public void onChunkPostNotBorder(final LevelChunk chunk, final ChunkHolder holder);
public void onChunkTicking(final LevelChunk chunk, final ChunkHolder holder);
public void onChunkNotTicking(final LevelChunk chunk, final ChunkHolder holder);
public void onChunkEntityTicking(final LevelChunk chunk, final ChunkHolder holder);
public void onChunkNotEntityTicking(final LevelChunk chunk, final ChunkHolder holder);
public ChunkHolder getUnloadingChunkHolder(final ServerLevel level, final int chunkX, final int chunkZ);
public int getSendViewDistance(final ServerPlayer player);
public int getViewDistance(final ServerPlayer player);
public int getTickViewDistance(final ServerPlayer player);
public void addPlayerToDistanceMaps(final ServerLevel world, final ServerPlayer player);
public void removePlayerFromDistanceMaps(final ServerLevel world, final ServerPlayer player);
public void updateMaps(final ServerLevel world, final ServerPlayer player);
public long[] getCounterTypesUncached(final TicketType type);
}

View File

@@ -1,6 +1,5 @@
package ca.spottedleaf.moonrise.common.util;
import ca.spottedleaf.moonrise.common.PlatformHooks;
import ca.spottedleaf.moonrise.common.config.moonrise.MoonriseConfig;
import ca.spottedleaf.yamlconfig.adapter.TypeAdapterRegistry;
import ca.spottedleaf.yamlconfig.config.YamlConfig;
@@ -12,7 +11,7 @@ public final class ConfigHolder {
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigHolder.class);
private static final File CONFIG_FILE = new File(System.getProperty(PlatformHooks.get().getBrand() + ".ConfigFile", "config/moonrise.yml"));
private static final File CONFIG_FILE = new File(System.getProperty("Moonrise.ConfigFile", "config/moonrise.yml"));
private static final TypeAdapterRegistry CONFIG_ADAPTERS = new TypeAdapterRegistry();
private static final YamlConfig<MoonriseConfig> CONFIG;
static {
@@ -22,7 +21,7 @@ public final class ConfigHolder {
throw new RuntimeException(ex);
}
}
private static final String CONFIG_HEADER = String.format("""
private static final String CONFIG_HEADER = """
This is the configuration file for Moonrise.
Each configuration option is prefixed with a comment to explain what it does. Additional changes to this file
@@ -30,10 +29,10 @@ public final class ConfigHolder {
Below are the Moonrise startup flags. Note that startup flags must be placed in the JVM arguments, not
program arguments.
-D%1$s.ConfigFile=<file> - Override the config file location. Might be useful for multiple game versions.
-D%1$s.WorkerThreadCount=<number> - Override the auto configured worker thread counts (worker-threads).
-D%1$s.MaxViewDistance=<number> - Overrides the maximum view distance, should only use for debugging purposes.
""", PlatformHooks.get().getBrand());
-DMoonrise.ConfigFile=<file> - Override the config file location. Might be useful for multiple game versions.
-DMoonrise.WorkerThreadCount=<number> - Override the auto configured worker thread counts (worker-threads).
-DMoonrise.MaxViewDistance=<number> - Overrides the maximum view distance, should only use for debugging purposes.
""";
static {
reloadConfig();

View File

@@ -1,44 +0,0 @@
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() {}
}

View File

@@ -1,7 +1,6 @@
package ca.spottedleaf.moonrise.common.util;
import com.google.gson.JsonElement;
import com.google.gson.Strictness;
import com.google.gson.internal.Streams;
import com.google.gson.stream.JsonWriter;
import java.io.File;
@@ -17,7 +16,7 @@ public final class JsonUtil {
final StringWriter stringWriter = new StringWriter();
final JsonWriter jsonWriter = new JsonWriter(stringWriter);
jsonWriter.setIndent(" ");
jsonWriter.setStrictness(Strictness.LENIENT);
jsonWriter.setLenient(false);
Streams.write(element, jsonWriter);
final String jsonString = stringWriter.toString();

View File

@@ -3,12 +3,8 @@ package ca.spottedleaf.moonrise.common.util;
public final class MixinWorkarounds {
// mixins tries to find the owner of the clone() method, which doesn't exist and NPEs
// https://github.com/FabricMC/Mixin/pull/147
public static long[] clone(final long[] values) {
return values.clone();
}
public static byte[] clone(final byte[] values) {
return values.clone();
}
}

View File

@@ -19,7 +19,7 @@ public final class MoonriseCommon {
@Override
public void accept(Thread thread) {
thread.setDaemon(true);
thread.setName(PlatformHooks.get().getBrand() + " Common Worker #" + this.idGenerator.getAndIncrement());
thread.setName("Moonrise Common Worker #" + this.idGenerator.getAndIncrement());
thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
@Override
public void uncaughtException(final Thread thread, final Throwable throwable) {
@@ -44,7 +44,7 @@ public final class MoonriseCommon {
} else {
defaultWorkerThreads = defaultWorkerThreads / 2;
}
defaultWorkerThreads = Integer.getInteger(PlatformHooks.get().getBrand() + ".WorkerThreadCount", Integer.valueOf(defaultWorkerThreads));
defaultWorkerThreads = Integer.getInteger("Moonrise.WorkerThreadCount", Integer.valueOf(defaultWorkerThreads));
int workerThreads = configWorkerThreads;

View File

@@ -1,10 +1,8 @@
package ca.spottedleaf.moonrise.common.util;
import ca.spottedleaf.moonrise.common.PlatformHooks;
public final class MoonriseConstants {
public static final int MAX_VIEW_DISTANCE = Integer.getInteger(PlatformHooks.get().getBrand() + ".MaxViewDistance", 32);
public static final int MAX_VIEW_DISTANCE = Integer.getInteger("Moonrise.MaxViewDistance", 32);
private MoonriseConstants() {}

View File

@@ -0,0 +1,53 @@
package ca.spottedleaf.moonrise.common.util;
import net.minecraft.world.level.levelgen.LegacyRandomSource;
/**
* Avoid costly CAS of superclass
*/
public final class SimpleRandom extends LegacyRandomSource {
private static final long MULTIPLIER = 25214903917L;
private static final long ADDEND = 11L;
private static final int BITS = 48;
private static final long MASK = (1L << BITS) - 1;
private long value;
public SimpleRandom(final long seed) {
super(0L);
this.value = seed;
}
@Override
public void setSeed(final long seed) {
this.value = (seed ^ MULTIPLIER) & MASK;
}
private long advanceSeed() {
return this.value = ((this.value * MULTIPLIER) + ADDEND) & MASK;
}
@Override
public int next(final int bits) {
return (int)(this.advanceSeed() >>> (BITS - bits));
}
@Override
public int nextInt() {
final long seed = this.advanceSeed();
return (int)(seed >>> (BITS - Integer.SIZE));
}
@Override
public int nextInt(final int bound) {
if (bound <= 0) {
throw new IllegalArgumentException();
}
// https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
final long value = this.advanceSeed() >>> (BITS - Integer.SIZE);
return (int)((value * (long)bound) >>> Integer.SIZE);
}
}

View File

@@ -1,105 +0,0 @@
package ca.spottedleaf.moonrise.common.util;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.levelgen.BitRandomSource;
import net.minecraft.world.level.levelgen.MarsagliaPolarGaussian;
import net.minecraft.world.level.levelgen.PositionalRandomFactory;
/**
* Avoid costly CAS of superclass + division in nextInt
*/
public final class SimpleThreadUnsafeRandom implements BitRandomSource {
private static final long MULTIPLIER = 25214903917L;
private static final long ADDEND = 11L;
private static final int BITS = 48;
private static final long MASK = (1L << BITS) - 1L;
private long value;
private final MarsagliaPolarGaussian gaussianSource = new MarsagliaPolarGaussian(this);
public SimpleThreadUnsafeRandom(final long seed) {
this.setSeed(seed);
}
@Override
public void setSeed(final long seed) {
this.value = (seed ^ MULTIPLIER) & MASK;
this.gaussianSource.reset();
}
private long advanceSeed() {
return this.value = ((this.value * MULTIPLIER) + ADDEND) & MASK;
}
@Override
public int next(final int bits) {
return (int)(this.advanceSeed() >>> (BITS - bits));
}
@Override
public int nextInt() {
final long seed = this.advanceSeed();
return (int)(seed >>> (BITS - Integer.SIZE));
}
@Override
public int nextInt(final int bound) {
if (bound <= 0) {
throw new IllegalArgumentException();
}
// https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/
final long value = this.advanceSeed() >>> (BITS - Integer.SIZE);
return (int)((value * (long)bound) >>> Integer.SIZE);
}
@Override
public double nextGaussian() {
return this.gaussianSource.nextGaussian();
}
@Override
public RandomSource fork() {
return new SimpleThreadUnsafeRandom(this.nextLong());
}
@Override
public PositionalRandomFactory forkPositional() {
return new SimpleRandomPositionalFactory(this.nextLong());
}
public static final class SimpleRandomPositionalFactory implements PositionalRandomFactory {
private final long seed;
public SimpleRandomPositionalFactory(final long seed) {
this.seed = seed;
}
public long getSeed() {
return this.seed;
}
@Override
public RandomSource fromHashOf(final String string) {
return new SimpleThreadUnsafeRandom((long)string.hashCode() ^ this.seed);
}
@Override
public RandomSource fromSeed(final long seed) {
return new SimpleThreadUnsafeRandom(seed);
}
@Override
public RandomSource at(final int x, final int y, final int z) {
return new SimpleThreadUnsafeRandom(Mth.getSeed(x, y, z) ^ this.seed);
}
@Override
public void parityConfigString(final StringBuilder stringBuilder) {
stringBuilder.append("SimpleRandomPositionalFactory{").append(this.seed).append('}');
}
}
}

View File

@@ -1,94 +0,0 @@
package ca.spottedleaf.moonrise.common.util;
import net.minecraft.util.Mth;
import net.minecraft.util.RandomSource;
import net.minecraft.world.level.levelgen.BitRandomSource;
import net.minecraft.world.level.levelgen.MarsagliaPolarGaussian;
import net.minecraft.world.level.levelgen.PositionalRandomFactory;
/**
* Avoid costly CAS of superclass
*/
public final class ThreadUnsafeRandom implements BitRandomSource {
private static final long MULTIPLIER = 25214903917L;
private static final long ADDEND = 11L;
private static final int BITS = 48;
private static final long MASK = (1L << BITS) - 1L;
private long value;
private final MarsagliaPolarGaussian gaussianSource = new MarsagliaPolarGaussian(this);
public ThreadUnsafeRandom(final long seed) {
this.setSeed(seed);
}
@Override
public void setSeed(final long seed) {
this.value = (seed ^ MULTIPLIER) & MASK;
this.gaussianSource.reset();
}
private long advanceSeed() {
return this.value = ((this.value * MULTIPLIER) + ADDEND) & MASK;
}
@Override
public int next(final int bits) {
return (int)(this.advanceSeed() >>> (BITS - bits));
}
@Override
public int nextInt() {
final long seed = this.advanceSeed();
return (int)(seed >>> (BITS - Integer.SIZE));
}
@Override
public double nextGaussian() {
return this.gaussianSource.nextGaussian();
}
@Override
public RandomSource fork() {
return new ThreadUnsafeRandom(this.nextLong());
}
@Override
public PositionalRandomFactory forkPositional() {
return new ThreadUnsafeRandomPositionalFactory(this.nextLong());
}
public static final class ThreadUnsafeRandomPositionalFactory implements PositionalRandomFactory {
private final long seed;
public ThreadUnsafeRandomPositionalFactory(final long seed) {
this.seed = seed;
}
public long getSeed() {
return this.seed;
}
@Override
public RandomSource fromHashOf(final String string) {
return new ThreadUnsafeRandom((long)string.hashCode() ^ this.seed);
}
@Override
public RandomSource fromSeed(final long seed) {
return new ThreadUnsafeRandom(seed);
}
@Override
public RandomSource at(final int x, final int y, final int z) {
return new ThreadUnsafeRandom(Mth.getSeed(x, y, z) ^ this.seed);
}
@Override
public void parityConfigString(final StringBuilder stringBuilder) {
stringBuilder.append("ThreadUnsafeRandomPositionalFactory{").append(this.seed).append('}');
}
}
}

View File

@@ -15,81 +15,56 @@ 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 failed main thread check: " + reason + ", context=" + getThreadContext(), new Throwable());
LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, 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 failed main thread check: " +
reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + pos;
LOGGER.error(ex, new Throwable());
throw new IllegalStateException(ex);
}
}
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 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);
LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable());
throw new IllegalStateException(reason);
}
}
public static void ensureTickThread(final Level world, final ChunkPos pos, final String reason) {
if (!isTickThreadFor(world, 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);
LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable());
throw new IllegalStateException(reason);
}
}
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 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);
LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable());
throw new IllegalStateException(reason);
}
}
public static void ensureTickThread(final Entity entity, final String reason) {
if (!isTickThreadFor(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);
LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable());
throw new IllegalStateException(reason);
}
}
public static void ensureTickThread(final Level world, final AABB aabb, final String reason) {
if (!isTickThreadFor(world, 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);
LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable());
throw new IllegalStateException(reason);
}
}
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 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);
LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable());
throw new IllegalStateException(reason);
}
}
@@ -130,10 +105,6 @@ public class TickThread extends Thread {
return isTickThread();
}
public static boolean isTickThreadFor(final Level world, final BlockPos pos, final int blockRadius) {
return isTickThread();
}
public static boolean isTickThreadFor(final Level world, final ChunkPos pos) {
return isTickThread();
}

View File

@@ -8,19 +8,19 @@ public final class WorldUtil {
// min, max are inclusive
public static int getMaxSection(final LevelHeightAccessor world) {
return world.getMaxSectionY();
return world.getMaxSection() - 1; // getMaxSection() is exclusive
}
public static int getMaxSection(final Level world) {
return world.getMaxSectionY();
return world.getMaxSection() - 1; // getMaxSection() is exclusive
}
public static int getMinSection(final LevelHeightAccessor world) {
return world.getMinSectionY();
return world.getMinSection();
}
public static int getMinSection(final Level world) {
return world.getMinSectionY();
return world.getMinSection();
}
public static int getMaxLightSection(final LevelHeightAccessor world) {

View File

@@ -154,9 +154,9 @@ abstract class LevelChunkSectionMixin implements BlockCountingChunkSection {
if (this.maybeHas((final BlockState state) -> !state.isAir())) {
final PalettedContainer.Data<BlockState> data = this.states.data;
final Palette<BlockState> palette = data.palette();
final Palette<BlockState> palette = data.palette;
final int paletteSize = palette.getSize();
final BitStorage storage = data.storage();
final BitStorage storage = data.storage;
final Int2ObjectOpenHashMap<ShortArrayList> counts;
if (paletteSize == 1) {

View File

@@ -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();
}

View File

@@ -6,7 +6,6 @@ import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
import net.minecraft.world.level.block.state.properties.BooleanProperty;
import net.minecraft.world.level.block.state.properties.Property;
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.Constant;
import org.spongepowered.asm.mixin.injection.Inject;
@@ -18,9 +17,6 @@ abstract class BooleanPropertyMixin extends Property<Boolean> implements Propert
super(string, class_);
}
@Unique
private static final Boolean[] BY_ID = new Boolean[]{ Boolean.FALSE, Boolean.TRUE };
@Override
public final int moonrise$getIdFor(final Boolean value) {
return value.booleanValue() ? 1 : 0;
@@ -37,6 +33,23 @@ abstract class BooleanPropertyMixin extends Property<Boolean> implements Propert
)
)
private void init(final CallbackInfo ci) {
this.moonrise$setById(BY_ID);
this.moonrise$setById(new Boolean[]{ Boolean.FALSE, Boolean.TRUE });
}
/**
* This skips all ops after the identity comparison in the original code.
*
* @reason Properties are identity comparable
* @author Spottedleaf
*/
@WrapOperation(
method = "equals",
constant = @Constant(
classValue = BooleanProperty.class,
ordinal = 0
)
)
private boolean skipFurtherComparison(final Object obj, final Operation<Boolean> orig) {
return false;
}
}

View File

@@ -18,6 +18,9 @@ import java.util.Collection;
@Mixin(EnumProperty.class)
abstract class EnumPropertyMixin<T extends Enum<T> & StringRepresentable> extends Property<T> implements PropertyAccess<T> {
@Shadow
public abstract Collection<T> getPossibleValues();
@Unique
private int[] idLookupTable;

View File

@@ -83,6 +83,7 @@ abstract class StateHolderMixin<O, S> implements PropertyAccessStateHolder {
}
// remove values arrays
this.values = null;
for (final Map.Entry<Map<Property<?>, Comparable<?>>, S> entry : map.entrySet()) {
final S value = entry.getValue();
((StateHolderMixin<O, S>)(Object)(StateHolder<O, S>)value).values = null;
@@ -125,8 +126,8 @@ abstract class StateHolderMixin<O, S> implements PropertyAccessStateHolder {
* @author Spottedleaf
*/
@Overwrite
public <T extends Comparable<T>> T getNullableValue(final Property<T> property) {
return property == null ? null : this.optimisedTable.get(this.tableIndex, property);
public <T extends Comparable<T>> Optional<T> getOptionalValue(final Property<T> property) {
return property == null ? Optional.empty() : Optional.ofNullable(this.optimisedTable.get(this.tableIndex, property));
}
/**
@@ -166,7 +167,7 @@ abstract class StateHolderMixin<O, S> implements PropertyAccessStateHolder {
*/
@Overwrite
public Map<Property<?>, Comparable<?>> getValues() {
final ZeroCollidingReferenceStateTable<O, S> table = this.optimisedTable;
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;
}

View File

@@ -66,6 +66,9 @@ abstract class ChunkHolderMixin extends GenerationChunkHolder implements ChunkSy
@Unique
private final ReferenceList<ServerPlayer> playersSentChunkTo = new ReferenceList<>(EMPTY_PLAYER_ARRAY);
@Unique
private boolean isMarkedDirtyForPlayers;
@Unique
private ChunkMap getChunkMap() {
return (ChunkMap)this.playerProvider;
@@ -120,6 +123,16 @@ abstract class ChunkHolderMixin extends GenerationChunkHolder implements ChunkSy
return ret;
}
@Override
public final boolean moonrise$isMarkedDirtyForPlayers() {
return this.isMarkedDirtyForPlayers;
}
@Override
public final void moonrise$markDirtyForPlayers(final boolean value) {
this.isMarkedDirtyForPlayers = value;
}
@Unique
private static final ServerPlayer[] EMPTY_PLAYER_ARRAY = new ServerPlayer[0];
@@ -287,7 +300,14 @@ abstract class ChunkHolderMixin extends GenerationChunkHolder implements ChunkSy
// no players to sent to, so don't need to update anything
return null;
}
return this.getChunkToSend();
final LevelChunk ret = this.getChunkToSend();
if (ret != null) {
((ChunkSystemServerLevel)this.getChunkMap().level).moonrise$addUnsyncedChunk((ChunkHolder)(Object)this);
return ret;
}
return ret;
}
/**
@@ -306,7 +326,14 @@ abstract class ChunkHolderMixin extends GenerationChunkHolder implements ChunkSy
// no players to sent to, so don't need to update anything
return null;
}
return this.getChunkToSend();
final LevelChunk ret = this.getChunkToSend();
if (ret != null) {
((ChunkSystemServerLevel)this.getChunkMap().level).moonrise$addUnsyncedChunk((ChunkHolder)(Object)this);
return ret;
}
return ret;
}
/**
@@ -366,7 +393,7 @@ abstract class ChunkHolderMixin extends GenerationChunkHolder implements ChunkSy
/**
* @reason Use ticket system to control ticket levels
* @author Spottedleaf
* @see net.minecraft.server.level.ServerChunkCache#addTicketWithRadius(TicketType, ChunkPos, int)
* @see net.minecraft.server.level.ServerChunkCache#addRegionTicket(TicketType, ChunkPos, int, Object)
*/
@Overwrite
public void setTicketLevel(int i) {
@@ -397,14 +424,8 @@ abstract class ChunkHolderMixin extends GenerationChunkHolder implements ChunkSy
* @reason Chunk system hooks for ticket level updating now in {@link NewChunkHolder#processTicketLevelUpdate(List, List)}
* @author Spottedleaf
*/
// 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) {
@Overwrite
public void updateFutures(final ChunkMap chunkMap, final Executor executor) {
throw new UnsupportedOperationException();
}

View File

@@ -2,7 +2,6 @@ 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;
@@ -16,8 +15,8 @@ abstract class ChunkMap$DistanceManagerMixin extends net.minecraft.server.level.
@Final
ChunkMap field_17443;
protected ChunkMap$DistanceManagerMixin(final TicketStorage p_394060_, final Executor p_140774_, final Executor p_140775_) {
super(p_394060_, p_140774_, p_140775_);
protected ChunkMap$DistanceManagerMixin(Executor executor, Executor executor2) {
super(executor, executor2);
}
/**

View File

@@ -1,7 +1,7 @@
package ca.spottedleaf.moonrise.mixin.chunk_system;
import ca.spottedleaf.moonrise.common.PlatformHooks;
import ca.spottedleaf.moonrise.common.util.MoonriseConstants;
import ca.spottedleaf.moonrise.common.util.ChunkSystem;
import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemChunkMap;
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
@@ -11,17 +11,14 @@ import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder;
import com.mojang.datafixers.DataFixer;
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.IntConsumer;
import java.util.function.Supplier;
import it.unimi.dsi.fastutil.longs.LongSet;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.StreamTagVisitor;
import net.minecraft.server.level.ChunkGenerationTask;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ChunkResult;
import net.minecraft.server.level.ChunkTaskDispatcher;
import net.minecraft.server.level.ChunkTaskPriorityQueueSorter;
import net.minecraft.server.level.ChunkTrackingView;
import net.minecraft.server.level.GeneratingChunkMap;
import net.minecraft.server.level.GenerationChunkHolder;
@@ -31,8 +28,8 @@ import net.minecraft.server.level.progress.ChunkProgressListener;
import net.minecraft.util.Mth;
import net.minecraft.util.StaticCache2D;
import net.minecraft.util.thread.BlockableEventLoop;
import net.minecraft.util.thread.ProcessorHandle;
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;
@@ -44,6 +41,7 @@ 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;
@@ -80,10 +78,13 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
private volatile Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunkMap;
@Shadow
private ChunkTaskDispatcher worldgenTaskDispatcher;
private ChunkTaskPriorityQueueSorter queueSorter;
@Shadow
private ChunkTaskDispatcher lightTaskDispatcher;
private ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> worldgenMailbox;
@Shadow
private ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> mainThreadMailbox;
@Shadow
private int serverViewDistance;
@@ -97,12 +98,6 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
@Shadow
private Queue<Runnable> unloadQueue;
@Shadow
private LongSet chunksToEagerlySave;
@Shadow
private AtomicInteger activeChunkWrites;
public ChunkMapMixin(RegionStorageInfo regionStorageInfo, Path path, DataFixer dataFixer, boolean bl) {
super(regionStorageInfo, path, dataFixer, bl);
}
@@ -124,27 +119,25 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
)
)
private void constructor(
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) {
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) {
// intentionally destroy old chunk system hooks
this.updatingChunkMap = null;
this.visibleChunkMap = null;
this.pendingUnloads = null;
this.worldgenTaskDispatcher = null;
this.lightTaskDispatcher = null;
this.queueSorter = null;
this.worldgenMailbox = null;
this.mainThreadMailbox = null;
this.pendingGenerationTasks = null;
this.unloadQueue = null;
this.chunksToEagerlySave = null;
this.activeChunkWrites = null;
// Dummy impl for mods that try to loadAsync directly
this.worker = new IOWorker(
// copied from super call
new RegionStorageInfo(p_214837_.getLevelId(), p_214836_.dimension(), "chunk"),
p_214837_.getDimensionPath(p_214836_.dimension()).resolve("region"), p_214848_
new RegionStorageInfo(arg2.getLevelId(), arg.dimension(), "chunk"), arg2.getDimensionPath(arg.dimension()).resolve("region"), bl
) {
@Override
public boolean isOldChunkAround(final ChunkPos chunkPos, final int i) {
@@ -159,7 +152,7 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
@Override
public CompletableFuture<Optional<CompoundTag>> loadAsync(final ChunkPos chunkPos) {
final CompletableFuture<Optional<CompoundTag>> future = new CompletableFuture<>();
MoonriseRegionFileIO.loadDataAsync(ChunkMapMixin.this.level, chunkPos.x, chunkPos.z, MoonriseRegionFileIO.RegionFileType.CHUNK_DATA, (final CompoundTag tag, final Throwable throwable) -> {
MoonriseRegionFileIO.loadDataAsync(ChunkMapMixin.this.level, chunkPos.x, chunkPos.z, MoonriseRegionFileIO.RegionFileType.CHUNK_DATA, (tag, throwable) -> {
if (throwable != null) {
future.completeExceptionally(throwable);
} else {
@@ -191,15 +184,6 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
};
}
/**
* @reason This map is not needed, we maintain our own ordered set of chunks to autosave.
* @author Spottedleaf
*/
@Overwrite
public void setChunkUnsaved(final ChunkPos pos) {
}
/**
* @reason Route to new chunk system hooks
* @author Spottedleaf
@@ -277,15 +261,6 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
throw new UnsupportedOperationException();
}
/**
* @reason Destroy old chunk system hooks
* @author Spottedleaf
*/
@Overwrite
public void onLevelChange(final ChunkPos chunkPos, final IntSupplier intSupplier, final int i, final IntConsumer intConsumer) {
throw new UnsupportedOperationException();
}
/**
* @reason Destroy old chunk system hooks
* @author Spottedleaf
@@ -334,15 +309,6 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
((ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.autoSave();
}
/**
* @reason Destroy old chunk system hooks
* @author Spottedleaf
*/
@Overwrite
public void saveChunksEagerly(final BooleanSupplier hasTime) {
throw new UnsupportedOperationException();
}
/**
* @reason Destroy old chunk system hooks
* @author Spottedleaf
@@ -437,7 +403,7 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
* @author Spottedleaf
*/
@Overwrite
public void onChunkReadyToSend(final ChunkHolder holder, final LevelChunk chunk) {
public void onChunkReadyToSend(final LevelChunk chunk) {
throw new UnsupportedOperationException();
}
@@ -456,7 +422,7 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
* @see NewChunkHolder#save(boolean)
*/
@Overwrite
public boolean saveChunkIfNeeded(final ChunkHolder chunkHolder, final long time) {
public boolean saveChunkIfNeeded(final ChunkHolder chunkHolder) {
throw new UnsupportedOperationException();
}
@@ -500,7 +466,7 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
*/
@Overwrite
public int getPlayerViewDistance(final ServerPlayer player) {
return PlatformHooks.get().getSendViewDistance(player);
return ChunkSystem.getSendViewDistance(player);
}
/**
@@ -539,39 +505,6 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
throw new UnsupportedOperationException();
}
/**
* @reason Route to new chunk system
* @author Spottedleaf
*/
@Redirect(
method = "collectSpawningChunks",
at = @At(
value = "INVOKE",
target = "Lit/unimi/dsi/fastutil/longs/Long2ObjectLinkedOpenHashMap;get(J)Ljava/lang/Object;"
)
)
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);
}
@Override
public CompletableFuture<Optional<CompoundTag>> read(final ChunkPos pos) {
final CompletableFuture<Optional<CompoundTag>> ret = new CompletableFuture<>();
@@ -591,11 +524,10 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
}
@Override
public CompletableFuture<Void> write(final ChunkPos pos, final Supplier<CompoundTag> tag) {
public CompletableFuture<Void> write(final ChunkPos pos, final CompoundTag tag) {
MoonriseRegionFileIO.scheduleSave(
this.level, pos.x, pos.z, tag.get(),
MoonriseRegionFileIO.RegionFileType.CHUNK_DATA
);
this.level, pos.x, pos.z, tag,
MoonriseRegionFileIO.RegionFileType.CHUNK_DATA);
return null;
}
@@ -616,7 +548,7 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
)
)
private void avoidUpdateChunkTrackingInUpdate(final ChunkMap instance, final ServerPlayer serverPlayer) {
PlatformHooks.get().addPlayerToDistanceMaps(this.level, serverPlayer);
ChunkSystem.addPlayerToDistanceMaps(this.level, serverPlayer);
}
/**
@@ -646,7 +578,7 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
)
private void avoidApplyChunkTrackingViewInUpdate(final ChunkMap instance, final ServerPlayer serverPlayer,
final ChunkTrackingView chunkTrackingView) {
PlatformHooks.get().removePlayerFromDistanceMaps(this.level, serverPlayer);
ChunkSystem.removePlayerFromDistanceMaps(this.level, serverPlayer);
}
/**
@@ -660,7 +592,7 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
)
)
private void updateMapsHook(final ServerPlayer player, final CallbackInfo ci) {
PlatformHooks.get().updateMaps(this.level, player);
ChunkSystem.updateMaps(this.level, player);
}
/**

View File

@@ -3,13 +3,13 @@ package ca.spottedleaf.moonrise.mixin.chunk_system;
import net.minecraft.core.SectionPos;
import net.minecraft.world.entity.ai.village.poi.PoiManager;
import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.storage.SerializableChunkData;
import net.minecraft.world.level.chunk.storage.ChunkSerializer;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(SerializableChunkData.class)
abstract class SerializableChunkDataMixin {
@Mixin(ChunkSerializer.class)
abstract class ChunkSerializerMixin {
/**
* @reason Chunk system handles this during full transition
@@ -17,12 +17,12 @@ abstract class SerializableChunkDataMixin {
* @see ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.ChunkFullTask
*/
@Redirect(
method = "read",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/ai/village/poi/PoiManager;checkConsistencyWithBlocks(Lnet/minecraft/core/SectionPos;Lnet/minecraft/world/level/chunk/LevelChunkSection;)V"
)
method = "read",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/ai/village/poi/PoiManager;checkConsistencyWithBlocks(Lnet/minecraft/core/SectionPos;Lnet/minecraft/world/level/chunk/LevelChunkSection;)V"
)
)
private void skipConsistencyCheck(final PoiManager instance, final SectionPos sectionPos, final LevelChunkSection levelChunkSection) {}
private static void skipConsistencyCheck(PoiManager instance, SectionPos sectionPos, LevelChunkSection levelChunkSection) {}
}

View File

@@ -22,13 +22,12 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.io.IOException;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.function.Supplier;
@Mixin(ChunkStorage.class)
abstract class ChunkStorageMixin implements ChunkSystemChunkStorage, AutoCloseable {
@Shadow
public IOWorker worker;
private IOWorker worker;
@Unique
private static final Logger LOGGER = LogUtils.getLogger();
@@ -119,13 +118,13 @@ abstract class ChunkStorageMixin implements ChunkSystemChunkStorage, AutoCloseab
method = "write",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/level/chunk/storage/IOWorker;store(Lnet/minecraft/world/level/ChunkPos;Ljava/util/function/Supplier;)Ljava/util/concurrent/CompletableFuture;"
target = "Lnet/minecraft/world/level/chunk/storage/IOWorker;store(Lnet/minecraft/world/level/ChunkPos;Lnet/minecraft/nbt/CompoundTag;)Ljava/util/concurrent/CompletableFuture;"
)
)
private CompletableFuture<Void> redirectWrite(final IOWorker instance, final ChunkPos chunkPos,
final Supplier<CompoundTag> compoundTag) {
final CompoundTag compoundTag) {
try {
this.storage.write(chunkPos, compoundTag.get());
this.storage.write(chunkPos, compoundTag);
return CompletableFuture.completedFuture(null);
} catch (final Throwable throwable) {
return CompletableFuture.failedFuture(throwable);

View File

@@ -41,8 +41,8 @@ abstract class ClientLevelMixin extends Level implements ChunkSystemLevel {
@Final
private ClientChunkCache chunkSource;
protected ClientLevelMixin(final WritableLevelData writableLevelData, final ResourceKey<Level> resourceKey, final RegistryAccess registryAccess, final Holder<DimensionType> holder, final boolean bl, final boolean bl2, final long l, final int i) {
super(writableLevelData, resourceKey, registryAccess, holder, bl, bl2, l, i);
protected ClientLevelMixin(WritableLevelData writableLevelData, ResourceKey<Level> resourceKey, RegistryAccess registryAccess, Holder<DimensionType> holder, Supplier<ProfilerFiller> supplier, boolean bl, boolean bl2, long l, int i) {
super(writableLevelData, resourceKey, registryAccess, holder, supplier, bl, bl2, l, i);
}
/**
@@ -55,8 +55,9 @@ abstract class ClientLevelMixin extends Level implements ChunkSystemLevel {
value = "RETURN"
)
)
private void init(ClientPacketListener clientPacketListener, ClientLevel.ClientLevelData clientLevelData, ResourceKey<Level> resourceKey,
Holder<DimensionType> holder, int i, int j, LevelRenderer levelRenderer, boolean bl, long l, int k, CallbackInfo ci) {
private void init(ClientPacketListener clientPacketListener, ClientLevel.ClientLevelData clientLevelData,
ResourceKey<Level> resourceKey, Holder<DimensionType> holder, int i, int j, Supplier<ProfilerFiller> supplier,
LevelRenderer levelRenderer, boolean bl, long l, CallbackInfo ci) {
this.entityStorage = null;
this.moonrise$setEntityLookup(new ClientEntityLookup(this, ((ClientLevel)(Object)this).new EntityCallbacks()));

View File

@@ -1,27 +1,23 @@
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 ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketStorage;
import it.unimi.dsi.fastutil.longs.LongConsumer;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.longs.LongSet;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.ChunkMap;
import net.minecraft.server.level.ChunkTaskPriorityQueueSorter;
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.util.thread.ProcessorHandle;
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;
@@ -29,7 +25,6 @@ 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;
@@ -37,14 +32,13 @@ import java.util.concurrent.Executor;
abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
@Shadow
public LoadingChunkTracker loadingChunkTracker;
Long2ObjectOpenHashMap<SortedArraySet<Ticket<?>>> tickets;
@Shadow
public SimulationChunkTracker simulationChunkTracker;
private DistanceManager.ChunkTicketTracker ticketTracker;
@Shadow
@Final
private TicketStorage ticketStorage;
private TickingTracker tickingTicketsTracker;
@Shadow
private DistanceManager.PlayerTicketTracker playerTicketManager;
@@ -53,7 +47,13 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
Set<ChunkHolder> chunksToUpdateFutures;
@Shadow
ThrottlingChunkTaskDispatcher ticketDispatcher;
ChunkTaskPriorityQueueSorter ticketThrottler;
@Shadow
ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> ticketThrottlerInput;
@Shadow
ProcessorHandle<ChunkTaskPriorityQueueSorter.Release> ticketThrottlerReleaser;
@Shadow
LongSet ticketsToRelease;
@@ -62,8 +62,10 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
Executor mainThreadExecutor;
@Shadow
private int simulationDistance;
private DistanceManager.FixedPlayerDistanceChunkTracker naturalSpawnChunkCounter;
@Shadow
private int simulationDistance;
@Override
public ChunkMap moonrise$getChunkMap() {
@@ -71,8 +73,7 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
}
/**
* @reason Destroy old chunk system state to prevent it from being used, and set the chunk map
* for the ticket storage
* @reason Destroy old chunk system state to prevent it from being used
* @author Spottedleaf
*/
@Inject(
@@ -82,23 +83,33 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
)
)
private void destroyFields(final CallbackInfo ci) {
this.loadingChunkTracker = null;
this.simulationChunkTracker = null;
this.tickets = null;
this.ticketTracker = null;
this.tickingTicketsTracker = null;
this.playerTicketManager = null;
this.chunksToUpdateFutures = null;
this.ticketDispatcher = null;
this.ticketThrottler = null;
this.ticketThrottlerInput = null;
this.ticketThrottlerReleaser = null;
this.ticketsToRelease = null;
this.mainThreadExecutor = null;
this.simulationDistance = -1;
((ChunkSystemTicketStorage)this.ticketStorage).moonrise$setChunkMap(this.moonrise$getChunkMap());
}
@Override
public final ChunkHolderManager moonrise$getChunkHolderManager() {
public ChunkHolderManager moonrise$getChunkHolderManager() {
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,6 +119,46 @@ 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
@@ -130,10 +181,11 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
method = "addPlayer",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/level/TicketStorage;addTicket(Lnet/minecraft/server/level/Ticket;Lnet/minecraft/world/level/ChunkPos;)V"
target = "Lnet/minecraft/server/level/TickingTracker;addTicket(Lnet/minecraft/server/level/TicketType;Lnet/minecraft/world/level/ChunkPos;ILjava/lang/Object;)V"
)
)
private void skipTickingTicketTrackerAdd(final TicketStorage instance, final Ticket ticket, final ChunkPos pos) {}
private <T> void skipTickingTicketTrackerAdd(final TickingTracker instance, final TicketType<T> ticketType,
final ChunkPos chunkPos, final int i, final T object) {}
/**
* @reason Remove old chunk system hooks
@@ -172,10 +224,11 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
method = "removePlayer",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/level/TicketStorage;removeTicket(Lnet/minecraft/server/level/Ticket;Lnet/minecraft/world/level/ChunkPos;)V"
target = "Lnet/minecraft/server/level/TickingTracker;removeTicket(Lnet/minecraft/server/level/TicketType;Lnet/minecraft/world/level/ChunkPos;ILjava/lang/Object;)V"
)
)
private void skipTickingTicketTrackerRemove(final TicketStorage instance, final Ticket ticket, final ChunkPos pos) {}
private <T> void skipTickingTicketTrackerRemove(final TickingTracker instance, final TicketType<T> ticketType,
final ChunkPos chunkPos, final int i, final T object) {}
/**
* @reason Remove old chunk system hooks
@@ -226,9 +279,8 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
* @author Spottedleaf
*/
@Overwrite
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();
public String getTicketDebugString(final long pos) {
return this.moonrise$getChunkHolderManager().getTicketDebugString(pos);
}
/**
@@ -257,25 +309,41 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
* @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()));
}
public String getDebugStatus() {
return "No DistanceManager stats available";
}
/**
* @reason Route to new chunk system
* @reason Remove old chunk system hooks
* @author Spottedleaf
*/
@Overwrite
public String getDebugStatus() {
return "N/A";
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 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();
}
}

View File

@@ -11,14 +11,9 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(DynamicGameEventListener.class)
abstract class DynamicGameEventListenerMixin {
@Shadow
@Nullable
private SectionPos lastSection;
@Shadow @Nullable private SectionPos lastSection;
@Inject(
method = "remove",
at = @At("RETURN")
)
@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.

View File

@@ -4,7 +4,6 @@ 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;
@@ -33,6 +32,10 @@ abstract class EntityMixin implements ChunkSystemEntity {
@Shadow
protected abstract Stream<Entity> getIndirectPassengersStream();
@Shadow
@Final
private static Logger LOGGER;
@Shadow
private Level level;
@@ -40,8 +43,6 @@ 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();

View File

@@ -25,7 +25,7 @@ abstract class EntityTickListMixin {
private Int2ObjectMap<Entity> passive;
@Unique
private final IteratorSafeOrderedReferenceSet<Entity> entities = new IteratorSafeOrderedReferenceSet<>(Entity.class);
private final IteratorSafeOrderedReferenceSet<Entity> entities = new IteratorSafeOrderedReferenceSet<>();
/**
* @reason Initialise new fields and destroy old state

View File

@@ -195,6 +195,15 @@ abstract class GenerationChunkHolderMixin {
throw new UnsupportedOperationException();
}
/**
* @reason Chunk system is not built on futures anymore
* @author Spottedleaf
*/
@Overwrite
public int getGenerationRefCount() {
throw new UnsupportedOperationException();
}
/**
* @reason Route to new chunk holder
* @author Spottedleaf

View File

@@ -1,7 +1,6 @@
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;
@@ -49,7 +48,7 @@ abstract class LevelChunkMixin extends ChunkAccess implements ChunkSystemLevelCh
private boolean postProcessingDone;
@Unique
private NewChunkHolder chunkAndHolder;
private ServerChunkCache.ChunkAndHolder chunkAndHolder;
@Override
public final boolean moonrise$isPostProcessingDone() {
@@ -57,12 +56,12 @@ abstract class LevelChunkMixin extends ChunkAccess implements ChunkSystemLevelCh
}
@Override
public final NewChunkHolder moonrise$getChunkHolder() {
public final ServerChunkCache.ChunkAndHolder moonrise$getChunkAndHolder() {
return this.chunkAndHolder;
}
@Override
public final void moonrise$setChunkHolder(final NewChunkHolder holder) {
public final void moonrise$setChunkAndHolder(final ServerChunkCache.ChunkAndHolder holder) {
this.chunkAndHolder = holder;
}
@@ -94,15 +93,11 @@ abstract class LevelChunkMixin extends ChunkAccess implements ChunkSystemLevelCh
}
@Override
public boolean tryMarkSaved() {
if (!this.isUnsaved()) {
return false;
public void setUnsaved(final boolean needsSaving) {
if (!needsSaving) {
((ChunkSystemLevelChunkTicks)this.blockTicks).moonrise$clearDirty();
((ChunkSystemLevelChunkTicks)this.fluidTicks).moonrise$clearDirty();
}
((ChunkSystemLevelChunkTicks)this.blockTicks).moonrise$clearDirty();
((ChunkSystemLevelChunkTicks)this.fluidTicks).moonrise$clearDirty();
super.tryMarkSaved();
return true;
super.setUnsaved(needsSaving);
}
}

View File

@@ -105,12 +105,12 @@ abstract class LevelChunkTicksMixin<T> implements ChunkSystemLevelChunkTicks, Se
* @author Spottedleaf
*/
@Inject(
method = "pack",
method = "save(JLjava/util/function/Function;)Lnet/minecraft/nbt/ListTag;",
at = @At(
value = "HEAD"
)
)
private void saveHook(final long time, final CallbackInfoReturnable<ListTag> cir) {
private void saveHook(final long time, final Function<T, String> idFunction, final CallbackInfoReturnable<ListTag> cir) {
this.lastSaved = time;
}

View File

@@ -10,7 +10,6 @@ import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.dfl.DefaultEnti
import ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemEntityGetter;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.FullChunkStatus;
import net.minecraft.util.profiling.Profiler;
import net.minecraft.util.profiling.ProfilerFiller;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityType;
@@ -38,6 +37,9 @@ import java.util.function.Predicate;
@Mixin(Level.class)
abstract class LevelMixin implements ChunkSystemLevel, ChunkSystemEntityGetter, LevelAccessor, AutoCloseable {
@Shadow
public abstract ProfilerFiller getProfiler();
@Shadow
public abstract LevelChunk getChunk(int i, int j);
@@ -57,7 +59,7 @@ abstract class LevelMixin implements ChunkSystemLevel, ChunkSystemEntityGetter,
}
@Override
public final void moonrise$setEntityLookup(final EntityLookup entityLookup) {
public void moonrise$setEntityLookup(final EntityLookup entityLookup) {
if (this.entityLookup != null && !(this.entityLookup instanceof DefaultEntityLookup)) {
throw new IllegalStateException("Entity lookup already initialised");
}
@@ -85,7 +87,7 @@ abstract class LevelMixin implements ChunkSystemLevel, ChunkSystemEntityGetter,
@Overwrite
@Override
public List<Entity> getEntities(final Entity entity, final AABB boundingBox, final Predicate<? super Entity> predicate) {
Profiler.get().incrementCounter("getEntities");
this.getProfiler().incrementCounter("getEntities");
final List<Entity> ret = new ArrayList<>();
((ChunkSystemLevel)this).moonrise$getEntityLookup().getEntities(entity, boundingBox, ret, predicate);
@@ -103,7 +105,7 @@ abstract class LevelMixin implements ChunkSystemLevel, ChunkSystemEntityGetter,
public <T extends Entity> void getEntities(final EntityTypeTest<Entity, T> entityTypeTest,
final AABB boundingBox, final Predicate<? super T> predicate,
final List<? super T> into, final int maxCount) {
Profiler.get().incrementCounter("getEntities");
this.getProfiler().incrementCounter("getEntities");
if (entityTypeTest instanceof EntityType<T> byType) {
if (maxCount != Integer.MAX_VALUE) {
@@ -176,7 +178,7 @@ abstract class LevelMixin implements ChunkSystemLevel, ChunkSystemEntityGetter,
*/
@Override
public final <T extends Entity> List<T> getEntitiesOfClass(final Class<T> entityClass, final AABB boundingBox, final Predicate<? super T> predicate) {
Profiler.get().incrementCounter("getEntities");
this.getProfiler().incrementCounter("getEntities");
final List<T> ret = new ArrayList<>();
((ChunkSystemLevel)this).moonrise$getEntityLookup().getEntities(entityClass, null, boundingBox, ret, predicate);
@@ -194,7 +196,7 @@ abstract class LevelMixin implements ChunkSystemLevel, ChunkSystemEntityGetter,
*/
@Override
public final List<Entity> moonrise$getHardCollidingEntities(final Entity entity, final AABB box, final Predicate<? super Entity> predicate) {
Profiler.get().incrementCounter("getEntities");
this.getProfiler().incrementCounter("getEntities");
final List<Entity> ret = new ArrayList<>();
((ChunkSystemLevel)this).moonrise$getEntityLookup().getHardCollidingEntities(entity, box, ret, predicate);

View File

@@ -190,11 +190,6 @@ 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;
}
@@ -243,9 +238,8 @@ abstract class MinecraftServerMixin extends ReentrantBlockableEventLoop<TickTask
)
)
private void closeIOThreads(final CallbackInfo ci) {
LOGGER.info("Waiting for all RegionFile I/O tasks to complete...");
LOGGER.info("Waiting for I/O tasks to complete...");
MoonriseRegionFileIO.flush((MinecraftServer)(Object)this);
LOGGER.info("All RegionFile I/O tasks to complete");
if ((Object)this instanceof DedicatedServer) {
MoonriseCommon.haltExecutors();
}

View File

@@ -36,7 +36,6 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.BooleanSupplier;
import java.util.function.Function;
import java.util.function.Predicate;
@@ -45,14 +44,7 @@ import java.util.stream.Stream;
@Mixin(PoiManager.class)
// Declare the generic type as Object so that our Overrides match the method signature of the superclass
// Specifically, getOrCreate must return Object so that existing invokes do not route to the superclass
public abstract class PoiManagerMixin extends SectionStorage<Object, Object> implements ChunkSystemPoiManager {
public PoiManagerMixin(final SimpleRegionStorage simpleRegionStorage, final Codec<Object> codec, final Function<Object, Object> function,
final BiFunction<Object, Runnable, Object> biFunction, final Function<Runnable, Object> function2,
final RegistryAccess registryAccess, final ChunkIOErrorReporter chunkIOErrorReporter,
final LevelHeightAccessor levelHeightAccessor) {
super(simpleRegionStorage, codec, function, biFunction, function2, registryAccess, chunkIOErrorReporter, levelHeightAccessor);
}
public abstract class PoiManagerMixin extends SectionStorage<Object> implements ChunkSystemPoiManager {
@Shadow
abstract boolean isVillageCenter(long l);
@@ -60,6 +52,10 @@ public abstract class PoiManagerMixin extends SectionStorage<Object, Object> imp
@Shadow
public abstract void checkConsistencyWithBlocks(SectionPos sectionPos, LevelChunkSection levelChunkSection);
public PoiManagerMixin(SimpleRegionStorage simpleRegionStorage, Function<Runnable, Codec<Object>> function, Function<Runnable, Object> function2, RegistryAccess registryAccess, ChunkIOErrorReporter chunkIOErrorReporter, LevelHeightAccessor levelHeightAccessor) {
super(simpleRegionStorage, function, function2, registryAccess, chunkIOErrorReporter, levelHeightAccessor);
}
@Unique
private ServerLevel world;
@@ -155,8 +151,8 @@ public abstract class PoiManagerMixin extends SectionStorage<Object, Object> imp
TickThread.ensureTickThread(this.world, chunkX, chunkZ, "Accessing poi chunk off-main");
final PoiChunk ret = ((ChunkSystemServerLevel)this.world).moonrise$getChunkTaskScheduler().chunkHolderManager
.getPoiChunkIfLoaded(chunkX, chunkZ, true);
final ChunkHolderManager manager = ((ChunkSystemServerLevel)this.world).moonrise$getChunkTaskScheduler().chunkHolderManager;
final PoiChunk ret = manager.getPoiChunkIfLoaded(chunkX, chunkZ, true);
return ret == null ? Optional.empty() : (Optional)ret.getSectionForVanilla(chunkY);
}
@@ -210,13 +206,9 @@ public abstract class PoiManagerMixin extends SectionStorage<Object, Object> imp
public final void moonrise$onUnload(final long coordinate) { // Paper - rewrite chunk system
final int chunkX = CoordinateUtils.getChunkX(coordinate);
final int chunkZ = CoordinateUtils.getChunkZ(coordinate);
final int minY = WorldUtil.getMinSection(this.world);
final int maxY = WorldUtil.getMaxSection(this.world);
TickThread.ensureTickThread(this.world, chunkX, chunkZ, "Unloading poi chunk off-main");
for (int sectionY = minY; sectionY <= maxY; ++sectionY) {
final long sectionPos = SectionPos.asLong(chunkX, sectionY, chunkZ);
for (int section = this.levelHeightAccessor.getMinSection(); section < this.levelHeightAccessor.getMaxSection(); ++section) {
final long sectionPos = SectionPos.asLong(chunkX, section, chunkZ);
this.updateDistanceTracking(sectionPos);
}
}
@@ -225,12 +217,8 @@ public abstract class PoiManagerMixin extends SectionStorage<Object, Object> imp
public final void moonrise$loadInPoiChunk(final PoiChunk poiChunk) {
final int chunkX = poiChunk.chunkX;
final int chunkZ = poiChunk.chunkZ;
final int minY = WorldUtil.getMinSection(this.world);
final int maxY = WorldUtil.getMaxSection(this.world);
TickThread.ensureTickThread(this.world, chunkX, chunkZ, "Loading poi chunk off-main");
for (int sectionY = minY; sectionY <= maxY; ++sectionY) {
for (int sectionY = this.levelHeightAccessor.getMinSection(); sectionY < this.levelHeightAccessor.getMaxSection(); ++sectionY) {
final PoiSection section = poiChunk.getSection(sectionY);
if (section != null && !((ChunkSystemPoiSection)section).moonrise$isEmpty()) {
this.onSectionLoad(SectionPos.asLong(chunkX, sectionY, chunkZ));
@@ -266,4 +254,20 @@ public abstract class PoiManagerMixin extends SectionStorage<Object, Object> imp
private <T> Stream<T> skipLoadedSet(final Stream<T> instance, final Predicate<? super T> predicate) {
return instance;
}
@Override
public final void moonrise$close() throws IOException {}
@Override
public final CompoundTag moonrise$read(final int chunkX, final int chunkZ) throws IOException {
return MoonriseRegionFileIO.loadData(
this.world, chunkX, chunkZ, MoonriseRegionFileIO.RegionFileType.POI_DATA,
MoonriseRegionFileIO.getIOBlockingPriorityForCurrentThread()
);
}
@Override
public final void moonrise$write(final int chunkX, final int chunkZ, final CompoundTag data) throws IOException {
MoonriseRegionFileIO.scheduleSave(this.world, chunkX, chunkZ, data, MoonriseRegionFileIO.RegionFileType.POI_DATA);
}
}

View File

@@ -30,7 +30,7 @@ abstract class PoiSectionMixin implements ChunkSystemPoiSection {
@Unique
private final Optional<PoiSection> noAllocOptional = Optional.of((PoiSection)(Object)this);
private final Optional<PoiSection> noAllocOptional = Optional.of((PoiSection)(Object)this);;
@Override
public final boolean moonrise$isEmpty() {

View File

@@ -2,6 +2,8 @@ package ca.spottedleaf.moonrise.mixin.chunk_system;
import ca.spottedleaf.moonrise.patches.chunk_system.level.storage.ChunkSystemSectionStorage;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.resources.RegistryOps;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.storage.RegionFileStorage;
import net.minecraft.world.level.chunk.storage.SectionStorage;
@@ -21,11 +23,15 @@ import java.util.Optional;
import java.util.concurrent.CompletableFuture;
@Mixin(SectionStorage.class)
abstract class SectionStorageMixin<R, P> implements ChunkSystemSectionStorage, AutoCloseable {
abstract class SectionStorageMixin implements ChunkSystemSectionStorage, AutoCloseable {
@Shadow
private SimpleRegionStorage simpleRegionStorage;
@Shadow
@Final
private static Logger LOGGER;
@Unique
private RegionFileStorage storage;
@@ -35,9 +41,6 @@ abstract class SectionStorageMixin<R, P> implements ChunkSystemSectionStorage, A
return this.storage;
}
@Override
public void moonrise$close() throws IOException {}
/**
* @reason Retrieve storage from IOWorker, and then nuke it
* @author Spottedleaf
@@ -58,8 +61,12 @@ abstract class SectionStorageMixin<R, P> implements ChunkSystemSectionStorage, A
* @author Spottedleaf
*/
@Overwrite
public final CompletableFuture<Optional<SectionStorage.PackedChunk<P>>> tryRead(final ChunkPos pos) {
throw new IllegalStateException("Only chunk system can write state, offending class:" + this.getClass().getName());
public final CompletableFuture<Optional<CompoundTag>> tryRead(final ChunkPos pos) {
try {
return CompletableFuture.completedFuture(Optional.ofNullable(this.moonrise$read(pos.x, pos.z)));
} catch (final Throwable thr) {
return CompletableFuture.failedFuture(thr);
}
}
/**
@@ -67,17 +74,29 @@ abstract class SectionStorageMixin<R, P> implements ChunkSystemSectionStorage, A
* @author Spottedleaf
*/
@Overwrite
public void unpackChunk(final ChunkPos chunkPos, final SectionStorage.PackedChunk<P> packedChunk) {
public void readColumn(final ChunkPos pos, final RegistryOps<Tag> ops, final CompoundTag data) {
throw new IllegalStateException("Only chunk system can load in state, offending class:" + this.getClass().getName());
}
/**
* @reason Destroy old chunk system hook
* @reason Route to new chunk system hook
* @author Spottedleaf
*/
@Overwrite
private void writeChunk(final ChunkPos chunkPos) {
throw new IllegalStateException("Only chunk system can write state, offending class:" + this.getClass().getName());
@Redirect(
method = "writeColumn(Lnet/minecraft/world/level/ChunkPos;)V",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/level/chunk/storage/SimpleRegionStorage;write(Lnet/minecraft/world/level/ChunkPos;Lnet/minecraft/nbt/CompoundTag;)Ljava/util/concurrent/CompletableFuture;"
)
)
private CompletableFuture<Void> redirectWrite(final SimpleRegionStorage instance, final ChunkPos pos,
final CompoundTag tag) {
try {
this.moonrise$write(pos.x, pos.z, tag);
} catch (final IOException ex) {
LOGGER.error("Error writing poi chunk data to disk for chunk " + pos, ex);
}
return null;
}
/**
@@ -94,4 +113,4 @@ abstract class SectionStorageMixin<R, P> implements ChunkSystemSectionStorage, A
private void redirectClose(final SimpleRegionStorage instance) throws IOException {
this.moonrise$close();
}
}
}

View File

@@ -3,17 +3,18 @@ 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;
@@ -23,7 +24,6 @@ import net.minecraft.world.level.chunk.ChunkSource;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LightChunk;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import net.minecraft.world.level.storage.DimensionDataStorage;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
@@ -34,6 +34,8 @@ 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;
@@ -49,13 +51,12 @@ abstract class ServerChunkCacheMixin extends ChunkSource implements ChunkSystemS
@Final
public ServerLevel level;
@Shadow
@Final
private DimensionDataStorage dataStorage;
@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);
@@ -267,7 +268,6 @@ abstract class ServerChunkCacheMixin extends ChunkSource implements ChunkSystemS
@Override
@Overwrite
public void close() throws IOException {
this.dataStorage.close();
((ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.close(true, true);
}
@@ -316,51 +316,86 @@ abstract class ServerChunkCacheMixin extends ChunkSource implements ChunkSystemS
return false;
}
/**
* @reason We need to use {@link ChunkHolder#getChunkToSend()} as the new chunk system will not bring every chunk
* sent to players up to block ticking.
* @reason Perform mid-tick chunk task processing during chunk tick
* @author Spottedleaf
*/
@Redirect(
method = "broadcastChangedChunks",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/server/level/ChunkHolder;getTickingChunk()Lnet/minecraft/world/level/chunk/LevelChunk;")
@Inject(
method = "tickChunks",
at = @At(
value = "INVOKE",
shift = At.Shift.AFTER,
target = "Lnet/minecraft/server/level/ServerLevel;tickChunk(Lnet/minecraft/world/level/chunk/LevelChunk;I)V"
)
)
private LevelChunk redirectTickingChunk(final ChunkHolder instance) {
return instance.getChunkToSend();
private void midTickChunks(final CallbackInfo ci) {
if ((++this.chunksTicked & 7L) != 0L) {
return;
}
((ChunkSystemMinecraftServer)this.level.getServer()).moonrise$executeMidTickTasks();
}
/**
* @reason In the chunk system, spawn chunks will return only entity ticking chunks - we can elide the
* entity ticking range check.
* @reason In the chunk system, ticking chunks always have loaded entities. Of course, they are also always
* marked to be as ticking as well.
* @author Spottedleaf
*/
@Redirect(
method = "tickSpawningChunk",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/server/level/DistanceManager;inEntityTickingRange(J)Z"
)
method = "tickChunks",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/server/level/ServerLevel;isNaturalSpawningAllowed(Lnet/minecraft/world/level/ChunkPos;)Z"
)
)
private boolean shortTickThunder(final DistanceManager instance, final long pos) {
private boolean shortNaturalSpawning(final ServerLevel instance, final ChunkPos chunkPos) {
return true;
}
/**
* @reason In the chunk system, spawn chunks will return only entity ticking chunks - we can elide the
* entity ticking check.
* @reason In the chunk system, ticking chunks always have loaded entities. Of course, they are also always
* marked to be as ticking as well.
* @author Spottedleaf
*/
@Redirect(
method = "tickSpawningChunk",
method = "tickChunks",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/server/level/ServerLevel;shouldTickBlocksAt(J)Z"
)
)
private boolean shortShouldTickBlocks(final ServerLevel instance, final long pos) {
return true;
}
/**
* @reason Since chunks in non-simulation range are only brought up to FULL status, not TICKING,
* those chunks may not be present in the ticking list and as a result we need to use our own list
* to ensure these chunks broadcast changes
* @author Spottedleaf
*/
@Redirect(
method = "tickChunks",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/server/level/ServerLevel;canSpawnEntitiesInChunk(Lnet/minecraft/world/level/ChunkPos;)Z"
target = "Ljava/util/List;forEach(Ljava/util/function/Consumer;)V"
)
)
private boolean onlyCheckWBForSpawning(final ServerLevel instance, final ChunkPos pos) {
return instance.getWorldBorder().isWithinBounds(pos);
private void fixBroadcastChanges(final List<ServerChunkCache.ChunkAndHolder> instance,
final Consumer<ServerChunkCache.ChunkAndHolder> consumer) {
final ReferenceList<ChunkHolder> unsyncedChunks = ((ChunkSystemServerLevel)this.level).moonrise$getUnsyncedChunks();
final ChunkHolder[] chunkHolders = unsyncedChunks.getRawDataUnchecked();
final int totalUnsyncedChunks = unsyncedChunks.size();
Objects.checkFromToIndex(0, totalUnsyncedChunks, chunkHolders.length);
for (int i = 0; i < totalUnsyncedChunks; ++i) {
final ChunkHolder chunkHolder = chunkHolders[i];
final LevelChunk chunk = chunkHolder.getChunkToSend();
if (chunk != null) {
chunkHolder.broadcastChanges(chunk);
}
}
((ChunkSystemServerLevel)this.level).moonrise$clearUnsyncedChunks();
}
}

View File

@@ -10,6 +10,7 @@ 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;
@@ -26,11 +27,13 @@ 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;
@@ -61,10 +64,12 @@ 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)
@@ -81,8 +86,8 @@ abstract class ServerLevelMixin extends Level implements ChunkSystemServerLevel,
@Final
private ServerChunkCache chunkSource;
protected ServerLevelMixin(final WritableLevelData writableLevelData, final ResourceKey<Level> resourceKey, final RegistryAccess registryAccess, final Holder<DimensionType> holder, final boolean bl, final boolean bl2, final long l, final int i) {
super(writableLevelData, resourceKey, registryAccess, holder, bl, bl2, l, i);
protected ServerLevelMixin(WritableLevelData writableLevelData, ResourceKey<Level> resourceKey, RegistryAccess registryAccess, Holder<DimensionType> holder, Supplier<ProfilerFiller> supplier, boolean bl, boolean bl2, long l, int i) {
super(writableLevelData, resourceKey, registryAccess, holder, supplier, bl, bl2, l, i);
}
@Unique
@@ -116,16 +121,22 @@ abstract class ServerLevelMixin extends Level implements ChunkSystemServerLevel,
private final NearbyPlayers nearbyPlayers = new NearbyPlayers((ServerLevel)(Object)this);
@Unique
private static final LevelChunk[] EMPTY_LEVEL_CHUNKS = new LevelChunk[0];
private static final ServerChunkCache.ChunkAndHolder[] EMPTY_CHUNK_AND_HOLDERS = new ServerChunkCache.ChunkAndHolder[0];
@Unique
private final ReferenceList<LevelChunk> loadedChunks = new ReferenceList<>(EMPTY_LEVEL_CHUNKS);
private static final ChunkHolder[] EMPTY_CHUNK_HOLDERS = new ChunkHolder[0];
@Unique
private final ReferenceList<LevelChunk> tickingChunks = new ReferenceList<>(EMPTY_LEVEL_CHUNKS);
private final ReferenceList<ServerChunkCache.ChunkAndHolder> loadedChunks = new ReferenceList<>(EMPTY_CHUNK_AND_HOLDERS);
@Unique
private final ReferenceList<LevelChunk> entityTickingChunks = new ReferenceList<>(EMPTY_LEVEL_CHUNKS);
private final ReferenceList<ServerChunkCache.ChunkAndHolder> tickingChunks = new ReferenceList<>(EMPTY_CHUNK_AND_HOLDERS);
@Unique
private final ReferenceList<ServerChunkCache.ChunkAndHolder> entityTickingChunks = new ReferenceList<>(EMPTY_CHUNK_AND_HOLDERS);
@Unique
private final ReferenceList<ChunkHolder> unsyncedChunks = new ReferenceList<>(EMPTY_CHUNK_HOLDERS);
/**
* @reason Initialise fields / destroy entity manager state
@@ -329,20 +340,59 @@ abstract class ServerLevelMixin extends Level implements ChunkSystemServerLevel,
}
@Override
public final ReferenceList<LevelChunk> moonrise$getLoadedChunks() {
public final ReferenceList<ServerChunkCache.ChunkAndHolder> moonrise$getLoadedChunks() {
return this.loadedChunks;
}
@Override
public final ReferenceList<LevelChunk> moonrise$getTickingChunks() {
public final ReferenceList<ServerChunkCache.ChunkAndHolder> moonrise$getTickingChunks() {
return this.tickingChunks;
}
@Override
public final ReferenceList<LevelChunk> moonrise$getEntityTickingChunks() {
public final ReferenceList<ServerChunkCache.ChunkAndHolder> moonrise$getEntityTickingChunks() {
return this.entityTickingChunks;
}
@Override
public final ReferenceList<ChunkHolder> moonrise$getUnsyncedChunks() {
return this.unsyncedChunks;
}
@Override
public final void moonrise$addUnsyncedChunk(final ChunkHolder chunkHolder) {
if (((ChunkSystemChunkHolder)chunkHolder).moonrise$isMarkedDirtyForPlayers()) {
return;
}
((ChunkSystemChunkHolder)chunkHolder).moonrise$markDirtyForPlayers(true);
this.unsyncedChunks.add(chunkHolder);
}
@Override
public final void moonrise$removeUnsyncedChunk(final ChunkHolder chunkHolder) {
if (!((ChunkSystemChunkHolder)chunkHolder).moonrise$isMarkedDirtyForPlayers()) {
return;
}
((ChunkSystemChunkHolder)chunkHolder).moonrise$markDirtyForPlayers(false);
this.unsyncedChunks.remove(chunkHolder);
}
@Override
public final void moonrise$clearUnsyncedChunks() {
final ChunkHolder[] chunkHolders = this.unsyncedChunks.getRawDataUnchecked();
final int totalUnsyncedChunks = this.unsyncedChunks.size();
Objects.checkFromToIndex(0, totalUnsyncedChunks, chunkHolders.length);
for (int i = 0; i < totalUnsyncedChunks; ++i) {
final ChunkHolder chunkHolder = chunkHolders[i];
((ChunkSystemChunkHolder)chunkHolder).moonrise$markDirtyForPlayers(false);
}
this.unsyncedChunks.clear();
}
@Override
public final boolean moonrise$areChunksLoaded(final int fromX, final int fromZ, final int toX, final int toZ) {
final ServerChunkCache chunkSource = this.chunkSource;
@@ -661,7 +711,7 @@ abstract class ServerLevelMixin extends Level implements ChunkSystemServerLevel,
* @author Spottedleaf
*/
@Overwrite
public boolean isPositionEntityTicking(final BlockPos pos) {
public boolean isPositionEntityTicking(BlockPos pos) {
final NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(CoordinateUtils.getChunkKey(pos));
return chunkHolder != null && chunkHolder.isEntityTickingReady();
}
@@ -671,7 +721,7 @@ abstract class ServerLevelMixin extends Level implements ChunkSystemServerLevel,
* @author Spottedleaf
*/
@Overwrite
public boolean areEntitiesActuallyLoadedAndTicking(final ChunkPos pos) {
public boolean isNaturalSpawningAllowed(final BlockPos pos) {
final NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(CoordinateUtils.getChunkKey(pos));
return chunkHolder != null && chunkHolder.isEntityTickingReady();
}
@@ -680,14 +730,8 @@ abstract class ServerLevelMixin extends Level implements ChunkSystemServerLevel,
* @reason Redirect to chunk system
* @author Spottedleaf
*/
@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) {
@Overwrite
public boolean isNaturalSpawningAllowed(final ChunkPos pos) {
final NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(CoordinateUtils.getChunkKey(pos));
return chunkHolder != null && chunkHolder.isEntityTickingReady();
}

View File

@@ -49,7 +49,8 @@ abstract class SortedArraySetMixin<T> extends AbstractSet<T> implements ChunkSys
if (i >= len) {
return false;
}
if (!filter.test(backingArray[i++])) {
if (!filter.test(backingArray[i])) {
++i;
continue;
}
break;
@@ -57,7 +58,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 - 1; // this is where new elements are shifted to
int lastIndex = i; // this is where new elements are shifted to
for (; i < len; ++i) {
final T curr = backingArray[i];

View File

@@ -1,7 +1,6 @@
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;
@@ -9,75 +8,61 @@ 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 type;
private TicketType<T> type;
@Shadow
@Final
private int ticketLevel;
@Shadow
private long ticksLeft;
@Final
public T key;
@Unique
private T identifier;
private long removeDelay;
@Override
public final long moonrise$getRemoveDelay() {
return this.ticksLeft;
return this.removeDelay;
}
@Override
public final void moonrise$setRemoveDelay(final long 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;
this.removeDelay = removeDelay;
}
/**
* @reason Change debug to include remove identifier
* @reason Change debug to include remove delay
* @author Spottedleaf
*/
@Overwrite
@Override
public String toString() {
return "Ticket[" + this.type + " " + this.ticketLevel + " (" + this.identifier + ")] to die in " + this.ticksLeft;
return "Ticket[" + this.type + " " + this.ticketLevel + " (" + this.key + ")] to die in " + this.removeDelay;
}
@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 void setCreatedTick(final long tickCreated) {
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);
/**
* @reason Remove old chunk system hook
* @author Spottedleaf
*/
@Overwrite
public boolean timedOut(final long currentTick) {
throw new UnsupportedOperationException();
}
}

View File

@@ -1,260 +0,0 @@
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();
}
}

View File

@@ -1,69 +0,0 @@
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);
}
}

View File

@@ -2,27 +2,18 @@ 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 net.minecraft.world.level.chunk.LevelChunk;
import org.spongepowered.asm.mixin.*;
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.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@@ -93,25 +84,12 @@ abstract class ChunkMapMixin {
((ChunkTickDistanceManager)this.distanceManager).moonrise$removePlayer(player, SectionPos.of(player));
}
/**
* @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);
}
/**
* @reason Use nearby players to avoid iterating over all online players
* @author Spottedleaf
*/
@Overwrite
public boolean anyPlayerCloseEnoughForSpawningInternal(final ChunkPos pos) {
public boolean anyPlayerCloseEnoughForSpawning(final ChunkPos pos) {
final ReferenceList<ServerPlayer> players = ((ChunkSystemServerLevel)this.level).moonrise$getNearbyPlayers().getPlayers(
pos, NearbyPlayers.NearbyMapType.SPAWN_RANGE
);
@@ -165,111 +143,4 @@ 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();
}
}

View File

@@ -4,11 +4,9 @@ import ca.spottedleaf.moonrise.common.misc.PositionCountingAreaMap;
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickConstants;
import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickDistanceManager;
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;
@@ -22,24 +20,20 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
abstract class DistanceManagerMixin implements ChunkTickDistanceManager {
@Shadow
public DistanceManager.FixedPlayerDistanceChunkTracker naturalSpawnChunkCounter;
private 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
@@ -48,18 +42,11 @@ 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
@@ -116,19 +103,7 @@ abstract class DistanceManagerMixin implements ChunkTickDistanceManager {
* @author Spottedleaf
*/
@Overwrite
public TriState hasPlayersNearby(final long pos) {
if (this.narrowSpawnChunkTracker.hasObjectsNear(pos)) {
return TriState.TRUE;
}
return this.spawnChunkTracker.hasObjectsNear(pos) ? TriState.DEFAULT : TriState.FALSE;
}
/**
* @reason Use spawnChunkTracker instead
* @author Spottedleaf
*/
@Overwrite
public LongIterator getSpawnCandidateChunks() {
return this.spawnChunkTracker.getPositions().iterator();
public boolean hasPlayersNearby(final long pos) {
return this.spawnChunkTracker.hasObjectsNear(CoordinateUtils.getChunkX(pos), CoordinateUtils.getChunkZ(pos));
}
}

View File

@@ -1,23 +1,36 @@
package ca.spottedleaf.moonrise.mixin.chunk_tick_iteration;
import ca.spottedleaf.moonrise.common.list.ReferenceList;
import ca.spottedleaf.moonrise.common.util.SimpleThreadUnsafeRandom;
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
import ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer;
import ca.spottedleaf.moonrise.common.misc.NearbyPlayers;
import ca.spottedleaf.moonrise.common.util.SimpleRandom;
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 com.llamalad7.mixinextras.sugar.Local;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
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.GameRules;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.chunk.ChunkSource;
import net.minecraft.world.level.chunk.LevelChunk;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
@@ -29,13 +42,60 @@ abstract class ServerChunkCacheMixin extends ChunkSource {
@Final
public ServerLevel level;
@Shadow
@Final
public ChunkMap chunkMap;
@Unique
private ServerChunkCache.ChunkAndHolder[] iterationCopy;
@Unique
private final SimpleThreadUnsafeRandom shuffleRandom = new SimpleThreadUnsafeRandom(0L);
private int iterationCopyLen;
@Unique
private final SimpleRandom shuffleRandom = new SimpleRandom(0L);
/**
* @reason Avoid creating the list, which is sized at the chunkholder count. The actual number of ticking
* chunks is always lower. The mixin below will initialise the list to non-null.
* @author Spottedleaf
*/
@Redirect(
method = "tickChunks",
at = @At(
value = "INVOKE",
target = "Lcom/google/common/collect/Lists;newArrayListWithCapacity(I)Ljava/util/ArrayList;"
)
)
private <T> ArrayList<T> avoidListCreation(final int initialArraySize) {
return null;
}
/**
* @reason Initialise the list to contain only the ticking chunks.
* @author Spottedleaf
*/
@ModifyVariable(
method = "tickChunks",
at = @At(
value = "STORE",
opcode = Opcodes.ASTORE,
ordinal = 0
)
)
private List<ServerChunkCache.ChunkAndHolder> initTickChunks(final List<ServerChunkCache.ChunkAndHolder> shouldBeNull) {
final ReferenceList<ServerChunkCache.ChunkAndHolder> tickingChunks =
((ChunkTickServerLevel)this.level).moonrise$getPlayerTickingChunks();
final ServerChunkCache.ChunkAndHolder[] raw = tickingChunks.getRawDataUnchecked();
final int size = tickingChunks.size();
if (this.iterationCopy == null || this.iterationCopy.length < size) {
this.iterationCopy = new ServerChunkCache.ChunkAndHolder[raw.length];
}
this.iterationCopyLen = size;
System.arraycopy(raw, 0, this.iterationCopy, 0, size);
return ObjectArrayList.wrap(
this.iterationCopy, size
);
}
/**
* @reason Use random implementation which does not use CAS and has a faster nextInt(int)
@@ -43,7 +103,7 @@ abstract class ServerChunkCacheMixin extends ChunkSource {
* @author Spottedleaf
*/
@Redirect(
method = "tickChunks(Lnet/minecraft/util/profiling/ProfilerFiller;J)V",
method = "tickChunks",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/Util;shuffle(Ljava/util/List;Lnet/minecraft/util/RandomSource;)V"
@@ -55,39 +115,75 @@ abstract class ServerChunkCacheMixin extends ChunkSource {
}
/**
* @reason Do not iterate over entire chunk holder map; additionally perform mid-tick chunk task execution
* @reason Do not initialise ticking chunk list, as we did that above.
* @author Spottedleaf
*/
@Redirect(
method = "tickChunks(Lnet/minecraft/util/profiling/ProfilerFiller;J)V",
method = "tickChunks",
at = @At(
value = "INVOKE",
target = "Ljava/util/Iterator;hasNext()Z",
ordinal = 0
)
)
private <E> boolean skipTickAdd(final Iterator<E> instance) {
return false;
}
/**
* @reason Use the nearby players cache
* @author Spottedleaf
*/
@Redirect(
method = "tickChunks",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/server/level/ChunkMap;forEachBlockTickingChunk(Ljava/util/function/Consumer;)V"
target = "Lnet/minecraft/server/level/ChunkMap;anyPlayerCloseEnoughForSpawning(Lnet/minecraft/world/level/ChunkPos;)Z"
)
)
private void iterateTickingChunksFaster(final ChunkMap instance, final Consumer<LevelChunk> consumer) {
final ServerLevel world = this.level;
final int randomTickSpeed = world.getGameRules().getInt(GameRules.RULE_RANDOMTICKING);
private boolean useNearbyCache(final ChunkMap instance, final ChunkPos chunkPos,
@Local(ordinal = 0, argsOnly = false) 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;
}
// 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();
final ReferenceList<ServerPlayer> players = nearbyPlayers.getPlayers(NearbyPlayers.NearbyMapType.SPAWN_RANGE);
// 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();
if (players == null) {
return false;
}
Objects.checkFromToIndex(0, size, raw.length);
for (int i = 0; i < size; ++i) {
world.tickChunk(raw[i], randomTickSpeed);
final ServerPlayer[] raw = players.getRawDataUnchecked();
final int len = players.size();
// call mid-tick tasks for chunk system
if ((i & 7) == 0) {
((ChunkSystemMinecraftServer)this.level.getServer()).moonrise$executeMidTickTasks();
continue;
Objects.checkFromIndexSize(0, len, raw.length);
for (int i = 0; i < len; ++i) {
if (instance.playerIsCloseEnoughForSpawning(raw[i], chunkPos)) {
return true;
}
}
return false;
}
/**
* @reason Clear the iteration array after the list is done being used.
* @author Spottedleaf
*/
@Inject(
method = "tickChunks",
at = @At(
value = "INVOKE",
target = "Ljava/util/List;forEach(Ljava/util/function/Consumer;)V",
ordinal = 0,
shift = At.Shift.AFTER
)
)
private void broadcastChanges(final CallbackInfo ci) {
Arrays.fill(this.iterationCopy, 0, this.iterationCopyLen, null);
}
}

View File

@@ -19,16 +19,16 @@ import org.spongepowered.asm.mixin.Unique;
abstract class ServerLevelMixin implements ChunkTickServerLevel {
@Unique
private static final LevelChunk[] EMPTY_LEVEL_CHUNKS = new LevelChunk[0];
private static final ServerChunkCache.ChunkAndHolder[] EMPTY_PLAYER_CHUNK_HOLDERS = new ServerChunkCache.ChunkAndHolder[0];
@Unique
private final ReferenceList<LevelChunk> playerTickingChunks = new ReferenceList<>(EMPTY_LEVEL_CHUNKS);
private final ReferenceList<ServerChunkCache.ChunkAndHolder> playerTickingChunks = new ReferenceList<>(EMPTY_PLAYER_CHUNK_HOLDERS);
@Unique
private final Long2IntOpenHashMap playerTickingRequests = new Long2IntOpenHashMap();
@Override
public final ReferenceList<LevelChunk> moonrise$getPlayerTickingChunks() {
public final ReferenceList<ServerChunkCache.ChunkAndHolder> moonrise$getPlayerTickingChunks() {
return this.playerTickingChunks;
}
@@ -39,12 +39,12 @@ abstract class ServerLevelMixin implements ChunkTickServerLevel {
return;
}
this.playerTickingChunks.add(chunk);
this.playerTickingChunks.add(((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder());
}
@Override
public final void moonrise$removeChunkForPlayerTicking(final LevelChunk chunk) {
this.playerTickingChunks.remove(chunk);
this.playerTickingChunks.remove(((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder());
}
@Override
@@ -65,7 +65,9 @@ abstract class ServerLevelMixin implements ChunkTickServerLevel {
return;
}
this.playerTickingChunks.add((LevelChunk)chunkHolder.getCurrentChunk());
this.playerTickingChunks.add(
((ChunkSystemLevelChunk)(LevelChunk)chunkHolder.getCurrentChunk()).moonrise$getChunkAndHolder()
);
}
@Override
@@ -91,6 +93,8 @@ abstract class ServerLevelMixin implements ChunkTickServerLevel {
return;
}
this.playerTickingChunks.remove((LevelChunk)chunkHolder.getCurrentChunk());
this.playerTickingChunks.remove(
((ChunkSystemLevelChunk)(LevelChunk)chunkHolder.getCurrentChunk()).moonrise$getChunkAndHolder()
);
}
}

View File

@@ -6,32 +6,37 @@ import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.decoration.ArmorStand;
import net.minecraft.world.entity.vehicle.AbstractMinecart;
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.AABB;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Shadow;
import java.util.List;
import java.util.function.Predicate;
@Mixin(ArmorStand.class)
abstract class ArmorStandMixin extends LivingEntity {
@Shadow
@Final
private static Predicate<Entity> RIDABLE_MINECARTS;
protected ArmorStandMixin(EntityType<? extends LivingEntity> entityType, Level level) {
super(entityType, level);
}
/**
* @reason Optimise by making it use the class lookup
* @reason Optimise this method by making it use the class lookup
* @author Spottedleaf
*/
@Redirect(
method = "pushEntities",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/level/Level;getEntities(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/phys/AABB;Ljava/util/function/Predicate;)Ljava/util/List;"
)
)
private List<Entity> redirectGetEntities(final Level instance, final Entity entity, final AABB list, final Predicate<? super Entity> arg) {
return (List)this.level().getEntitiesOfClass(AbstractMinecart.class, this.getBoundingBox(), arg);
@Overwrite
public void pushEntities() {
final List<AbstractMinecart> nearby = this.level().getEntitiesOfClass(AbstractMinecart.class, this.getBoundingBox(), RIDABLE_MINECARTS);
for (int i = 0, len = nearby.size(); i < len; ++i) {
final AbstractMinecart minecart = nearby.get(i);
if (this.distanceToSqr(minecart) <= 0.2) {
minecart.push(this);
}
}
}
}

View File

@@ -30,12 +30,6 @@ abstract class BlockStateBaseMixin extends StateHolder<Block, BlockState> implem
@Shadow
public abstract boolean isAir();
@Shadow
public VoxelShape[] occlusionShapesByFace;
@Shadow
public VoxelShape occlusionShape;
protected BlockStateBaseMixin(Block object, Reference2ObjectArrayMap<Property<?>, Comparable<?>> reference2ObjectArrayMap, MapCodec<BlockState> mapCodec) {
super(object, reference2ObjectArrayMap, mapCodec);
}
@@ -76,7 +70,7 @@ abstract class BlockStateBaseMixin extends StateHolder<Block, BlockState> implem
}
if (neighbours) {
for (final Direction direction : DIRECTIONS_CACHED) {
initCaches(((CollisionVoxelShape)shape).moonrise$getFaceShapeClamped(direction), false);
initCaches(Shapes.getFaceShape(shape, direction), false);
initCaches(shape.getFaceShape(direction), false);
}
}
@@ -108,21 +102,17 @@ abstract class BlockStateBaseMixin extends StateHolder<Block, BlockState> implem
if (this.constantCollisionShape != null) {
initCaches(this.constantCollisionShape, true);
}
if (this.cache.occlusionShapes != null) {
for (final VoxelShape shape : this.cache.occlusionShapes) {
initCaches(shape, false);
}
}
} else {
this.occludesFullBlock = false;
this.emptyCollisionShape = false;
this.emptyConstantCollisionShape = false;
this.constantCollisionShape = null;
}
if (this.occlusionShape != null) {
initCaches(this.occlusionShape, true);
}
if (this.occlusionShapesByFace != null) {
for (final VoxelShape shape : this.occlusionShapesByFace) {
initCaches(shape, true);
}
}
}
@Override

View File

@@ -1,16 +1,20 @@
package ca.spottedleaf.moonrise.mixin.collisions;
import ca.spottedleaf.moonrise.common.util.WorldUtil;
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel;
import ca.spottedleaf.moonrise.patches.collisions.CollisionUtil;
import ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState;
import ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape;
import ca.spottedleaf.moonrise.patches.collisions.util.NoneMatchStream;
import it.unimi.dsi.fastutil.floats.FloatArraySet;
import it.unimi.dsi.fastutil.floats.FloatArrays;
import net.minecraft.core.BlockPos;
import net.minecraft.tags.BlockTags;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntityDimensions;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkSource;
import net.minecraft.world.level.chunk.LevelChunkSection;
@@ -23,8 +27,11 @@ 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.ArrayList;
import java.util.List;
import java.util.stream.Stream;
@Mixin(Entity.class)
abstract class EntityMixin {
@@ -50,6 +57,12 @@ abstract class EntityMixin {
@Shadow
private boolean onGround;
@Shadow
public abstract boolean isAlive();
@Shadow
protected abstract void onInsideBlock(final BlockState blockState);
@Unique
private static float[] calculateStepHeights(final AABB box, final List<VoxelShape> voxels, final List<AABB> aabbs, final float stepHeight,
final float collidedY) {
@@ -283,4 +296,163 @@ abstract class EntityMixin {
return false;
}
/**
* @reason Avoid streams for retrieving blocks
* @author Spottedleaf
*/
@Redirect(
method = "move",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/level/Level;getBlockStatesIfLoaded(Lnet/minecraft/world/phys/AABB;)Ljava/util/stream/Stream;",
ordinal = 0
)
)
private <T> Stream<T> avoidStreams(final Level world, final AABB boundingBox) {
final int minBlockX = Mth.floor(boundingBox.minX);
final int minBlockY = Mth.floor(boundingBox.minY);
final int minBlockZ = Mth.floor(boundingBox.minZ);
final int maxBlockX = Mth.floor(boundingBox.maxX);
final int maxBlockY = Mth.floor(boundingBox.maxY);
final int maxBlockZ = Mth.floor(boundingBox.maxZ);
final int minChunkX = minBlockX >> 4;
final int minChunkY = minBlockY >> 4;
final int minChunkZ = minBlockZ >> 4;
final int maxChunkX = maxBlockX >> 4;
final int maxChunkY = maxBlockY >> 4;
final int maxChunkZ = maxBlockZ >> 4;
if (!((ChunkSystemLevel)world).moonrise$areChunksLoaded(minChunkX, minChunkZ, maxChunkX, maxChunkZ)) {
return new NoneMatchStream<>(true);
}
final int minSection = WorldUtil.getMinSection(world);
final ChunkSource chunkSource = world.getChunkSource();
for (int currChunkZ = minChunkZ; currChunkZ <= maxChunkZ; ++currChunkZ) {
for (int currChunkX = minChunkX; currChunkX <= maxChunkX; ++currChunkX) {
final LevelChunkSection[] sections = chunkSource.getChunk(currChunkX, currChunkZ, ChunkStatus.FULL, false).getSections();
for (int currChunkY = minChunkY; currChunkY <= maxChunkY; ++currChunkY) {
final int sectionIdx = currChunkY - minSection;
if (sectionIdx < 0 || sectionIdx >= sections.length) {
continue;
}
final LevelChunkSection section = sections[sectionIdx];
if (section.hasOnlyAir()) {
// empty
continue;
}
final PalettedContainer<BlockState> blocks = section.states;
final int minXIterate = currChunkX == minChunkX ? (minBlockX & 15) : 0;
final int maxXIterate = currChunkX == maxChunkX ? (maxBlockX & 15) : 15;
final int minZIterate = currChunkZ == minChunkZ ? (minBlockZ & 15) : 0;
final int maxZIterate = currChunkZ == maxChunkZ ? (maxBlockZ & 15) : 15;
final int minYIterate = currChunkY == minChunkY ? (minBlockY & 15) : 0;
final int maxYIterate = currChunkY == maxChunkY ? (maxBlockY & 15) : 15;
for (int currY = minYIterate; currY <= maxYIterate; ++currY) {
for (int currZ = minZIterate; currZ <= maxZIterate; ++currZ) {
for (int currX = minXIterate; currX <= maxXIterate; ++currX) {
final BlockState blockState = blocks.get((currX) | (currZ << 4) | ((currY) << 8));
if (blockState.is(Blocks.LAVA) || blockState.is(BlockTags.FIRE)) {
return new NoneMatchStream<>(false);
}
}
}
}
}
}
}
return new NoneMatchStream<>(true);
}
/**
* @reason Retrieve blocks more efficiently
* @author Spottedleaf
*/
@Overwrite
public void checkInsideBlocks() {
final AABB boundingBox = this.getBoundingBox();
final int minBlockX = Mth.floor(boundingBox.minX + CollisionUtil.COLLISION_EPSILON);
final int minBlockY = Mth.floor(boundingBox.minY + CollisionUtil.COLLISION_EPSILON);
final int minBlockZ = Mth.floor(boundingBox.minZ + CollisionUtil.COLLISION_EPSILON);
final int maxBlockX = Mth.floor(boundingBox.maxX - CollisionUtil.COLLISION_EPSILON);
final int maxBlockY = Mth.floor(boundingBox.maxY - CollisionUtil.COLLISION_EPSILON);
final int maxBlockZ = Mth.floor(boundingBox.maxZ - CollisionUtil.COLLISION_EPSILON);
final int minChunkX = minBlockX >> 4;
final int minChunkY = minBlockY >> 4;
final int minChunkZ = minBlockZ >> 4;
final int maxChunkX = maxBlockX >> 4;
final int maxChunkY = maxBlockY >> 4;
final int maxChunkZ = maxBlockZ >> 4;
final Level world = this.level;
if (!((ChunkSystemLevel)world).moonrise$areChunksLoaded(minChunkX, minChunkZ, maxChunkX, maxChunkZ)) {
return;
}
final int minSection = WorldUtil.getMinSection(world);
final ChunkSource chunkSource = world.getChunkSource();
final BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos();
for (int currChunkZ = minChunkZ; currChunkZ <= maxChunkZ; ++currChunkZ) {
for (int currChunkX = minChunkX; currChunkX <= maxChunkX; ++currChunkX) {
final LevelChunkSection[] sections = chunkSource.getChunk(currChunkX, currChunkZ, ChunkStatus.FULL, false).getSections();
for (int currChunkY = minChunkY; currChunkY <= maxChunkY; ++currChunkY) {
final int sectionIdx = currChunkY - minSection;
if (sectionIdx < 0 || sectionIdx >= sections.length) {
continue;
}
final LevelChunkSection section = sections[sectionIdx];
if (section.hasOnlyAir()) {
// empty
continue;
}
final PalettedContainer<BlockState> blocks = section.states;
final int minXIterate = currChunkX == minChunkX ? (minBlockX & 15) : 0;
final int maxXIterate = currChunkX == maxChunkX ? (maxBlockX & 15) : 15;
final int minZIterate = currChunkZ == minChunkZ ? (minBlockZ & 15) : 0;
final int maxZIterate = currChunkZ == maxChunkZ ? (maxBlockZ & 15) : 15;
final int minYIterate = currChunkY == minChunkY ? (minBlockY & 15) : 0;
final int maxYIterate = currChunkY == maxChunkY ? (maxBlockY & 15) : 15;
for (int currY = minYIterate; currY <= maxYIterate; ++currY) {
mutablePos.setY(currY | (currChunkY << 4));
for (int currZ = minZIterate; currZ <= maxZIterate; ++currZ) {
mutablePos.setZ(currZ | (currChunkZ << 4));
for (int currX = minXIterate; currX <= maxXIterate; ++currX) {
mutablePos.setX(currX | (currChunkX << 4));
final BlockState blockState = blocks.get((currX) | (currZ << 4) | ((currY) << 8));
if (!this.isAlive()) {
return;
}
blockState.entityInside(world, mutablePos, (Entity)(Object)this);
this.onInsideBlock(blockState);
}
}
}
}
}
}
}
}

View File

@@ -1,5 +1,6 @@
package ca.spottedleaf.moonrise.mixin.collisions;
import ca.spottedleaf.moonrise.common.PlatformHooks;
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
import ca.spottedleaf.moonrise.patches.getblock.GetBlockChunk;
import ca.spottedleaf.moonrise.patches.collisions.CollisionUtil;
@@ -9,15 +10,20 @@ import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import net.minecraft.core.BlockPos;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.Mth;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.item.PrimedTnt;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Explosion;
import net.minecraft.world.level.ExplosionDamageCalculator;
import net.minecraft.world.level.ServerExplosion;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.gameevent.GameEvent;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
@@ -27,20 +33,33 @@ 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.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Optional;
@Mixin(ServerExplosion.class)
abstract class ServerExplosionMixin {
@Mixin(Explosion.class)
abstract class ExplosionMixin {
@Shadow
@Final
private ServerLevel level;
private Level level;
@Shadow
@Final
private Entity source;
@Shadow
@Final
private double x;
@Shadow
@Final
private double y;
@Shadow
@Final
private double z;
@Shadow
@Final
@@ -50,13 +69,21 @@ abstract class ServerExplosionMixin {
@Final
private float radius;
@Shadow
@Final
private ObjectArrayList<BlockPos> toBlow;
@Shadow
@Final
private Map<Player, Vec3> hitPlayers;
@Shadow
@Final
private boolean fire;
@Shadow
@Final
private Vec3 center;
private DamageSource damageSource;
@Unique
@@ -115,12 +142,6 @@ abstract class ServerExplosionMixin {
@Unique
private LevelChunk[] chunkCache = null;
@Unique
private ExplosionBlockCache[] directMappedBlockCache;
@Unique
private BlockPos.MutableBlockPos mutablePos;
@Unique
private ExplosionBlockCache getOrCacheExplosionBlock(final int x, final int y, final int z,
final long key, final boolean calculateResistance) {
@@ -322,45 +343,29 @@ abstract class ServerExplosionMixin {
return (float)missedRays / (float)totalRays;
}
/**
* @reason Init cache fields
* @author Spottedleaf
*/
@Inject(
method = "explode",
at = @At(
value = "HEAD"
)
)
private void initCacheFields(final CallbackInfo ci) {
this.blockCache = new Long2ObjectOpenHashMap<>();
this.chunkPosCache = new long[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH];
Arrays.fill(this.chunkPosCache, ChunkPos.INVALID_CHUNK_POS);
this.chunkCache = new LevelChunk[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH];
this.directMappedBlockCache = new ExplosionBlockCache[BLOCK_EXPLOSION_CACHE_WIDTH * BLOCK_EXPLOSION_CACHE_WIDTH * BLOCK_EXPLOSION_CACHE_WIDTH];
this.mutablePos = new BlockPos.MutableBlockPos();
}
/**
* @reason Rewrite ray casting for performance
* @reason Rewrite ray casting and seen fraction calculation for performance
* @author Spottedleaf
*/
@Overwrite
public List<BlockPos> calculateExplodedPositions() {
final ObjectArrayList<BlockPos> ret = new ObjectArrayList<>();
public void explode() {
this.level.gameEvent(this.source, GameEvent.EXPLODE, new Vec3(this.x, this.y, this.z));
final Vec3 center = this.center;
this.blockCache = new Long2ObjectOpenHashMap<>();
final ExplosionBlockCache[] blockCache = this.directMappedBlockCache;
this.chunkPosCache = new long[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH];
Arrays.fill(this.chunkPosCache, ChunkPos.INVALID_CHUNK_POS);
this.chunkCache = new LevelChunk[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH];
final ExplosionBlockCache[] blockCache = new ExplosionBlockCache[BLOCK_EXPLOSION_CACHE_WIDTH * BLOCK_EXPLOSION_CACHE_WIDTH * BLOCK_EXPLOSION_CACHE_WIDTH];
// use initial cache value that is most likely to be used: the source position
final ExplosionBlockCache initialCache;
{
final int blockX = Mth.floor(center.x);
final int blockY = Mth.floor(center.y);
final int blockZ = Mth.floor(center.z);
final int blockX = Mth.floor(this.x);
final int blockY = Mth.floor(this.y);
final int blockZ = Mth.floor(this.z);
final long key = BlockPos.asLong(blockX, blockY, blockZ);
@@ -376,9 +381,9 @@ abstract class ServerExplosionMixin {
for (int ray = 0, len = CACHED_RAYS.length; ray < len;) {
ExplosionBlockCache cachedBlock = initialCache;
double currX = center.x;
double currY = center.y;
double currZ = center.z;
double currX = this.x;
double currY = this.y;
double currZ = this.z;
final double incX = CACHED_RAYS[ray];
final double incY = CACHED_RAYS[ray + 1];
@@ -397,7 +402,7 @@ abstract class ServerExplosionMixin {
if (cachedBlock.key != key) {
final int cacheKey =
(blockX & BLOCK_EXPLOSION_CACHE_MASK) |
(blockX & BLOCK_EXPLOSION_CACHE_MASK) |
(blockY & BLOCK_EXPLOSION_CACHE_MASK) << (BLOCK_EXPLOSION_CACHE_SHIFT) |
(blockZ & BLOCK_EXPLOSION_CACHE_MASK) << (BLOCK_EXPLOSION_CACHE_SHIFT + BLOCK_EXPLOSION_CACHE_SHIFT);
cachedBlock = blockCache[cacheKey];
@@ -419,7 +424,7 @@ abstract class ServerExplosionMixin {
cachedBlock.shouldExplode = shouldExplode ? Boolean.TRUE : Boolean.FALSE;
if (shouldExplode) {
if (this.fire || !cachedBlock.blockState.isAir()) {
ret.add(cachedBlock.immutablePos);
this.toBlow.add(cachedBlock.immutablePos);
}
}
}
@@ -431,42 +436,83 @@ abstract class ServerExplosionMixin {
} while (power > 0.0f);
}
return ret;
}
final double diameter = (double)this.radius * 2.0;
final List<Entity> entities = this.level.getEntities(this.source,
new AABB(
(double)Mth.floor(this.x - (diameter + 1.0)),
(double)Mth.floor(this.y - (diameter + 1.0)),
(double)Mth.floor(this.z - (diameter + 1.0)),
/**
* @reason Use optimised getSeenPercent implementation
* @author Spottedleaf
*/
@Redirect(
method = {
"hurtEntities()V",
"hurtEntities(Ljava/util/List;)V" // Neo moves logic into this new method
},
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/level/ServerExplosion;getSeenPercent(Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/entity/Entity;)F"
)
)
private float useBetterSeenPercent(final Vec3 center, final Entity target) {
return this.getSeenFraction(center, target, this.directMappedBlockCache, this.mutablePos);
}
(double)Mth.floor(this.x + (diameter + 1.0)),
(double)Mth.floor(this.y + (diameter + 1.0)),
(double)Mth.floor(this.z + (diameter + 1.0))
)
);
final Vec3 center = new Vec3(this.x, this.y, this.z);
final BlockPos.MutableBlockPos blockPos = new BlockPos.MutableBlockPos();
final PlatformHooks platformHooks = PlatformHooks.get();
platformHooks.onExplosion(this.level, (Explosion)(Object)this, entities, diameter);
for (int i = 0, len = entities.size(); i < len; ++i) {
final Entity entity = entities.get(i);
if (entity.ignoreExplosion((Explosion)(Object)this)) {
continue;
}
final double normalizedDistanceToCenter = Math.sqrt(entity.distanceToSqr(center)) / diameter;
if (normalizedDistanceToCenter > 1.0) {
continue;
}
double distX = entity.getX() - this.x;
double distY = (entity instanceof PrimedTnt ? entity.getY() : entity.getEyeY()) - this.y;
double distZ = entity.getZ() - this.z;
final double distMag = Math.sqrt(distX * distX + distY * distY + distZ * distZ);
if (distMag == 0.0) {
continue;
}
distX /= distMag;
distY /= distMag;
distZ /= distMag;
// route to new visible fraction calculation, using the existing block cache
final double seenFraction = (double)this.getSeenFraction(center, entity, blockCache, blockPos);
if (this.damageCalculator.shouldDamageEntity((Explosion)(Object)this, entity)) {
// inline getEntityDamageAmount so that we can avoid double calling getSeenPercent, which is the MOST
// expensive part of this loop!!!!
final double factor = (1.0 - normalizedDistanceToCenter) * seenFraction;
entity.hurt(this.damageSource, (float)((factor * factor + factor) / 2.0 * 7.0 * diameter + 1.0));
}
final double intensityFraction = (1.0 - normalizedDistanceToCenter) * seenFraction * (double)this.damageCalculator.getKnockbackMultiplier(entity);
final double knockbackFraction;
if (entity instanceof LivingEntity livingEntity) {
knockbackFraction = intensityFraction * (1.0 - livingEntity.getAttributeValue(Attributes.EXPLOSION_KNOCKBACK_RESISTANCE));
} else {
knockbackFraction = intensityFraction;
}
Vec3 knockback = new Vec3(distX * knockbackFraction, distY * knockbackFraction, distZ * knockbackFraction);
knockback = platformHooks.modifyExplosionKnockback(this.level, (Explosion)(Object)this, entity, knockback);
entity.setDeltaMovement(entity.getDeltaMovement().add(knockback));
if (entity instanceof Player player) {
if (!player.isSpectator() && (!player.isCreative() || !player.getAbilities().flying)) {
this.hitPlayers.put(player, knockback);
}
}
entity.onExplosionHit(this.source);
}
/**
* @reason Destroy cache fields
* @author Spottedleaf
*/
@Inject(
method = "explode",
at = @At(
value = "RETURN"
)
)
private void destroyCacheFields(final CallbackInfo ci) {
this.blockCache = null;
this.chunkPosCache = null;
this.chunkCache = null;
this.directMappedBlockCache = null;
this.mutablePos = null;
}
}

View File

@@ -83,7 +83,7 @@ abstract class LevelMixin implements LevelAccessor, AutoCloseable {
final Vec3 to = clipContext.getTo();
final Vec3 from = clipContext.getFrom();
return BlockHitResult.miss(to, Direction.getApproximateNearest(from.x - to.x, from.y - to.y, from.z - to.z), BlockPos.containing(to.x, to.y, to.z));
return BlockHitResult.miss(to, Direction.getNearest(from.x - to.x, from.y - to.y, from.z - to.z), BlockPos.containing(to.x, to.y, to.z));
}
@Unique

View File

@@ -4,7 +4,9 @@ import ca.spottedleaf.moonrise.patches.collisions.CollisionUtil;
import ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape;
import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
import net.minecraft.client.renderer.block.LiquidBlockRenderer;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.phys.shapes.ArrayVoxelShape;
import net.minecraft.world.phys.shapes.BooleanOp;
@@ -21,7 +23,12 @@ abstract class LiquidBlockRendererMixin {
* @author Spottedleaf
*/
@Overwrite
private static boolean isFaceOccludedByState(final Direction direction, final float height, final BlockState state) {
private static boolean isFaceOccludedByState(final BlockGetter world, final Direction direction, final float height,
final BlockPos pos, final BlockState state) {
if (!state.canOcclude()) {
return false;
}
// check for created shape is empty
if (height < (float)CollisionUtil.COLLISION_EPSILON) {
return false;
@@ -43,26 +50,25 @@ abstract class LiquidBlockRendererMixin {
} else {
// the extrusion includes the height
heightShape = new ArrayVoxelShape(
Shapes.block().shape,
CollisionUtil.ZERO_ONE,
DoubleArrayList.wrap(new double[] { 0.0, heightDouble }),
CollisionUtil.ZERO_ONE
Shapes.block().shape,
CollisionUtil.ZERO_ONE,
DoubleArrayList.wrap(new double[] { 0.0, heightDouble }),
CollisionUtil.ZERO_ONE
);
}
final VoxelShape occlusionShape = ((CollisionVoxelShape)state.getFaceOcclusionShape(direction.getOpposite()))
.moonrise$getFaceShapeClamped(direction.getOpposite());
final VoxelShape stateShape = ((CollisionVoxelShape)state.getOcclusionShape(world, pos)).moonrise$getFaceShapeClamped(direction.getOpposite());
if (occlusionShape.isEmpty()) {
if (stateShape.isEmpty()) {
// cannot occlude
return false;
}
// fast check for box
if (heightShape == occlusionShape) {
if (heightShape == stateShape) {
return true;
}
return !Shapes.joinIsNotEmpty(heightShape, occlusionShape, BooleanOp.ONLY_FIRST);
return !Shapes.joinIsNotEmpty(heightShape, stateShape, BooleanOp.ONLY_FIRST);
}
}

View File

@@ -0,0 +1,55 @@
package ca.spottedleaf.moonrise.mixin.collisions;
import net.minecraft.world.entity.Attackable;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.EntitySelector;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.Level;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
import org.spongepowered.asm.mixin.Shadow;
import java.util.List;
@Mixin(LivingEntity.class)
abstract class LivingEntityMixin extends Entity implements Attackable {
@Shadow
protected abstract void doPush(Entity entity);
public LivingEntityMixin(EntityType<?> entityType, Level level) {
super(entityType, level);
}
/**
* @reason Optimise this method
* @author Spottedleaf
*/
@Overwrite
public void pushEntities() {
if (this.level().isClientSide()) {
final List<Player> players = this.level().getEntitiesOfClass(Player.class, this.getBoundingBox(), EntitySelector.pushableBy(this));
for (int i = 0, len = players.size(); i < len; ++i) {
this.doPush(players.get(i));
}
} else {
final List<Entity> nearby = this.level().getEntities(this, this.getBoundingBox(), EntitySelector.pushableBy(this));
// only iterate ONCE
int nonPassengers = 0;
for (int i = 0, len = nearby.size(); i < len; ++i) {
final Entity entity = nearby.get(i);
nonPassengers += (entity.isPassenger() ? 0 : 1);
this.doPush(entity);
}
int maxCramming;
if (nonPassengers != 0 && (maxCramming = this.level().getGameRules().getInt(GameRules.RULE_MAX_ENTITY_CRAMMING)) > 0
&& nonPassengers > (maxCramming - 1) && this.random.nextInt(4) == 0) {
this.hurt(this.damageSources().cramming(), 6.0F);
}
}
}
}

View File

@@ -79,7 +79,8 @@ abstract class ParticleMixin {
final List<VoxelShape> voxels = new ArrayList<>();
final boolean collided = CollisionUtil.getCollisionsForBlocksOrWorldBorder(
world, entity, collisionBox, voxels, boxes,
0, null
0,
null
);
if (!collided) {

View File

@@ -278,6 +278,15 @@ abstract class ShapesMixin {
return ret;
}
/**
* @reason Route to use cache
* @author Spottedleaf
*/
@Overwrite
public static VoxelShape getFaceShape(final VoxelShape shape, final Direction direction) {
return ((CollisionVoxelShape)shape).moonrise$getFaceShapeClamped(direction);
}
@Unique
private static boolean mergedMayOccludeBlock(final VoxelShape shape1, final VoxelShape shape2) {
// if the combined bounds of the two shapes cannot occlude, then neither can the merged
@@ -345,8 +354,11 @@ abstract class ShapesMixin {
* @author Spottedleaf
*/
@Overwrite
public static boolean blockOccludes(final VoxelShape first, final VoxelShape second, final Direction direction) {
if (first == BLOCK & second == BLOCK) {
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) {
return true;
}

View File

@@ -1,7 +1,9 @@
package ca.spottedleaf.moonrise.mixin.collisions;
import ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape;
import net.minecraft.core.Direction;
import net.minecraft.world.phys.shapes.SliceShape;
import net.minecraft.world.phys.shapes.VoxelShape;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
@@ -20,7 +22,7 @@ abstract class SliceShapeMixin {
value = "RETURN"
)
)
private void initState(final CallbackInfo ci) {
private void initState(final VoxelShape parent, final Direction.Axis forAxis, final int forIndex, final CallbackInfo ci) {
((CollisionVoxelShape)this).moonrise$initCache();
}
}

View File

@@ -378,19 +378,19 @@ abstract class VoxelShapeMixin implements CollisionVoxelShape {
case X: {
final double[] values = this.rootCoordinatesX;
return CollisionUtil.findFloor(
values, this.offsetX, value, 0, values.length - 1
values, value - this.offsetX, 0, values.length - 1
);
}
case Y: {
final double[] values = this.rootCoordinatesY;
return CollisionUtil.findFloor(
values, this.offsetY, value, 0, values.length - 1
values, value - this.offsetY, 0, values.length - 1
);
}
case Z: {
final double[] values = this.rootCoordinatesZ;
return CollisionUtil.findFloor(
values, this.offsetZ, value, 0, values.length - 1
values, value - this.offsetZ, 0, values.length - 1
);
}
default: {
@@ -411,7 +411,7 @@ abstract class VoxelShapeMixin implements CollisionVoxelShape {
// see findIndex
final int index = CollisionUtil.findFloor(
coords, offset, (positiveDir ? (1.0 - CollisionUtil.COLLISION_EPSILON) : (0.0 + CollisionUtil.COLLISION_EPSILON)),
coords, (positiveDir ? (1.0 - CollisionUtil.COLLISION_EPSILON) : (0.0 + CollisionUtil.COLLISION_EPSILON)) - offset,
0, coords.length - 1
);
@@ -687,13 +687,13 @@ abstract class VoxelShapeMixin implements CollisionVoxelShape {
final AABB singleAABB = this.singleAABBRepresentation;
if (singleAABB != null) {
if (singleAABB.contains(fromBehindOffsetX, fromBehindOffsetY, fromBehindOffsetZ)) {
return new BlockHitResult(fromBehind, Direction.getApproximateNearest(directionOpposite.x, directionOpposite.y, directionOpposite.z).getOpposite(), offset, true);
return new BlockHitResult(fromBehind, Direction.getNearest(directionOpposite.x, directionOpposite.y, directionOpposite.z).getOpposite(), offset, true);
}
return clip(singleAABB, from, to, offset);
}
if (CollisionUtil.strictlyContains((VoxelShape)(Object)this, fromBehindOffsetX, fromBehindOffsetY, fromBehindOffsetZ)) {
return new BlockHitResult(fromBehind, Direction.getApproximateNearest(directionOpposite.x, directionOpposite.y, directionOpposite.z).getOpposite(), offset, true);
return new BlockHitResult(fromBehind, Direction.getNearest(directionOpposite.x, directionOpposite.y, directionOpposite.z).getOpposite(), offset, true);
}
return AABB.clip(((VoxelShape)(Object)this).toAabbs(), from, to, offset);

View File

@@ -1,6 +1,5 @@
package ca.spottedleaf.moonrise.mixin.entity_tracker;
import ca.spottedleaf.moonrise.common.PlatformHooks;
import ca.spottedleaf.moonrise.common.list.ReferenceList;
import ca.spottedleaf.moonrise.common.misc.NearbyPlayers;
import ca.spottedleaf.moonrise.common.util.TickThread;
@@ -145,8 +144,8 @@ abstract class TrackedEntityMixin implements EntityTrackerTrackedEntity {
*/
@Overwrite
public int getEffectiveRange() {
final Entity entity = this.entity;
int range = this.range;
final Entity entity = this.entity;
if (entity.getPassengers() == ImmutableList.<Entity>of()) {
return this.scaledRange(range);
@@ -155,9 +154,8 @@ abstract class TrackedEntityMixin implements EntityTrackerTrackedEntity {
// note: we change to List
final List<Entity> passengers = (List<Entity>)entity.getIndirectPassengers();
for (int i = 0, len = passengers.size(); i < len; ++i) {
final Entity passenger = passengers.get(i);
// note: max should be branchless
range = Math.max(range, PlatformHooks.get().modifyEntityTrackingRange(passenger, passenger.getType().clientTrackingRange() << 4));
range = Math.max(range, passengers.get(i).getType().clientTrackingRange() << 4);
}
return this.scaledRange(range);

View File

@@ -24,7 +24,7 @@ abstract class PalettedContainerMixin<T> implements PaletteResize<T>, PalettedCo
private void updateData(final PalettedContainer.Data<T> data) {
if (data != null) {
((FastPaletteData<T>)(Object)data).moonrise$setPalette(
((FastPalette<T>)data.palette()).moonrise$getRawPalette((FastPaletteData<T>)(Object)data)
((FastPalette<T>)data.palette).moonrise$getRawPalette((FastPaletteData<T>)(Object)data)
);
}
}
@@ -80,7 +80,7 @@ abstract class PalettedContainerMixin<T> implements PaletteResize<T>, PalettedCo
@Unique
private T readPaletteSlow(final PalettedContainer.Data<T> data, final int paletteIdx) {
return data.palette().valueFor(paletteIdx);
return data.palette.valueFor(paletteIdx);
}
@Unique
@@ -103,9 +103,9 @@ abstract class PalettedContainerMixin<T> implements PaletteResize<T>, PalettedCo
*/
@Overwrite
public T getAndSet(final int index, final T value) {
final int paletteIdx = this.data.palette().idFor(value);
final int paletteIdx = this.data.palette.idFor(value);
final PalettedContainer.Data<T> data = this.data;
final int prev = data.storage().getAndSet(index, paletteIdx);
final int prev = data.storage.getAndSet(index, paletteIdx);
return this.readPalette(data, prev);
}
@@ -116,6 +116,6 @@ abstract class PalettedContainerMixin<T> implements PaletteResize<T>, PalettedCo
@Overwrite
public T get(final int index) {
final PalettedContainer.Data<T> data = this.data;
return this.readPalette(data, data.storage().get(index));
return this.readPalette(data, data.storage.get(index));
}
}

View File

@@ -114,16 +114,16 @@ abstract class FlowingFluidMixin extends Fluid {
private static final int COLLISION_OCCLUSION_CACHE_SIZE = 2048;
@Unique
private static final ThreadLocal<FluidOcclusionCacheKey[]> COLLISION_OCCLUSION_CACHE = ThreadLocal.withInitial(() -> new FluidOcclusionCacheKey[COLLISION_OCCLUSION_CACHE_SIZE]);
private static final FluidOcclusionCacheKey[] COLLISION_OCCLUSION_CACHE = new FluidOcclusionCacheKey[COLLISION_OCCLUSION_CACHE_SIZE];
/**
* @reason Try to avoid going to the cache for simple cases; additionally use better caching strategy
* @author Spottedleaf
*/
@Overwrite
public static boolean canPassThroughWall(final Direction direction, final BlockGetter level,
final BlockPos fromPos, final BlockState fromState,
final BlockPos toPos, final BlockState toState) {
private boolean canPassThroughWall(final Direction direction, final BlockGetter level,
final BlockPos fromPos, final BlockState fromState,
final BlockPos toPos, final BlockState toState) {
if (((CollisionBlockState)fromState).moonrise$emptyCollisionShape() & ((CollisionBlockState)toState).moonrise$emptyCollisionShape()) {
// don't even try to cache simple cases
return true;
@@ -135,7 +135,7 @@ abstract class FlowingFluidMixin extends Fluid {
}
final FluidOcclusionCacheKey[] cache = ((CollisionBlockState)fromState).moonrise$hasCache() & ((CollisionBlockState)toState).moonrise$hasCache() ?
COLLISION_OCCLUSION_CACHE.get() : null;
COLLISION_OCCLUSION_CACHE : null;
final int keyIndex
= (((CollisionBlockState)fromState).moonrise$uniqueId1() ^ ((CollisionBlockState)toState).moonrise$uniqueId2() ^ ((CollisionDirection)(Object)direction).moonrise$uniqueId())

View File

@@ -42,7 +42,7 @@ abstract class FluidStateMixin extends StateHolder<Fluid, FluidState> implements
private BlockState legacyBlock;
@Override
public final void moonrise$initCaches() {
public void moonrise$initCaches() {
this.amount = this.getType().getAmount((FluidState)(Object)this);
this.isEmpty = this.getType().isEmpty();
this.isSource = this.getType().isSource((FluidState)(Object)this);

View File

@@ -29,9 +29,9 @@ abstract class MappedRegistryMixin<T> {
final RegistrationInfo registrationInfo,
final CallbackInfoReturnable<Holder.Reference<T>> cir
) {
if (resourceKey.registryKey() == (Object)Registries.FLUID) {
for (final FluidState possibleState : ((Fluid)object).getStateDefinition().getPossibleStates()) {
((FluidFluidState)(Object)possibleState).moonrise$initCaches();
if (resourceKey.registryKey() == (Object) Registries.FLUID) {
for (final FluidState possibleState : ((Fluid) object).getStateDefinition().getPossibleStates()) {
((FluidFluidState) (Object) possibleState).moonrise$initCaches();
}
}
}

View File

@@ -16,20 +16,20 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(value = Level.class, priority = 1100)
abstract class LevelMixin implements LevelAccessor, AutoCloseable {
@Unique
private int minY;
@Unique
private int height;
@Unique
private int maxY;
private int minBuildHeight;
@Unique
private int minSectionY;
private int maxBuildHeight;
@Unique
private int maxSectionY;
private int minSection;
@Unique
private int maxSection;
@Unique
private int sectionsCount;
@@ -47,17 +47,12 @@ abstract class LevelMixin implements LevelAccessor, AutoCloseable {
private void init(final CallbackInfo ci,
@Local(ordinal = 0, argsOnly = true) final Holder<DimensionType> dimensionTypeHolder) {
final DimensionType dimType = dimensionTypeHolder.value();
this.minY = dimType.minY();
this.height = dimType.height();
this.maxY = this.minY + this.height - 1;
this.minSectionY = this.minY >> 4;
this.maxSectionY = this.maxY >> 4;
this.sectionsCount = this.maxSectionY - this.minSectionY + 1;
}
@Override
public int getMinY() {
return this.minY;
this.minBuildHeight = dimType.minY();
this.maxBuildHeight = this.minBuildHeight + this.height;
this.minSection = this.minBuildHeight >> 4;
this.maxSection = ((this.maxBuildHeight - 1) >> 4) + 1;
this.sectionsCount = this.maxSection - this.minSection;
}
@Override
@@ -66,52 +61,52 @@ abstract class LevelMixin implements LevelAccessor, AutoCloseable {
}
@Override
public int getMaxY() {
return this.maxY;
public int getMinBuildHeight() {
return this.minBuildHeight;
}
@Override
public int getMaxBuildHeight() {
return this.maxBuildHeight;
}
@Override
public int getMinSection() {
return this.minSection;
}
@Override
public int getMaxSection() {
return this.maxSection;
}
@Override
public boolean isOutsideBuildHeight(final int y) {
return y < this.minBuildHeight || y >= this.maxBuildHeight;
}
@Override
public boolean isOutsideBuildHeight(final BlockPos blockPos) {
return this.isOutsideBuildHeight(blockPos.getY());
}
@Override
public int getSectionIndex(final int blockY) {
return (blockY >> 4) - this.minSection;
}
@Override
public int getSectionIndexFromSectionY(final int sectionY) {
return sectionY - this.minSection;
}
@Override
public int getSectionYFromSectionIndex(final int sectionIdx) {
return sectionIdx + this.minSection;
}
@Override
public int getSectionsCount() {
return this.sectionsCount;
}
@Override
public int getMinSectionY() {
return this.minSectionY;
}
@Override
public int getMaxSectionY() {
return this.maxSectionY;
}
@Override
public boolean isInsideBuildHeight(final int blockY) {
return blockY >= this.minY && blockY <= this.maxY;
}
@Override
public boolean isOutsideBuildHeight(final BlockPos pos) {
return this.isOutsideBuildHeight(pos.getY());
}
@Override
public boolean isOutsideBuildHeight(final int blockY) {
return blockY < this.minY || blockY > this.maxY;
}
@Override
public int getSectionIndex(final int blockY) {
return (blockY >> 4) - this.minSectionY;
}
@Override
public int getSectionIndexFromSectionY(final int sectionY) {
return sectionY - this.minSectionY;
}
@Override
public int getSectionYFromSectionIndex(final int sectionIdx) {
return sectionIdx + this.minSectionY;
}
}

View File

@@ -24,8 +24,8 @@ abstract class AcquirePoiMixin {
*/
@Redirect(
method = {
"lambda$create$8",
"method_46885"
"method_46885",
"*(ZLorg/apache/commons/lang3/mutable/MutableLong;Lit/unimi/dsi/fastutil/longs/Long2ObjectMap;Ljava/util/function/Predicate;Lnet/minecraft/world/entity/ai/behavior/declarative/MemoryAccessor;Ljava/util/Optional;Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/PathfinderMob;J)Z"
},
at = @At(
target = "Lnet/minecraft/world/entity/ai/village/poi/PoiManager;findAllClosestFirstWithType(Ljava/util/function/Predicate;Ljava/util/function/Predicate;Lnet/minecraft/core/BlockPos;ILnet/minecraft/world/entity/ai/village/poi/PoiManager$Occupancy;)Ljava/util/stream/Stream;",
@@ -33,9 +33,9 @@ abstract class AcquirePoiMixin {
ordinal = 0
)
)
private static Stream<Pair<Holder<PoiType>, BlockPos>> useLimitedSearch(PoiManager poiManager, Predicate<Holder<PoiType>> predicate,
Predicate<BlockPos> predicate2, BlockPos blockPos, int i,
PoiManager.Occupancy occup) {
private static Stream<Pair<Holder<PoiType>, BlockPos>> aaa(PoiManager poiManager, Predicate<Holder<PoiType>> predicate,
Predicate<BlockPos> predicate2, BlockPos blockPos, int i,
PoiManager.Occupancy occup) {
final List<Pair<Holder<PoiType>, BlockPos>> ret = new ArrayList<>();
PoiAccess.findNearestPoiPositions(

View File

@@ -20,17 +20,16 @@ import org.spongepowered.asm.mixin.Overwrite;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.BiFunction;
import java.util.function.BiPredicate;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Stream;
@Mixin(PoiManager.class)
abstract class PoiManagerMixin extends SectionStorage<PoiSection, PoiSection.Packed> {
abstract class PoiManagerMixin extends SectionStorage<PoiSection> {
public PoiManagerMixin(final SimpleRegionStorage simpleRegionStorage, final Codec<PoiSection.Packed> codec, final Function<PoiSection, PoiSection.Packed> function, final BiFunction<PoiSection.Packed, Runnable, PoiSection> biFunction, final Function<Runnable, PoiSection> function2, final RegistryAccess registryAccess, final ChunkIOErrorReporter chunkIOErrorReporter, final LevelHeightAccessor levelHeightAccessor) {
super(simpleRegionStorage, codec, function, biFunction, function2, registryAccess, chunkIOErrorReporter, levelHeightAccessor);
public PoiManagerMixin(SimpleRegionStorage simpleRegionStorage, Function<Runnable, Codec<PoiSection>> function, Function<Runnable, PoiSection> function2, RegistryAccess registryAccess, ChunkIOErrorReporter chunkIOErrorReporter, LevelHeightAccessor levelHeightAccessor) {
super(simpleRegionStorage, function, function2, registryAccess, chunkIOErrorReporter, levelHeightAccessor);
}
/**

View File

@@ -49,7 +49,7 @@ abstract class MinecraftMixin extends ReentrantBlockableEventLoop<Runnable> impl
return;
}
cir.setReturnValue(ret == null || ret == InactiveProfiler.INSTANCE ? this.leafProfiler : ProfilerFiller.combine(this.leafProfiler, ret));
cir.setReturnValue(ret == null || ret == InactiveProfiler.INSTANCE ? this.leafProfiler : ProfilerFiller.tee(this.leafProfiler, ret));
}
/**

View File

@@ -1,28 +0,0 @@
package ca.spottedleaf.moonrise.mixin.random;
import ca.spottedleaf.moonrise.common.util.ThreadUnsafeRandom;
import net.minecraft.util.RandomSource;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.levelgen.RandomSupport;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(Entity.class)
abstract class EntityMixin {
/**
* @reason Changes Entity#random to use ThreadUnsafeRandom, skipping the thread checks and CAS logic
* @author Spottedleadf
*/
@Redirect(
method = "<init>",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/util/RandomSource;create()Lnet/minecraft/util/RandomSource;"
)
)
private RandomSource redirectEntityRandom() {
return new ThreadUnsafeRandom(RandomSupport.generateUniqueSeed());
}
}

Some files were not shown because too many files have changed in this diff Show More