Compare commits
32 Commits
v0.3.0-bet
...
v0.1.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6841805446 | ||
|
|
eb20846213 | ||
|
|
66a0850ac9 | ||
|
|
9a16a91fb8 | ||
|
|
580041a1a1 | ||
|
|
fb31d0e1f7 | ||
|
|
0b2070d781 | ||
|
|
30a79469e3 | ||
|
|
254b331259 | ||
|
|
a21c44ad31 | ||
|
|
77ba4a4584 | ||
|
|
a510acbd78 | ||
|
|
6fdc3cb1df | ||
|
|
04e2b976ac | ||
|
|
bd938e6e35 | ||
|
|
3624d261f8 | ||
|
|
6c75d6935e | ||
|
|
e40c40613d | ||
|
|
84e7106762 | ||
|
|
0218cb5979 | ||
|
|
7d0d5a56dd | ||
|
|
4597f04a6d | ||
|
|
20764890a7 | ||
|
|
f719abdb64 | ||
|
|
0dce47bba6 | ||
|
|
47584ceee1 | ||
|
|
2fc858a683 | ||
|
|
68ea18bc51 | ||
|
|
9944946b29 | ||
|
|
ec1120ed10 | ||
|
|
8040c7a264 | ||
|
|
a9e36795e5 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -116,6 +116,3 @@ run/
|
||||
|
||||
# Avoid ignoring Gradle wrapper jar file (.jar files are usually ignored)
|
||||
!gradle-wrapper.jar
|
||||
|
||||
ConcurrentUtil/
|
||||
YamlConfig/
|
||||
|
||||
@@ -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 |
|
||||
|
||||
120
build.gradle
120
build.gradle
@@ -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
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
import org.gradle.api.provider.MapProperty;
|
||||
|
||||
public abstract class RunConfigCommon {
|
||||
public abstract MapProperty<String, String> getSystemProperties();
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
},
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -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
3
gradlew
vendored
@@ -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
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
1
neoforge/gradle.properties
Normal file
1
neoforge/gradle.properties
Normal file
@@ -0,0 +1 @@
|
||||
loom.platform=neoforge
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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": [
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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() {}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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() {}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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('}');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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('}');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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) {}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -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()));
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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];
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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())
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user