Compare commits
36 Commits
v0.2.0-bet
...
mc/1.21.6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a33ac1dc01 | ||
|
|
da21aeca85 | ||
|
|
694dab69c0 | ||
|
|
0764327cba | ||
|
|
724b8ef20a | ||
|
|
0ea5e4dcf5 | ||
|
|
1f8e863c4b | ||
|
|
9d58071cf5 | ||
|
|
303d763167 | ||
|
|
9e3a55f7bc | ||
|
|
aef2b81d6e | ||
|
|
0451444abf | ||
|
|
9a4078966d | ||
|
|
b2a7a92c74 | ||
|
|
30b011246c | ||
|
|
91455be558 | ||
|
|
41ccbb2611 | ||
|
|
b312be2921 | ||
|
|
b15e8398e7 | ||
|
|
b6410354e5 | ||
|
|
85ca21eb28 | ||
|
|
bda7cfaad9 | ||
|
|
fece86b279 | ||
|
|
27759719e9 | ||
|
|
13948cdf26 | ||
|
|
ac0c7deb43 | ||
|
|
16c8398d8a | ||
|
|
661ef813bb | ||
|
|
cf1d26a73c | ||
|
|
0cbff02a1c | ||
|
|
ce4ee767fe | ||
|
|
d31b15122f | ||
|
|
ca931e842b | ||
|
|
c2cf985899 | ||
|
|
d270cf06d9 | ||
|
|
09735958c0 |
@@ -68,19 +68,19 @@ allprojects {
|
|||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
maven {
|
maven {
|
||||||
url "https://repo.papermc.io/repository/maven-public/"
|
url = "https://repo.papermc.io/repository/maven-public/"
|
||||||
mavenContent {
|
mavenContent {
|
||||||
includeGroup("ca.spottedleaf")
|
includeGroup("ca.spottedleaf")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
maven {
|
maven {
|
||||||
url "https://api.modrinth.com/maven"
|
url = "https://api.modrinth.com/maven"
|
||||||
mavenContent {
|
mavenContent {
|
||||||
includeGroup("maven.modrinth")
|
includeGroup("maven.modrinth")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
maven { url "https://maven.shedaniel.me/" }
|
maven { url = "https://maven.shedaniel.me/" }
|
||||||
maven { url "https://maven.terraformersmc.com/releases/" }
|
maven { url = "https://maven.terraformersmc.com/releases/" }
|
||||||
}
|
}
|
||||||
|
|
||||||
// make build reproducible
|
// make build reproducible
|
||||||
|
|||||||
@@ -2,11 +2,17 @@ import dev.architectury.at.AccessChange;
|
|||||||
import dev.architectury.at.AccessTransform;
|
import dev.architectury.at.AccessTransform;
|
||||||
import dev.architectury.at.AccessTransformSet;
|
import dev.architectury.at.AccessTransformSet;
|
||||||
import dev.architectury.at.ModifierChange;
|
import dev.architectury.at.ModifierChange;
|
||||||
|
import dev.architectury.at.io.AccessTransformFormat;
|
||||||
import dev.architectury.at.io.AccessTransformFormats;
|
import dev.architectury.at.io.AccessTransformFormats;
|
||||||
import java.io.BufferedReader;
|
import java.io.BufferedReader;
|
||||||
|
import java.io.BufferedWriter;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.StringWriter;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import net.fabricmc.accesswidener.AccessWidenerReader;
|
import net.fabricmc.accesswidener.AccessWidenerReader;
|
||||||
import net.fabricmc.accesswidener.AccessWidenerVisitor;
|
import net.fabricmc.accesswidener.AccessWidenerVisitor;
|
||||||
@@ -66,12 +72,29 @@ public abstract class Aw2AtTask extends DefaultTask {
|
|||||||
final AccessTransformSet accessTransformSet = toAccessTransformSet(reader);
|
final AccessTransformSet accessTransformSet = toAccessTransformSet(reader);
|
||||||
Files.deleteIfExists(this.getOutputFile().get().getAsFile().toPath());
|
Files.deleteIfExists(this.getOutputFile().get().getAsFile().toPath());
|
||||||
Files.createDirectories(this.getOutputFile().get().getAsFile().toPath().getParent());
|
Files.createDirectories(this.getOutputFile().get().getAsFile().toPath().getParent());
|
||||||
AccessTransformFormats.FML.write(this.getOutputFile().get().getAsFile().toPath(), accessTransformSet);
|
writeLF(AccessTransformFormats.FML, this.getOutputFile().get().getAsFile().toPath(), accessTransformSet);
|
||||||
} catch (final IOException e) {
|
} catch (final IOException e) {
|
||||||
throw new RuntimeException(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)
|
// Below methods are heavily based on architectury-loom Aw2At class (MIT licensed)
|
||||||
/*
|
/*
|
||||||
MIT License
|
MIT License
|
||||||
@@ -98,8 +121,7 @@ public abstract class Aw2AtTask extends DefaultTask {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
public static AccessTransformSet toAccessTransformSet(final BufferedReader reader) throws IOException {
|
public static AccessTransformSet toAccessTransformSet(final BufferedReader reader) throws IOException {
|
||||||
// TODO: Remove copied classes once https://github.com/architectury/at/pull/1 is released
|
AccessTransformSet atSet = AccessTransformSet.create();
|
||||||
AccessTransformSet atSet = new at.AccessTransformSetImpl();
|
|
||||||
|
|
||||||
new AccessWidenerReader(new AccessWidenerVisitor() {
|
new AccessWidenerReader(new AccessWidenerVisitor() {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,97 +0,0 @@
|
|||||||
/*
|
|
||||||
* The MIT License (MIT)
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023 Architectury
|
|
||||||
* Copyright (c) 2018 Minecrell (https://github.com/Minecrell)
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package at;
|
|
||||||
|
|
||||||
import dev.architectury.at.AccessTransformSet;
|
|
||||||
import net.fabricmc.mappingio.tree.MappingTreeView;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
public class AccessTransformSetImpl implements AccessTransformSet {
|
|
||||||
|
|
||||||
private final Map<String, Class> classes = new LinkedHashMap<>();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, Class> getClasses() {
|
|
||||||
return Collections.unmodifiableMap(this.classes);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Class> getClass(String name) {
|
|
||||||
Objects.requireNonNull(name, "name");
|
|
||||||
return Optional.ofNullable(this.classes.get(name.replace('.', '/')));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Class getOrCreateClass(String name) {
|
|
||||||
Objects.requireNonNull(name, "name");
|
|
||||||
return this.classes.computeIfAbsent(name.replace('.', '/'), n -> new ClassAccessTransformSetImpl(this, n));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Optional<Class> removeClass(String name) {
|
|
||||||
Objects.requireNonNull(name, "name");
|
|
||||||
return Optional.ofNullable(this.classes.remove(name.replace('.', '/')));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AccessTransformSet remap(MappingTreeView mappings, String from, String to) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void merge(AccessTransformSet other) {
|
|
||||||
other.getClasses().forEach((name, classSet) -> getOrCreateClass(name).merge(classSet));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!(o instanceof AccessTransformSetImpl)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
AccessTransformSetImpl that = (AccessTransformSetImpl) o;
|
|
||||||
return this.classes.equals(that.classes);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return this.classes.hashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "AccessTransformSet{" + classes + '}';
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,256 +0,0 @@
|
|||||||
/*
|
|
||||||
* The MIT License (MIT)
|
|
||||||
*
|
|
||||||
* Copyright (c) 2023 Architectury
|
|
||||||
* Copyright (c) 2018 Minecrell (https://github.com/Minecrell)
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package at;
|
|
||||||
|
|
||||||
import dev.architectury.at.AccessTransform;
|
|
||||||
import dev.architectury.at.AccessTransformSet;
|
|
||||||
import org.cadixdev.bombe.analysis.InheritanceProvider;
|
|
||||||
import org.cadixdev.bombe.type.signature.MethodSignature;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.StringJoiner;
|
|
||||||
|
|
||||||
class ClassAccessTransformSetImpl implements AccessTransformSet.Class {
|
|
||||||
|
|
||||||
private final AccessTransformSet parent;
|
|
||||||
private final String name;
|
|
||||||
|
|
||||||
private AccessTransform classTransform = AccessTransform.EMPTY;
|
|
||||||
private AccessTransform allFields = AccessTransform.EMPTY;
|
|
||||||
private AccessTransform allMethods = AccessTransform.EMPTY;
|
|
||||||
|
|
||||||
private final Map<String, AccessTransform> fields = new LinkedHashMap<>();
|
|
||||||
private final Map<MethodSignature, AccessTransform> methods = new LinkedHashMap<>();
|
|
||||||
|
|
||||||
private boolean complete;
|
|
||||||
|
|
||||||
ClassAccessTransformSetImpl(AccessTransformSet parent, String name) {
|
|
||||||
this.parent = parent;
|
|
||||||
this.name = name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AccessTransformSet getParent() {
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getName() {
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AccessTransform get() {
|
|
||||||
return this.classTransform;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AccessTransform merge(AccessTransform transform) {
|
|
||||||
return this.classTransform = this.classTransform.merge(transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AccessTransform replace(AccessTransform transform) {
|
|
||||||
return this.classTransform = Objects.requireNonNull(transform, "transform");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AccessTransform allFields() {
|
|
||||||
return this.allFields;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AccessTransform mergeAllFields(AccessTransform transform) {
|
|
||||||
return this.allFields = this.allFields.merge(transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AccessTransform replaceAllFields(AccessTransform transform) {
|
|
||||||
return this.allFields = Objects.requireNonNull(transform, "transform");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AccessTransform allMethods() {
|
|
||||||
return this.allMethods;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AccessTransform mergeAllMethods(AccessTransform transform) {
|
|
||||||
return this.allMethods = this.allMethods.merge(transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AccessTransform replaceAllMethods(AccessTransform transform) {
|
|
||||||
return this.allMethods = Objects.requireNonNull(transform, "transform");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, AccessTransform> getFields() {
|
|
||||||
return Collections.unmodifiableMap(this.fields);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AccessTransform getField(String name) {
|
|
||||||
return this.fields.getOrDefault(Objects.requireNonNull(name, "name"), this.allFields);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AccessTransform mergeField(String name, AccessTransform transform) {
|
|
||||||
Objects.requireNonNull(name, "name");
|
|
||||||
Objects.requireNonNull(transform, "transform");
|
|
||||||
|
|
||||||
if (transform.isEmpty()) {
|
|
||||||
return this.fields.getOrDefault(name, AccessTransform.EMPTY);
|
|
||||||
}
|
|
||||||
return this.fields.merge(name, transform, AccessTransform::merge);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AccessTransform replaceField(String name, AccessTransform transform) {
|
|
||||||
Objects.requireNonNull(name, "name");
|
|
||||||
Objects.requireNonNull(transform, "transform");
|
|
||||||
|
|
||||||
if (transform.isEmpty()) {
|
|
||||||
return this.fields.remove(name);
|
|
||||||
}
|
|
||||||
return this.fields.put(name, transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<MethodSignature, AccessTransform> getMethods() {
|
|
||||||
return Collections.unmodifiableMap(this.methods);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AccessTransform getMethod(MethodSignature signature) {
|
|
||||||
return this.methods.getOrDefault(Objects.requireNonNull(signature, "signature"), this.allMethods);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AccessTransform mergeMethod(MethodSignature signature, AccessTransform transform) {
|
|
||||||
Objects.requireNonNull(signature, "signature");
|
|
||||||
Objects.requireNonNull(transform, "transform");
|
|
||||||
|
|
||||||
if (transform.isEmpty()) {
|
|
||||||
return this.methods.getOrDefault(signature, AccessTransform.EMPTY);
|
|
||||||
}
|
|
||||||
return this.methods.merge(signature, transform, AccessTransform::merge);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public AccessTransform replaceMethod(MethodSignature signature, AccessTransform transform) {
|
|
||||||
Objects.requireNonNull(signature, "signature");
|
|
||||||
Objects.requireNonNull(transform, "transform");
|
|
||||||
|
|
||||||
if (transform.isEmpty()) {
|
|
||||||
return this.methods.remove(signature);
|
|
||||||
}
|
|
||||||
return this.methods.put(signature, transform);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void merge(AccessTransformSet.Class other) {
|
|
||||||
Objects.requireNonNull(other, "other");
|
|
||||||
|
|
||||||
merge(other.get());
|
|
||||||
mergeAllFields(other.allFields());
|
|
||||||
mergeAllMethods(other.allMethods());
|
|
||||||
|
|
||||||
other.getFields().forEach(this::mergeField);
|
|
||||||
other.getMethods().forEach(this::mergeMethod);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isComplete() {
|
|
||||||
return this.complete;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void complete(InheritanceProvider provider, InheritanceProvider.ClassInfo info) {
|
|
||||||
if (this.complete) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (InheritanceProvider.ClassInfo parent : info.provideParents(provider)) {
|
|
||||||
AccessTransformSet.Class parentAts = getParent().getOrCreateClass(parent.getName());
|
|
||||||
parentAts.complete(provider, parent);
|
|
||||||
|
|
||||||
parentAts.getMethods().forEach((signature, transform) -> {
|
|
||||||
if (info.overrides(signature, parent)) {
|
|
||||||
mergeMethod(signature, transform);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.complete = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean equals(Object o) {
|
|
||||||
if (this == o) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
if (!(o instanceof ClassAccessTransformSetImpl)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ClassAccessTransformSetImpl that = (ClassAccessTransformSetImpl) o;
|
|
||||||
return this.classTransform.equals(that.classTransform) &&
|
|
||||||
this.allFields.equals(that.allFields) &&
|
|
||||||
this.allMethods.equals(that.allMethods) &&
|
|
||||||
this.fields.equals(that.fields) &&
|
|
||||||
this.methods.equals(that.methods);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int hashCode() {
|
|
||||||
return Objects.hash(this.classTransform, this.allFields, this.allMethods, this.fields, this.methods);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
StringJoiner joiner = new StringJoiner(", ", "AccessTransformSet.Class{", "}");
|
|
||||||
if (!this.classTransform.isEmpty()) {
|
|
||||||
joiner.add(this.classTransform.toString());
|
|
||||||
}
|
|
||||||
if (!this.allFields.isEmpty()) {
|
|
||||||
joiner.add("allFields=" + this.allFields);
|
|
||||||
}
|
|
||||||
if (!this.allMethods.isEmpty()) {
|
|
||||||
joiner.add("allMethods=" + this.allMethods);
|
|
||||||
}
|
|
||||||
if (!this.fields.isEmpty()) {
|
|
||||||
joiner.add("fields=" + this.fields);
|
|
||||||
}
|
|
||||||
if (!this.methods.isEmpty()) {
|
|
||||||
joiner.add("method=" + this.methods);
|
|
||||||
}
|
|
||||||
return joiner.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -6,6 +6,12 @@ plugins {
|
|||||||
id 'maven-publish'
|
id 'maven-publish'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boolean gui = enable_gui == "true"
|
||||||
|
if (gui) {
|
||||||
|
sourceSets.create("gui")
|
||||||
|
loom.createRemapConfigurations(sourceSets.gui)
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
minecraft "com.mojang:minecraft:${project.minecraft_version}"
|
||||||
mappings loom.officialMojangMappings()
|
mappings loom.officialMojangMappings()
|
||||||
@@ -20,9 +26,16 @@ dependencies {
|
|||||||
libs("ca.spottedleaf:yamlconfig:${rootProject.yamlconfig_version}") { setTransitive(false) }
|
libs("ca.spottedleaf:yamlconfig:${rootProject.yamlconfig_version}") { setTransitive(false) }
|
||||||
libs("org.yaml:snakeyaml:${rootProject.snakeyaml_version}")
|
libs("org.yaml:snakeyaml:${rootProject.snakeyaml_version}")
|
||||||
|
|
||||||
modImplementation "me.shedaniel.cloth:cloth-config-fabric:${rootProject.cloth_version}"
|
if (gui) {
|
||||||
include "me.shedaniel.cloth:cloth-config-fabric:${rootProject.cloth_version}"
|
guiCompileOnly(project(":"))
|
||||||
modImplementation "com.terraformersmc:modmenu:${rootProject.modmenu_version}"
|
runtimeOnly(sourceSets.gui.output)
|
||||||
|
shadow(sourceSets.gui.output)
|
||||||
|
modGuiImplementation "me.shedaniel.cloth:cloth-config-fabric:${rootProject.cloth_version}"
|
||||||
|
modRuntimeOnly "me.shedaniel.cloth:cloth-config-fabric:${rootProject.cloth_version}"
|
||||||
|
include "me.shedaniel.cloth:cloth-config-fabric:${rootProject.cloth_version}"
|
||||||
|
modGuiImplementation "com.terraformersmc:modmenu:${rootProject.modmenu_version}"
|
||||||
|
modRuntimeOnly "com.terraformersmc:modmenu:${rootProject.modmenu_version}"
|
||||||
|
}
|
||||||
|
|
||||||
modImplementation platform(fabricApiLibs.bom)
|
modImplementation platform(fabricApiLibs.bom)
|
||||||
modImplementation fabricApiLibs.command.api.v2
|
modImplementation fabricApiLibs.command.api.v2
|
||||||
@@ -31,6 +44,14 @@ dependencies {
|
|||||||
include fabricApiLibs.base
|
include fabricApiLibs.base
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gui) {
|
||||||
|
afterEvaluate {
|
||||||
|
configurations.guiCompileOnly {
|
||||||
|
extendsFrom configurations.getByName("minecraftNamedCompile")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
tasks.processResources {
|
tasks.processResources {
|
||||||
def properties = [
|
def properties = [
|
||||||
"version": project.version,
|
"version": project.version,
|
||||||
|
|||||||
@@ -3,9 +3,12 @@ package ca.spottedleaf.moonrise.fabric;
|
|||||||
import ca.spottedleaf.moonrise.common.util.BaseChunkSystemHooks;
|
import ca.spottedleaf.moonrise.common.util.BaseChunkSystemHooks;
|
||||||
import ca.spottedleaf.moonrise.common.PlatformHooks;
|
import ca.spottedleaf.moonrise.common.PlatformHooks;
|
||||||
import ca.spottedleaf.moonrise.common.util.ConfigHolder;
|
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.DSL;
|
||||||
import com.mojang.datafixers.DataFixer;
|
import com.mojang.datafixers.DataFixer;
|
||||||
|
import com.mojang.logging.LogUtils;
|
||||||
import com.mojang.serialization.Dynamic;
|
import com.mojang.serialization.Dynamic;
|
||||||
|
import it.unimi.dsi.fastutil.longs.LongArrays;
|
||||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents;
|
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents;
|
||||||
import net.fabricmc.loader.api.FabricLoader;
|
import net.fabricmc.loader.api.FabricLoader;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
@@ -15,6 +18,8 @@ import net.minecraft.server.level.ChunkHolder;
|
|||||||
import net.minecraft.server.level.GenerationChunkHolder;
|
import net.minecraft.server.level.GenerationChunkHolder;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.server.level.TicketType;
|
||||||
|
import net.minecraft.util.ProblemReporter;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.boss.EnderDragonPart;
|
import net.minecraft.world.entity.boss.EnderDragonPart;
|
||||||
import net.minecraft.world.level.BlockGetter;
|
import net.minecraft.world.level.BlockGetter;
|
||||||
@@ -28,7 +33,9 @@ import net.minecraft.world.level.chunk.ProtoChunk;
|
|||||||
import net.minecraft.world.level.chunk.status.ChunkStatusTasks;
|
import net.minecraft.world.level.chunk.status.ChunkStatusTasks;
|
||||||
import net.minecraft.world.level.chunk.storage.SerializableChunkData;
|
import net.minecraft.world.level.chunk.storage.SerializableChunkData;
|
||||||
import net.minecraft.world.level.entity.EntityTypeTest;
|
import net.minecraft.world.level.entity.EntityTypeTest;
|
||||||
|
import net.minecraft.world.level.storage.TagValueInput;
|
||||||
import net.minecraft.world.phys.AABB;
|
import net.minecraft.world.phys.AABB;
|
||||||
|
import org.slf4j.Logger;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
@@ -37,6 +44,8 @@ public final class FabricHooks extends BaseChunkSystemHooks implements PlatformH
|
|||||||
|
|
||||||
private static final boolean HAS_FABRIC_LIFECYCLE_EVENTS = FabricLoader.getInstance().isModLoaded("fabric-lifecycle-events-v1");
|
private static final boolean HAS_FABRIC_LIFECYCLE_EVENTS = FabricLoader.getInstance().isModLoaded("fabric-lifecycle-events-v1");
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LogUtils.getLogger();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getBrand() {
|
public String getBrand() {
|
||||||
return "Moonrise";
|
return "Moonrise";
|
||||||
@@ -248,11 +257,23 @@ public final class FabricHooks extends BaseChunkSystemHooks implements PlatformH
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void postLoadProtoChunk(final ServerLevel world, final ProtoChunk chunk) {
|
public void postLoadProtoChunk(final ServerLevel world, final ProtoChunk chunk) {
|
||||||
ChunkStatusTasks.postLoadProtoChunk(world, chunk.getEntities());
|
try (final ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(chunk.problemPath(), LOGGER)) {
|
||||||
|
ChunkStatusTasks.postLoadProtoChunk(world, TagValueInput.create(scopedCollector, world.registryAccess(), chunk.getEntities()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int modifyEntityTrackingRange(final Entity entity, final int currentRange) {
|
public int modifyEntityTrackingRange(final Entity entity, final int currentRange) {
|
||||||
return currentRange;
|
return currentRange;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long[] getCounterTypesUncached(final TicketType type) {
|
||||||
|
return type == TicketType.FORCED ? new long[] { ChunkSystemTicketType.COUNTER_TYPE_FORCED } : LongArrays.EMPTY_ARRAY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean addTicketForEnderPearls(final ServerLevel world) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.fabric.mixin.chunk_system;
|
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemDistanceManager;
|
|
||||||
import net.minecraft.server.level.ChunkLevel;
|
|
||||||
import net.minecraft.server.level.DistanceManager;
|
|
||||||
import net.minecraft.server.level.FullChunkStatus;
|
|
||||||
import net.minecraft.server.level.TicketType;
|
|
||||||
import net.minecraft.world.level.ChunkPos;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
|
||||||
|
|
||||||
@Mixin(DistanceManager.class)
|
|
||||||
abstract class FabricDistanceManagerMixin implements ChunkSystemDistanceManager {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @reason Route to new chunk system
|
|
||||||
* @author Spottedleaf
|
|
||||||
*/
|
|
||||||
@Overwrite
|
|
||||||
public <T> void addRegionTicket(final TicketType<T> type, final ChunkPos pos, final int radius, final T identifier) {
|
|
||||||
this.moonrise$getChunkHolderManager().addTicketAtLevel(type, pos, ChunkLevel.byStatus(FullChunkStatus.FULL) - radius, identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @reason Route to new chunk system
|
|
||||||
* @author Spottedleaf
|
|
||||||
*/
|
|
||||||
@Overwrite
|
|
||||||
public <T> void removeRegionTicket(final TicketType<T> type, final ChunkPos pos, final int radius, final T identifier) {
|
|
||||||
this.moonrise$getChunkHolderManager().removeTicketAtLevel(type, pos, ChunkLevel.byStatus(FullChunkStatus.FULL) - radius, identifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -36,7 +36,7 @@
|
|||||||
"accessWidener": "moonrise.accesswidener",
|
"accessWidener": "moonrise.accesswidener",
|
||||||
"depends": {
|
"depends": {
|
||||||
"fabricloader": ">=${loader_version}",
|
"fabricloader": ">=${loader_version}",
|
||||||
"minecraft": ">1.21.3 <1.21.5",
|
"minecraft": ">1.21.5 <1.21.7",
|
||||||
"fabric-command-api-v2": "*"
|
"fabric-command-api-v2": "*"
|
||||||
},
|
},
|
||||||
"custom": {
|
"custom": {
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
"parent": "moonrise.mixins.json",
|
"parent": "moonrise.mixins.json",
|
||||||
"package": "ca.spottedleaf.moonrise.fabric.mixin",
|
"package": "ca.spottedleaf.moonrise.fabric.mixin",
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"chunk_system.FabricDistanceManagerMixin",
|
|
||||||
"chunk_system.FabricMinecraftServerMixin",
|
"chunk_system.FabricMinecraftServerMixin",
|
||||||
"chunk_system.FabricServerLevelMixin",
|
"chunk_system.FabricServerLevelMixin",
|
||||||
"collisions.EntityMixin"
|
"collisions.EntityMixin"
|
||||||
|
|||||||
@@ -2,24 +2,27 @@
|
|||||||
org.gradle.jvmargs=-Xmx2G
|
org.gradle.jvmargs=-Xmx2G
|
||||||
org.gradle.parallel=true
|
org.gradle.parallel=true
|
||||||
org.gradle.caching=true
|
org.gradle.caching=true
|
||||||
|
org.gradle.configuration-cache=true
|
||||||
# Fabric Properties
|
# Fabric Properties
|
||||||
# check these on https://modmuss50.me/fabric.html
|
# check these on https://fabricmc.net/develop/
|
||||||
minecraft_version=1.21.4
|
minecraft_version=1.21.6
|
||||||
loader_version=0.16.9
|
loader_version=0.16.14
|
||||||
supported_minecraft_versions=1.21.4
|
supported_minecraft_versions=1.21.6
|
||||||
neoforge_version=21.4.33-beta
|
neoforge_version=21.6.11-beta
|
||||||
neoform_version=1.21.4-20241203.161809
|
neoform_version=1.21.6-20250617.151856
|
||||||
fabric_api_version=0.110.5+1.21.4
|
fabric_api_version=0.127.1+1.21.6
|
||||||
snakeyaml_version=2.3
|
snakeyaml_version=2.3
|
||||||
concurrentutil_version=0.0.2
|
concurrentutil_version=0.0.3
|
||||||
yamlconfig_version=1.0.2
|
yamlconfig_version=1.0.2
|
||||||
cloth_version=17.0.144
|
cloth_version=19.0.147
|
||||||
modmenu_version=13.0.0-beta.1
|
modmenu_version=15.0.0-beta.2
|
||||||
|
# set to false when modmenu/cloth is not updated for the current minecraft version
|
||||||
|
enable_gui=true
|
||||||
junit_version=5.11.3
|
junit_version=5.11.3
|
||||||
# version ids from modrinth
|
# version ids from modrinth
|
||||||
fabric_lithium_version=t1FlWYl9
|
fabric_lithium_version=nhc57Td2
|
||||||
neo_lithium_version=iDqQi66g
|
neo_lithium_version=P5VT33Jo
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
mod_version=0.2.0-beta.7
|
mod_version=0.4.0-SNAPSHOT
|
||||||
maven_group=ca.spottedleaf.moonrise
|
maven_group=ca.spottedleaf.moonrise
|
||||||
archives_base_name=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
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.1-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
6
gradlew
vendored
6
gradlew
vendored
@@ -114,7 +114,7 @@ case "$( uname )" in #(
|
|||||||
NONSTOP* ) nonstop=true ;;
|
NONSTOP* ) nonstop=true ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
|
CLASSPATH="\\\"\\\""
|
||||||
|
|
||||||
|
|
||||||
# Determine the Java command to use to start the JVM.
|
# Determine the Java command to use to start the JVM.
|
||||||
@@ -205,7 +205,7 @@ fi
|
|||||||
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
||||||
|
|
||||||
# Collect all arguments for the java command:
|
# Collect all arguments for the java command:
|
||||||
# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,
|
||||||
# and any embedded shellness will be escaped.
|
# and any embedded shellness will be escaped.
|
||||||
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be
|
||||||
# treated as '${Hostname}' itself on the command line.
|
# treated as '${Hostname}' itself on the command line.
|
||||||
@@ -213,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
|
|||||||
set -- \
|
set -- \
|
||||||
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
"-Dorg.gradle.appname=$APP_BASE_NAME" \
|
||||||
-classpath "$CLASSPATH" \
|
-classpath "$CLASSPATH" \
|
||||||
org.gradle.wrapper.GradleWrapperMain \
|
-jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \
|
||||||
"$@"
|
"$@"
|
||||||
|
|
||||||
# Stop when "xargs" is not available.
|
# Stop when "xargs" is not available.
|
||||||
|
|||||||
4
gradlew.bat
vendored
4
gradlew.bat
vendored
@@ -70,11 +70,11 @@ goto fail
|
|||||||
:execute
|
:execute
|
||||||
@rem Setup the command line
|
@rem Setup the command line
|
||||||
|
|
||||||
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
|
set CLASSPATH=
|
||||||
|
|
||||||
|
|
||||||
@rem Execute Gradle
|
@rem Execute Gradle
|
||||||
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
|
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %*
|
||||||
|
|
||||||
:end
|
:end
|
||||||
@rem End local scope for the variables with windows NT shell
|
@rem End local scope for the variables with windows NT shell
|
||||||
|
|||||||
@@ -4,9 +4,12 @@ import ca.spottedleaf.moonrise.common.util.BaseChunkSystemHooks;
|
|||||||
import ca.spottedleaf.moonrise.common.PlatformHooks;
|
import ca.spottedleaf.moonrise.common.PlatformHooks;
|
||||||
import ca.spottedleaf.moonrise.common.util.ConfigHolder;
|
import ca.spottedleaf.moonrise.common.util.ConfigHolder;
|
||||||
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
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.DSL;
|
||||||
import com.mojang.datafixers.DataFixer;
|
import com.mojang.datafixers.DataFixer;
|
||||||
|
import com.mojang.logging.LogUtils;
|
||||||
import com.mojang.serialization.Dynamic;
|
import com.mojang.serialization.Dynamic;
|
||||||
|
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.NbtOps;
|
import net.minecraft.nbt.NbtOps;
|
||||||
@@ -14,6 +17,8 @@ import net.minecraft.server.level.ChunkHolder;
|
|||||||
import net.minecraft.server.level.GenerationChunkHolder;
|
import net.minecraft.server.level.GenerationChunkHolder;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.server.level.TicketType;
|
||||||
|
import net.minecraft.util.ProblemReporter;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.level.BlockGetter;
|
import net.minecraft.world.level.BlockGetter;
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
@@ -27,6 +32,7 @@ import net.minecraft.world.level.chunk.ProtoChunk;
|
|||||||
import net.minecraft.world.level.chunk.status.ChunkStatusTasks;
|
import net.minecraft.world.level.chunk.status.ChunkStatusTasks;
|
||||||
import net.minecraft.world.level.chunk.storage.SerializableChunkData;
|
import net.minecraft.world.level.chunk.storage.SerializableChunkData;
|
||||||
import net.minecraft.world.level.entity.EntityTypeTest;
|
import net.minecraft.world.level.entity.EntityTypeTest;
|
||||||
|
import net.minecraft.world.level.storage.TagValueInput;
|
||||||
import net.minecraft.world.phys.AABB;
|
import net.minecraft.world.phys.AABB;
|
||||||
import net.neoforged.neoforge.common.CommonHooks;
|
import net.neoforged.neoforge.common.CommonHooks;
|
||||||
import net.neoforged.neoforge.common.NeoForge;
|
import net.neoforged.neoforge.common.NeoForge;
|
||||||
@@ -35,12 +41,15 @@ import net.neoforged.neoforge.event.EventHooks;
|
|||||||
import net.neoforged.neoforge.event.entity.EntityJoinLevelEvent;
|
import net.neoforged.neoforge.event.entity.EntityJoinLevelEvent;
|
||||||
import net.neoforged.neoforge.event.level.ChunkDataEvent;
|
import net.neoforged.neoforge.event.level.ChunkDataEvent;
|
||||||
import net.neoforged.neoforge.event.level.ChunkEvent;
|
import net.neoforged.neoforge.event.level.ChunkEvent;
|
||||||
|
import org.slf4j.Logger;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
public final class NeoForgeHooks extends BaseChunkSystemHooks implements PlatformHooks {
|
public final class NeoForgeHooks extends BaseChunkSystemHooks implements PlatformHooks {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LogUtils.getLogger();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getBrand() {
|
public String getBrand() {
|
||||||
return "Moonrise";
|
return "Moonrise";
|
||||||
@@ -254,11 +263,32 @@ public final class NeoForgeHooks extends BaseChunkSystemHooks implements Platfor
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void postLoadProtoChunk(final ServerLevel world, final ProtoChunk chunk) {
|
public void postLoadProtoChunk(final ServerLevel world, final ProtoChunk chunk) {
|
||||||
ChunkStatusTasks.postLoadProtoChunk(world, chunk.getEntities());
|
try (final ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(chunk.problemPath(), LOGGER)) {
|
||||||
|
ChunkStatusTasks.postLoadProtoChunk(world, TagValueInput.create(scopedCollector, world.registryAccess(), chunk.getEntities()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int modifyEntityTrackingRange(final Entity entity, final int currentRange) {
|
public int modifyEntityTrackingRange(final Entity entity, final int currentRange) {
|
||||||
return 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();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean addTicketForEnderPearls(final ServerLevel world) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,87 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.neoforge.mixin.chunk_system;
|
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemDistanceManager;
|
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickServerLevel;
|
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
|
||||||
import net.minecraft.server.level.ChunkLevel;
|
|
||||||
import net.minecraft.server.level.DistanceManager;
|
|
||||||
import net.minecraft.server.level.FullChunkStatus;
|
|
||||||
import net.minecraft.server.level.Ticket;
|
|
||||||
import net.minecraft.server.level.TicketType;
|
|
||||||
import net.minecraft.util.SortedArraySet;
|
|
||||||
import net.minecraft.world.level.ChunkPos;
|
|
||||||
import org.spongepowered.asm.mixin.Final;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
|
|
||||||
@Mixin(DistanceManager.class)
|
|
||||||
abstract class NeoForgeDistanceManagerMixin implements ChunkSystemDistanceManager {
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
private Long2ObjectOpenHashMap<SortedArraySet<Ticket<?>>> forcedTickets;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @reason Route to new chunk system
|
|
||||||
* @author Spottedleaf
|
|
||||||
*/
|
|
||||||
@Overwrite
|
|
||||||
public <T> void addRegionTicket(final TicketType<T> type, final ChunkPos pos, final int radius, final T identifier, final boolean forceTicks) {
|
|
||||||
final int level = ChunkLevel.byStatus(FullChunkStatus.FULL) - radius;
|
|
||||||
this.moonrise$getChunkHolderManager().addTicketAtLevel(type, pos, level, identifier);
|
|
||||||
if (forceTicks) {
|
|
||||||
final Ticket<T> forceTicket = new Ticket<>(type, level, identifier, forceTicks);
|
|
||||||
|
|
||||||
this.forcedTickets.compute(pos.toLong(), (final Long keyInMap, final SortedArraySet<Ticket<?>> valueInMap) -> {
|
|
||||||
final SortedArraySet<Ticket<?>> ret;
|
|
||||||
if (valueInMap != null) {
|
|
||||||
ret = valueInMap;
|
|
||||||
} else {
|
|
||||||
ret = SortedArraySet.create(4);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret.add(forceTicket)) {
|
|
||||||
((ChunkTickServerLevel)NeoForgeDistanceManagerMixin.this.moonrise$getChunkMap().level).moonrise$addPlayerTickingRequest(
|
|
||||||
CoordinateUtils.getChunkX(keyInMap.longValue()), CoordinateUtils.getChunkZ(keyInMap.longValue())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @reason Route to new chunk system
|
|
||||||
* @author Spottedleaf
|
|
||||||
*/
|
|
||||||
@Overwrite
|
|
||||||
public <T> void removeRegionTicket(final TicketType<T> type, final ChunkPos pos, final int radius, final T identifier, final boolean forceTicks) {
|
|
||||||
final int level = ChunkLevel.byStatus(FullChunkStatus.FULL) - radius;
|
|
||||||
this.moonrise$getChunkHolderManager().removeTicketAtLevel(type, pos, level, identifier);
|
|
||||||
if (forceTicks) {
|
|
||||||
final Ticket<T> forceTicket = new Ticket<>(type, level, identifier, forceTicks);
|
|
||||||
|
|
||||||
this.forcedTickets.computeIfPresent(pos.toLong(), (final Long keyInMap, final SortedArraySet<Ticket<?>> valueInMap) -> {
|
|
||||||
if (valueInMap.remove(forceTicket)) {
|
|
||||||
((ChunkTickServerLevel)NeoForgeDistanceManagerMixin.this.moonrise$getChunkMap().level).moonrise$removePlayerTickingRequest(
|
|
||||||
CoordinateUtils.getChunkX(keyInMap.longValue()), CoordinateUtils.getChunkZ(keyInMap.longValue())
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return valueInMap.isEmpty() ? null : valueInMap;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @reason Only use containsKey, as we fix the leak with this impl
|
|
||||||
* @author Spottedleaf
|
|
||||||
*/
|
|
||||||
@Overwrite
|
|
||||||
public boolean shouldForceTicks(final long chunkPos) {
|
|
||||||
return this.forcedTickets.containsKey(chunkPos);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
package ca.spottedleaf.moonrise.neoforge.mixin.chunk_system;
|
||||||
|
|
||||||
|
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketStorage;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType;
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||||
|
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||||
|
import net.minecraft.world.level.ChunkPos;
|
||||||
|
import net.minecraft.world.level.TicketStorage;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(TicketStorage.class)
|
||||||
|
abstract class NeoForgeTicketStorageMixin implements ChunkSystemTicketStorage {
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
private LongSet chunksWithForceNaturalSpawning;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Destroy old chunk system state
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Inject(
|
||||||
|
method = "<init>(Lit/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap;Lit/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap;)V",
|
||||||
|
at = @At(
|
||||||
|
value = "RETURN"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private void destroyFields(Long2ObjectOpenHashMap p_393873_, Long2ObjectOpenHashMap p_394615_, CallbackInfo ci) {
|
||||||
|
this.chunksWithForceNaturalSpawning = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason The forced natural spawning chunks would be empty, as tickets should always be empty.
|
||||||
|
* We need to do this to avoid throwing immediately.
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Redirect(
|
||||||
|
method = "<init>(Lit/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap;Lit/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap;)V",
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "Lnet/minecraft/world/level/TicketStorage;updateForcedNaturalSpawning()V"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private void avoidUpdatingForcedNaturalChunks(final TicketStorage instance) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Route to new chunk system
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Overwrite
|
||||||
|
public boolean shouldForceNaturalSpawning(final ChunkPos pos) {
|
||||||
|
final Long2IntOpenHashMap counters = ((ChunkSystemServerLevel)this.moonrise$getChunkMap().level).moonrise$getChunkTaskScheduler()
|
||||||
|
.chunkHolderManager.getTicketCounters(ChunkSystemTicketType.COUNTER_TYPER_NATURAL_SPAWNING_FORCED);
|
||||||
|
|
||||||
|
if (counters == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return counters.containsKey(CoordinateUtils.getChunkKey(pos));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -28,7 +28,7 @@ side = "BOTH"
|
|||||||
[[dependencies.moonrise]]
|
[[dependencies.moonrise]]
|
||||||
modId = "minecraft"
|
modId = "minecraft"
|
||||||
type = "required"
|
type = "required"
|
||||||
versionRange = "(1.21.3,1.21.5)"
|
versionRange = "(1.21.5,1.21.7)"
|
||||||
ordering = "NONE"
|
ordering = "NONE"
|
||||||
side = "BOTH"
|
side = "BOTH"
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,9 @@
|
|||||||
"parent": "moonrise.mixins.json",
|
"parent": "moonrise.mixins.json",
|
||||||
"package": "ca.spottedleaf.moonrise.neoforge.mixin",
|
"package": "ca.spottedleaf.moonrise.neoforge.mixin",
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"chunk_system.NeoForgeDistanceManagerMixin",
|
|
||||||
"chunk_system.NeoForgeMinecraftServerMixin",
|
"chunk_system.NeoForgeMinecraftServerMixin",
|
||||||
"chunk_system.NeoForgeServerLevelMixin",
|
"chunk_system.NeoForgeServerLevelMixin",
|
||||||
|
"chunk_system.NeoForgeTicketStorageMixin",
|
||||||
"collisions.EntityMixin"
|
"collisions.EntityMixin"
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ pluginManagement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("org.gradle.toolchains.foojay-resolver-convention") version "0.9.0"
|
id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0"
|
||||||
id("quiet-fabric-loom") version "1.9.312" apply false
|
id("quiet-fabric-loom") version "1.10.317" apply false
|
||||||
id("net.neoforged.moddev") version "2.0.61-beta" apply false
|
id("net.neoforged.moddev") version "2.0.80" apply false
|
||||||
id 'com.gradleup.shadow' version '8.3.5' apply false
|
id 'com.gradleup.shadow' version '8.3.6' apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencyResolutionManagement {
|
dependencyResolutionManagement {
|
||||||
|
|||||||
@@ -102,6 +102,8 @@ public interface PlatformHooks extends ChunkSystemHooks {
|
|||||||
|
|
||||||
public int modifyEntityTrackingRange(final Entity entity, final int currentRange);
|
public int modifyEntityTrackingRange(final Entity entity, final int currentRange);
|
||||||
|
|
||||||
|
public boolean addTicketForEnderPearls(final ServerLevel world);
|
||||||
|
|
||||||
public static final class Holder {
|
public static final class Holder {
|
||||||
private Holder() {
|
private Holder() {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package ca.spottedleaf.moonrise.common.config.moonrise;
|
|||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.config.ui.ClothConfig;
|
import ca.spottedleaf.moonrise.common.config.ui.ClothConfig;
|
||||||
import ca.spottedleaf.moonrise.common.util.MoonriseCommon;
|
import ca.spottedleaf.moonrise.common.util.MoonriseCommon;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler;
|
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkTaskScheduler;
|
||||||
import ca.spottedleaf.yamlconfig.InitialiseHook;
|
import ca.spottedleaf.yamlconfig.InitialiseHook;
|
||||||
import ca.spottedleaf.yamlconfig.annotation.Adaptable;
|
import ca.spottedleaf.yamlconfig.annotation.Adaptable;
|
||||||
@@ -38,7 +39,7 @@ public final class MoonriseConfig {
|
|||||||
|
|
||||||
|
|
||||||
@Adaptable
|
@Adaptable
|
||||||
public static final class Basic {
|
public static final class Basic implements InitialiseHook {
|
||||||
@Serializable(
|
@Serializable(
|
||||||
comment = """
|
comment = """
|
||||||
The maximum rate of chunks to send to any given player, per second. If this value is <= 0,
|
The maximum rate of chunks to send to any given player, per second. If this value is <= 0,
|
||||||
@@ -72,6 +73,20 @@ public final class MoonriseConfig {
|
|||||||
section = CHUNK_SYSTEM_SECTION
|
section = CHUNK_SYSTEM_SECTION
|
||||||
)
|
)
|
||||||
public double playerMaxGenRate = -1.0;
|
public double playerMaxGenRate = -1.0;
|
||||||
|
|
||||||
|
@Serializable(
|
||||||
|
comment = """
|
||||||
|
The delay before chunks are unloaded around players once they leave their view distance.
|
||||||
|
The Vanilla value is 0 ticks. Setting this value higher (i.e 5s) will allow pets to teleport
|
||||||
|
to their owners when they teleport.
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
public Duration playerChunkUnloadDelay = Duration.parse("0t");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialise() {
|
||||||
|
RegionizedPlayerChunkLoader.setUnloadDelay(this.playerChunkUnloadDelay.getTimeTicks());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Serializable(
|
@Serializable(
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package ca.spottedleaf.moonrise.common.list;
|
|||||||
|
|
||||||
import it.unimi.dsi.fastutil.objects.Reference2IntLinkedOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Reference2IntLinkedOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
|
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
|
||||||
|
import java.lang.reflect.Array;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
|
|
||||||
@@ -21,15 +22,34 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
|||||||
private int iteratorCount;
|
private int iteratorCount;
|
||||||
|
|
||||||
public IteratorSafeOrderedReferenceSet() {
|
public IteratorSafeOrderedReferenceSet() {
|
||||||
this(16, 0.75f, 16, 0.2);
|
this(Object.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IteratorSafeOrderedReferenceSet(final Class<? super E> arrComponent) {
|
||||||
|
this(16, 0.75f, 16, 0.2, arrComponent);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IteratorSafeOrderedReferenceSet(final int setCapacity, final float setLoadFactor, final int arrayCapacity,
|
public IteratorSafeOrderedReferenceSet(final int setCapacity, final float setLoadFactor, final int arrayCapacity,
|
||||||
final double maxFragFactor) {
|
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 = new Reference2IntLinkedOpenHashMap<>(setCapacity, setLoadFactor);
|
||||||
this.indexMap.defaultReturnValue(-1);
|
this.indexMap.defaultReturnValue(-1);
|
||||||
this.maxFragFactor = maxFragFactor;
|
this.maxFragFactor = maxFragFactor;
|
||||||
this.listElements = (E[])new Object[arrayCapacity];
|
this.listElements = (E[])Array.newInstance(arrComponent, arrayCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// includes null (gravestone) elements
|
||||||
|
public E[] getListRaw() {
|
||||||
|
return this.listElements;
|
||||||
|
}
|
||||||
|
|
||||||
|
// includes null (gravestone) elements
|
||||||
|
public int getListSize() {
|
||||||
|
return this.listSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -81,7 +101,7 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
|||||||
public int createRawIterator() {
|
public int createRawIterator() {
|
||||||
++this.iteratorCount;
|
++this.iteratorCount;
|
||||||
if (this.indexMap.isEmpty()) {
|
if (this.indexMap.isEmpty()) {
|
||||||
return -1;
|
return Integer.MAX_VALUE;
|
||||||
} else {
|
} else {
|
||||||
return this.firstInvalidIndex == 0 ? this.indexMap.getInt(this.indexMap.firstKey()) : 0;
|
return this.firstInvalidIndex == 0 ? this.indexMap.getInt(this.indexMap.firstKey()) : 0;
|
||||||
}
|
}
|
||||||
@@ -96,7 +116,7 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return Integer.MAX_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void finishRawIterator() {
|
public void finishRawIterator() {
|
||||||
@@ -205,10 +225,6 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
|||||||
//this.check();
|
//this.check();
|
||||||
}
|
}
|
||||||
|
|
||||||
public E rawGet(final int index) {
|
|
||||||
return this.listElements[index];
|
|
||||||
}
|
|
||||||
|
|
||||||
public int size() {
|
public int size() {
|
||||||
// always returns the correct amount - listSize can be different
|
// always returns the correct amount - listSize can be different
|
||||||
return this.indexMap.size();
|
return this.indexMap.size();
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package ca.spottedleaf.moonrise.common.misc;
|
package ca.spottedleaf.moonrise.common.misc;
|
||||||
|
|
||||||
import ca.spottedleaf.concurrentutil.util.IntPairUtil;
|
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||||
import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap;
|
||||||
@@ -23,12 +23,16 @@ public final class PositionCountingAreaMap<T> {
|
|||||||
return this.positions.size();
|
return this.positions.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasObjectsNear(final long pos) {
|
||||||
|
return this.positions.containsKey(pos);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean hasObjectsNear(final int toX, final int toZ) {
|
public boolean hasObjectsNear(final int toX, final int toZ) {
|
||||||
return this.positions.containsKey(IntPairUtil.key(toX, toZ));
|
return this.positions.containsKey(CoordinateUtils.getChunkKey(toX, toZ));
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getObjectsNear(final int toX, final int toZ) {
|
public int getObjectsNear(final int toX, final int toZ) {
|
||||||
return this.positions.get(IntPairUtil.key(toX, toZ));
|
return this.positions.get(CoordinateUtils.getChunkKey(toX, toZ));
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean add(final T parameter, final int toX, final int toZ, final int distance) {
|
public boolean add(final T parameter, final int toX, final int toZ, final int distance) {
|
||||||
@@ -85,12 +89,12 @@ public final class PositionCountingAreaMap<T> {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void addCallback(final T parameter, final int toX, final int toZ) {
|
protected void addCallback(final T parameter, final int toX, final int toZ) {
|
||||||
PositionCountingAreaMap.this.positions.addTo(IntPairUtil.key(toX, toZ), 1);
|
PositionCountingAreaMap.this.positions.addTo(CoordinateUtils.getChunkKey(toX, toZ), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void removeCallback(final T parameter, final int toX, final int toZ) {
|
protected void removeCallback(final T parameter, final int toX, final int toZ) {
|
||||||
final long key = IntPairUtil.key(toX, toZ);
|
final long key = CoordinateUtils.getChunkKey(toX, toZ);
|
||||||
if (PositionCountingAreaMap.this.positions.addTo(key, -1) == 1) {
|
if (PositionCountingAreaMap.this.positions.addTo(key, -1) == 1) {
|
||||||
PositionCountingAreaMap.this.positions.remove(key);
|
PositionCountingAreaMap.this.positions.remove(key);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
package ca.spottedleaf.moonrise.common.misc;
|
package ca.spottedleaf.moonrise.common.misc;
|
||||||
|
|
||||||
import ca.spottedleaf.concurrentutil.util.IntegerUtil;
|
|
||||||
|
|
||||||
public abstract class SingleUserAreaMap<T> {
|
public abstract class SingleUserAreaMap<T> {
|
||||||
|
|
||||||
public static final int NOT_SET = Integer.MIN_VALUE;
|
public static final int NOT_SET = Integer.MIN_VALUE;
|
||||||
@@ -99,8 +97,8 @@ public abstract class SingleUserAreaMap<T> {
|
|||||||
final int dx = toX - fromX;
|
final int dx = toX - fromX;
|
||||||
final int dz = toZ - fromZ;
|
final int dz = toZ - fromZ;
|
||||||
|
|
||||||
final int totalX = IntegerUtil.branchlessAbs(fromX - toX);
|
final int totalX = Math.abs(fromX - toX);
|
||||||
final int totalZ = IntegerUtil.branchlessAbs(fromZ - toZ);
|
final int totalZ = Math.abs(fromZ - toZ);
|
||||||
|
|
||||||
if (Math.max(totalX, totalZ) > (2 * Math.max(newViewDistance, oldViewDistance))) {
|
if (Math.max(totalX, totalZ) > (2 * Math.max(newViewDistance, oldViewDistance))) {
|
||||||
// teleported
|
// teleported
|
||||||
@@ -120,7 +118,7 @@ public abstract class SingleUserAreaMap<T> {
|
|||||||
for (int currZ = oldMinZ; currZ <= oldMaxZ; ++currZ) {
|
for (int currZ = oldMinZ; currZ <= oldMaxZ; ++currZ) {
|
||||||
|
|
||||||
// only remove if we're outside the new view distance...
|
// only remove if we're outside the new view distance...
|
||||||
if (Math.max(IntegerUtil.branchlessAbs(currX - toX), IntegerUtil.branchlessAbs(currZ - toZ)) > newViewDistance) {
|
if (Math.max(Math.abs(currX - toX), Math.abs(currZ - toZ)) > newViewDistance) {
|
||||||
this.removeCallback(parameter, currX, currZ);
|
this.removeCallback(parameter, currX, currZ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -136,7 +134,7 @@ public abstract class SingleUserAreaMap<T> {
|
|||||||
for (int currZ = newMinZ; currZ <= newMaxZ; ++currZ) {
|
for (int currZ = newMinZ; currZ <= newMaxZ; ++currZ) {
|
||||||
|
|
||||||
// only add if we're outside the old view distance...
|
// only add if we're outside the old view distance...
|
||||||
if (Math.max(IntegerUtil.branchlessAbs(currX - fromX), IntegerUtil.branchlessAbs(currZ - fromZ)) > oldViewDistance) {
|
if (Math.max(Math.abs(currX - fromX), Math.abs(currZ - fromZ)) > oldViewDistance) {
|
||||||
this.addCallback(parameter, currX, currZ);
|
this.addCallback(parameter, currX, currZ);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ public abstract class BaseChunkSystemHooks implements ChunkSystemHooks {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
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) {
|
||||||
scheduleChunkTask(level, chunkX, chunkZ, run, Priority.NORMAL);
|
this.scheduleChunkTask(level, chunkX, chunkZ, run, Priority.NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -71,7 +71,7 @@ public abstract class BaseChunkSystemHooks implements ChunkSystemHooks {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasAnyChunkHolders(final ServerLevel level) {
|
public boolean hasAnyChunkHolders(final ServerLevel level) {
|
||||||
return getUpdatingChunkHolderCount(level) != 0;
|
return this.getUpdatingChunkHolderCount(level) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -98,16 +98,12 @@ public abstract class BaseChunkSystemHooks implements ChunkSystemHooks {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onChunkBorder(final LevelChunk chunk, final ChunkHolder holder) {
|
public void onChunkBorder(final LevelChunk chunk, final ChunkHolder holder) {
|
||||||
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getLoadedChunks().add(
|
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getLoadedChunks().add(chunk);
|
||||||
((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onChunkNotBorder(final LevelChunk chunk, final ChunkHolder holder) {
|
public void onChunkNotBorder(final LevelChunk chunk, final ChunkHolder holder) {
|
||||||
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getLoadedChunks().remove(
|
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getLoadedChunks().remove(chunk);
|
||||||
((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -118,37 +114,29 @@ public abstract class BaseChunkSystemHooks implements ChunkSystemHooks {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onChunkTicking(final LevelChunk chunk, final ChunkHolder holder) {
|
public void onChunkTicking(final LevelChunk chunk, final ChunkHolder holder) {
|
||||||
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getTickingChunks().add(
|
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getTickingChunks().add(chunk);
|
||||||
((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder()
|
|
||||||
);
|
|
||||||
if (!((ChunkSystemLevelChunk)chunk).moonrise$isPostProcessingDone()) {
|
if (!((ChunkSystemLevelChunk)chunk).moonrise$isPostProcessingDone()) {
|
||||||
chunk.postProcessGeneration((ServerLevel)chunk.getLevel());
|
chunk.postProcessGeneration((ServerLevel)chunk.getLevel());
|
||||||
}
|
}
|
||||||
((ServerLevel)chunk.getLevel()).startTickingChunk(chunk);
|
((ServerLevel)chunk.getLevel()).startTickingChunk(chunk);
|
||||||
((ServerLevel)chunk.getLevel()).getChunkSource().chunkMap.tickingGenerated.incrementAndGet();
|
((ServerLevel)chunk.getLevel()).getChunkSource().chunkMap.tickingGenerated.incrementAndGet();
|
||||||
((ChunkTickServerLevel)(ServerLevel)chunk.getLevel()).moonrise$markChunkForPlayerTicking(chunk); // Moonrise - chunk tick iteration
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onChunkNotTicking(final LevelChunk chunk, final ChunkHolder holder) {
|
public void onChunkNotTicking(final LevelChunk chunk, final ChunkHolder holder) {
|
||||||
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getTickingChunks().remove(
|
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getTickingChunks().remove(chunk);
|
||||||
((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder()
|
|
||||||
);
|
|
||||||
((ChunkTickServerLevel)(ServerLevel)chunk.getLevel()).moonrise$removeChunkForPlayerTicking(chunk); // Moonrise - chunk tick iteration
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onChunkEntityTicking(final LevelChunk chunk, final ChunkHolder holder) {
|
public void onChunkEntityTicking(final LevelChunk chunk, final ChunkHolder holder) {
|
||||||
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getEntityTickingChunks().add(
|
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getEntityTickingChunks().add(chunk);
|
||||||
((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder()
|
((ChunkTickServerLevel)(ServerLevel)chunk.getLevel()).moonrise$markChunkForPlayerTicking(chunk); // Moonrise - chunk tick iteration
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onChunkNotEntityTicking(final LevelChunk chunk, final ChunkHolder holder) {
|
public void onChunkNotEntityTicking(final LevelChunk chunk, final ChunkHolder holder) {
|
||||||
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getEntityTickingChunks().remove(
|
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getEntityTickingChunks().remove(chunk);
|
||||||
((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder()
|
((ChunkTickServerLevel)(ServerLevel)chunk.getLevel()).moonrise$removeChunkForPlayerTicking(chunk); // Moonrise - chunk tick iteration
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import net.minecraft.server.level.ChunkHolder;
|
|||||||
import net.minecraft.server.level.FullChunkStatus;
|
import net.minecraft.server.level.FullChunkStatus;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.server.level.TicketType;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
@@ -74,4 +75,6 @@ public interface ChunkSystemHooks {
|
|||||||
public void removePlayerFromDistanceMaps(final ServerLevel world, final ServerPlayer player);
|
public void removePlayerFromDistanceMaps(final ServerLevel world, final ServerPlayer player);
|
||||||
|
|
||||||
public void updateMaps(final ServerLevel world, final ServerPlayer player);
|
public void updateMaps(final ServerLevel world, final ServerPlayer player);
|
||||||
|
|
||||||
|
public long[] getCounterTypesUncached(final TicketType type);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,8 @@ public final class CoordinateUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static long getChunkKey(final Entity entity) {
|
public static long getChunkKey(final Entity entity) {
|
||||||
return ((Mth.lfloor(entity.getZ()) >> 4) << 32) | ((Mth.lfloor(entity.getX()) >> 4) & 0xFFFFFFFFL);
|
final ChunkPos pos = entity.chunkPosition();
|
||||||
|
return ((long)pos.z << 32) | (pos.x & 0xFFFFFFFFL);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static long getChunkKey(final ChunkPos pos) {
|
public static long getChunkKey(final ChunkPos pos) {
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package ca.spottedleaf.moonrise.common.util;
|
||||||
|
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import java.text.DecimalFormat;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public final class EntityUtil {
|
||||||
|
|
||||||
|
private static final ThreadLocal<DecimalFormat> THREE_DECIMAL_PLACES = ThreadLocal.withInitial(() -> {
|
||||||
|
return new DecimalFormat("#,##0.000");
|
||||||
|
});
|
||||||
|
|
||||||
|
private static String formatVec(final Vec3 vec) {
|
||||||
|
final DecimalFormat format = THREE_DECIMAL_PLACES.get();
|
||||||
|
|
||||||
|
return "(" + format.format(vec.x) + "," + format.format(vec.y) + "," + format.format(vec.z) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String dumpEntityWithoutReferences(final Entity entity) {
|
||||||
|
if (entity == null) {
|
||||||
|
return "{null}";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "{type=" + entity.getClass().getSimpleName() + ",id=" + entity.getId() + ",uuid=" + entity.getUUID() + ",pos=" + formatVec(entity.position())
|
||||||
|
+ ",mot=" + formatVec(entity.getDeltaMovement()) + ",aabb=" + entity.getBoundingBox() + ",removed=" + entity.getRemovalReason() + ",has_vehicle=" + (entity.getVehicle() != null)
|
||||||
|
+ ",passenger_count=" + entity.getPassengers().size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String dumpEntity(final Entity entity) {
|
||||||
|
final List<Entity> passengers = entity.getPassengers();
|
||||||
|
final List<String> passengerStrings = new ArrayList<>(passengers.size());
|
||||||
|
|
||||||
|
for (final Entity passenger : passengers) {
|
||||||
|
passengerStrings.add("(" + dumpEntityWithoutReferences(passenger) + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
return "{root=[" + dumpEntityWithoutReferences(entity) + "], vehicle=[" + dumpEntityWithoutReferences(entity.getVehicle())
|
||||||
|
+ "], passengers=[" + String.join(",", passengerStrings) + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
private EntityUtil() {}
|
||||||
|
}
|
||||||
@@ -15,56 +15,81 @@ public class TickThread extends Thread {
|
|||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(TickThread.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(TickThread.class);
|
||||||
|
|
||||||
|
private static String getThreadContext() {
|
||||||
|
return "thread=" + Thread.currentThread().getName();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated
|
* @deprecated
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
public static void ensureTickThread(final String reason) {
|
public static void ensureTickThread(final String reason) {
|
||||||
if (!isTickThread()) {
|
if (!isTickThread()) {
|
||||||
LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable());
|
LOGGER.error("Thread failed main thread check: " + reason + ", context=" + getThreadContext(), new Throwable());
|
||||||
throw new IllegalStateException(reason);
|
throw new IllegalStateException(reason);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ensureTickThread(final Level world, final BlockPos pos, final String reason) {
|
public static void ensureTickThread(final Level world, final BlockPos pos, final String reason) {
|
||||||
if (!isTickThreadFor(world, pos)) {
|
if (!isTickThreadFor(world, pos)) {
|
||||||
LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable());
|
final String ex = "Thread failed main thread check: " +
|
||||||
throw new IllegalStateException(reason);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ensureTickThread(final Level world, final ChunkPos pos, final String reason) {
|
public static void ensureTickThread(final Level world, final ChunkPos pos, final String reason) {
|
||||||
if (!isTickThreadFor(world, pos)) {
|
if (!isTickThreadFor(world, pos)) {
|
||||||
LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable());
|
final String ex = "Thread failed main thread check: " +
|
||||||
throw new IllegalStateException(reason);
|
reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", chunk_pos=" + pos;
|
||||||
|
LOGGER.error(ex, new Throwable());
|
||||||
|
throw new IllegalStateException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ensureTickThread(final Level world, final int chunkX, final int chunkZ, final String reason) {
|
public static void ensureTickThread(final Level world, final int chunkX, final int chunkZ, final String reason) {
|
||||||
if (!isTickThreadFor(world, chunkX, chunkZ)) {
|
if (!isTickThreadFor(world, chunkX, chunkZ)) {
|
||||||
LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable());
|
final String ex = "Thread failed main thread check: " +
|
||||||
throw new IllegalStateException(reason);
|
reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", chunk_pos=" + new ChunkPos(chunkX, chunkZ);
|
||||||
|
LOGGER.error(ex, new Throwable());
|
||||||
|
throw new IllegalStateException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ensureTickThread(final Entity entity, final String reason) {
|
public static void ensureTickThread(final Entity entity, final String reason) {
|
||||||
if (!isTickThreadFor(entity)) {
|
if (!isTickThreadFor(entity)) {
|
||||||
LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable());
|
final String ex = "Thread failed main thread check: " +
|
||||||
throw new IllegalStateException(reason);
|
reason + ", context=" + getThreadContext() + ", entity=" + EntityUtil.dumpEntity(entity);
|
||||||
|
LOGGER.error(ex, new Throwable());
|
||||||
|
throw new IllegalStateException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ensureTickThread(final Level world, final AABB aabb, final String reason) {
|
public static void ensureTickThread(final Level world, final AABB aabb, final String reason) {
|
||||||
if (!isTickThreadFor(world, aabb)) {
|
if (!isTickThreadFor(world, aabb)) {
|
||||||
LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable());
|
final String ex = "Thread failed main thread check: " +
|
||||||
throw new IllegalStateException(reason);
|
reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", aabb=" + aabb;
|
||||||
|
LOGGER.error(ex, new Throwable());
|
||||||
|
throw new IllegalStateException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void ensureTickThread(final Level world, final double blockX, final double blockZ, final String reason) {
|
public static void ensureTickThread(final Level world, final double blockX, final double blockZ, final String reason) {
|
||||||
if (!isTickThreadFor(world, blockX, blockZ)) {
|
if (!isTickThreadFor(world, blockX, blockZ)) {
|
||||||
LOGGER.error("Thread " + Thread.currentThread().getName() + " failed main thread check: " + reason, new Throwable());
|
final String ex = "Thread failed main thread check: " +
|
||||||
throw new IllegalStateException(reason);
|
reason + ", context=" + getThreadContext() + ", world=" + WorldUtil.getWorldName(world) + ", block_pos=" + new Vec3(blockX, 0.0, blockZ);
|
||||||
|
LOGGER.error(ex, new Throwable());
|
||||||
|
throw new IllegalStateException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,6 +130,10 @@ public class TickThread extends Thread {
|
|||||||
return isTickThread();
|
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) {
|
public static boolean isTickThreadFor(final Level world, final ChunkPos pos) {
|
||||||
return isTickThread();
|
return isTickThread();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ abstract class LevelMixin implements LevelAccessor, AutoCloseable {
|
|||||||
|
|
||||||
if (doTick && this.shouldTickBlocksAt(tileEntity.getPos())) {
|
if (doTick && this.shouldTickBlocksAt(tileEntity.getPos())) {
|
||||||
tileEntity.tick();
|
tileEntity.tick();
|
||||||
// call mid tick tasks for chunk system
|
// call mid-tick tasks for chunk system
|
||||||
if ((++tickedEntities & 7) == 0) {
|
if ((++tickedEntities & 7) == 0) {
|
||||||
((ChunkSystemLevel)(Level)(Object)this).moonrise$midTickTasks();
|
((ChunkSystemLevel)(Level)(Object)this).moonrise$midTickTasks();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ abstract class StateHolderMixin<O, S> implements PropertyAccessStateHolder {
|
|||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public <T extends Comparable<T>> T getNullableValue(Property<T> property) {
|
public <T extends Comparable<T>> T getNullableValue(final Property<T> property) {
|
||||||
return property == null ? null : this.optimisedTable.get(this.tableIndex, property);
|
return property == null ? null : this.optimisedTable.get(this.tableIndex, property);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -166,7 +166,7 @@ abstract class StateHolderMixin<O, S> implements PropertyAccessStateHolder {
|
|||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public Map<Property<?>, Comparable<?>> getValues() {
|
public Map<Property<?>, Comparable<?>> getValues() {
|
||||||
ZeroCollidingReferenceStateTable<O, S> table = this.optimisedTable;
|
final ZeroCollidingReferenceStateTable<O, S> table = this.optimisedTable;
|
||||||
// We have to use this.values until the table is loaded
|
// We have to use this.values until the table is loaded
|
||||||
return table.isLoaded() ? table.getMapView(this.tableIndex) : this.values;
|
return table.isLoaded() ? table.getMapView(this.tableIndex) : this.values;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -366,7 +366,7 @@ abstract class ChunkHolderMixin extends GenerationChunkHolder implements ChunkSy
|
|||||||
/**
|
/**
|
||||||
* @reason Use ticket system to control ticket levels
|
* @reason Use ticket system to control ticket levels
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
* @see net.minecraft.server.level.ServerChunkCache#addRegionTicket(TicketType, ChunkPos, int, Object)
|
* @see net.minecraft.server.level.ServerChunkCache#addTicketWithRadius(TicketType, ChunkPos, int)
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public void setTicketLevel(int i) {
|
public void setTicketLevel(int i) {
|
||||||
@@ -397,8 +397,14 @@ abstract class ChunkHolderMixin extends GenerationChunkHolder implements ChunkSy
|
|||||||
* @reason Chunk system hooks for ticket level updating now in {@link NewChunkHolder#processTicketLevelUpdate(List, List)}
|
* @reason Chunk system hooks for ticket level updating now in {@link NewChunkHolder#processTicketLevelUpdate(List, List)}
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
// inject to avoid conflicting with fabric API's mixin here, we call their event in FabricHooks
|
||||||
public void updateFutures(final ChunkMap chunkMap, final Executor executor) {
|
@Inject(
|
||||||
|
method = "updateFutures",
|
||||||
|
at = @At(
|
||||||
|
value = "HEAD"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
public void clobberUpdateFutures(final ChunkMap chunkMap, final Executor executor, final CallbackInfo ci) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package ca.spottedleaf.moonrise.mixin.chunk_system;
|
|||||||
|
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemDistanceManager;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemDistanceManager;
|
||||||
import net.minecraft.server.level.ChunkMap;
|
import net.minecraft.server.level.ChunkMap;
|
||||||
|
import net.minecraft.world.level.TicketStorage;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
import org.spongepowered.asm.mixin.Final;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
@@ -15,8 +16,8 @@ abstract class ChunkMap$DistanceManagerMixin extends net.minecraft.server.level.
|
|||||||
@Final
|
@Final
|
||||||
ChunkMap field_17443;
|
ChunkMap field_17443;
|
||||||
|
|
||||||
protected ChunkMap$DistanceManagerMixin(Executor executor, Executor executor2) {
|
protected ChunkMap$DistanceManagerMixin(final TicketStorage p_394060_, final Executor p_140774_, final Executor p_140775_) {
|
||||||
super(executor, executor2);
|
super(p_394060_, p_140774_, p_140775_);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ import net.minecraft.util.Mth;
|
|||||||
import net.minecraft.util.StaticCache2D;
|
import net.minecraft.util.StaticCache2D;
|
||||||
import net.minecraft.util.thread.BlockableEventLoop;
|
import net.minecraft.util.thread.BlockableEventLoop;
|
||||||
import net.minecraft.world.level.ChunkPos;
|
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.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
@@ -43,7 +44,6 @@ import net.minecraft.world.level.chunk.storage.IOWorker;
|
|||||||
import net.minecraft.world.level.chunk.storage.RegionStorageInfo;
|
import net.minecraft.world.level.chunk.storage.RegionStorageInfo;
|
||||||
import net.minecraft.world.level.entity.ChunkStatusUpdateListener;
|
import net.minecraft.world.level.entity.ChunkStatusUpdateListener;
|
||||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||||
import net.minecraft.world.level.storage.DimensionDataStorage;
|
|
||||||
import net.minecraft.world.level.storage.LevelStorageSource;
|
import net.minecraft.world.level.storage.LevelStorageSource;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
import org.spongepowered.asm.mixin.Final;
|
||||||
@@ -124,11 +124,11 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
private void constructor(
|
private void constructor(
|
||||||
ServerLevel arg, LevelStorageSource.LevelStorageAccess arg2, DataFixer dataFixer,
|
ServerLevel p_214836_, LevelStorageSource.LevelStorageAccess p_214837_, DataFixer p_214838_,
|
||||||
StructureTemplateManager arg3, Executor executor, BlockableEventLoop<Runnable> arg4,
|
StructureTemplateManager p_214839_, Executor p_214840_, BlockableEventLoop p_214841_,
|
||||||
LightChunkGetter arg5, ChunkGenerator arg6, ChunkProgressListener arg7,
|
LightChunkGetter p_214842_, ChunkGenerator p_214843_, ChunkProgressListener p_214844_,
|
||||||
ChunkStatusUpdateListener arg8, Supplier<DimensionDataStorage> supplier, int j, boolean bl,
|
ChunkStatusUpdateListener p_214845_, Supplier p_214846_, TicketStorage p_394462_, int p_214847_,
|
||||||
final CallbackInfo ci) {
|
boolean p_214848_, CallbackInfo ci) {
|
||||||
// intentionally destroy old chunk system hooks
|
// intentionally destroy old chunk system hooks
|
||||||
this.updatingChunkMap = null;
|
this.updatingChunkMap = null;
|
||||||
this.visibleChunkMap = null;
|
this.visibleChunkMap = null;
|
||||||
@@ -143,7 +143,8 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
|
|||||||
// Dummy impl for mods that try to loadAsync directly
|
// Dummy impl for mods that try to loadAsync directly
|
||||||
this.worker = new IOWorker(
|
this.worker = new IOWorker(
|
||||||
// copied from super call
|
// copied from super call
|
||||||
new RegionStorageInfo(arg2.getLevelId(), arg.dimension(), "chunk"), arg2.getDimensionPath(arg.dimension()).resolve("region"), bl
|
new RegionStorageInfo(p_214837_.getLevelId(), p_214836_.dimension(), "chunk"),
|
||||||
|
p_214837_.getDimensionPath(p_214836_.dimension()).resolve("region"), p_214848_
|
||||||
) {
|
) {
|
||||||
@Override
|
@Override
|
||||||
public boolean isOldChunkAround(final ChunkPos chunkPos, final int i) {
|
public boolean isOldChunkAround(final ChunkPos chunkPos, final int i) {
|
||||||
@@ -543,13 +544,31 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
|
|||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Redirect(
|
@Redirect(
|
||||||
method = "forEachSpawnCandidateChunk",
|
method = "collectSpawningChunks",
|
||||||
at = @At(
|
at = @At(
|
||||||
value = "INVOKE",
|
value = "INVOKE",
|
||||||
target = "Lit/unimi/dsi/fastutil/longs/Long2ObjectLinkedOpenHashMap;get(J)Ljava/lang/Object;"
|
target = "Lit/unimi/dsi/fastutil/longs/Long2ObjectLinkedOpenHashMap;get(J)Ljava/lang/Object;"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
private <V> V redirectChunkHolderGet(final Long2ObjectLinkedOpenHashMap<V> instance, final long key) {
|
private <V> V redirectChunkHolderGetForSpawning(final Long2ObjectLinkedOpenHashMap<V> instance, final long key) {
|
||||||
|
return (V)this.getVisibleChunkIfPresent(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Route to new chunk system
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Redirect(
|
||||||
|
method = {
|
||||||
|
"method_67499",
|
||||||
|
"lambda$forEachBlockTickingChunk$36"
|
||||||
|
},
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "Lit/unimi/dsi/fastutil/longs/Long2ObjectLinkedOpenHashMap;get(J)Ljava/lang/Object;"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private <V> V redirectChunkHolderGetForBlockTicking(final Long2ObjectLinkedOpenHashMap<V> instance, final long key) {
|
||||||
return (V)this.getVisibleChunkIfPresent(key);
|
return (V)this.getVisibleChunkIfPresent(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,27 @@
|
|||||||
package ca.spottedleaf.moonrise.mixin.chunk_system;
|
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.common.util.MoonriseConstants;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemDistanceManager;
|
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.ChunkHolderManager;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder;
|
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketStorage;
|
||||||
|
import it.unimi.dsi.fastutil.longs.LongConsumer;
|
||||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||||
import net.minecraft.server.level.ChunkHolder;
|
import net.minecraft.server.level.ChunkHolder;
|
||||||
import net.minecraft.server.level.ChunkMap;
|
import net.minecraft.server.level.ChunkMap;
|
||||||
import net.minecraft.server.level.DistanceManager;
|
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.ThrottlingChunkTaskDispatcher;
|
||||||
import net.minecraft.server.level.Ticket;
|
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.Mth;
|
||||||
import net.minecraft.util.SortedArraySet;
|
|
||||||
import net.minecraft.world.level.ChunkPos;
|
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.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
@@ -24,6 +29,7 @@ import org.spongepowered.asm.mixin.injection.At;
|
|||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
|
||||||
@@ -31,13 +37,14 @@ import java.util.concurrent.Executor;
|
|||||||
abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
|
abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
Long2ObjectOpenHashMap<SortedArraySet<Ticket<?>>> tickets;
|
public LoadingChunkTracker loadingChunkTracker;
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
private DistanceManager.ChunkTicketTracker ticketTracker;
|
public SimulationChunkTracker simulationChunkTracker;
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
private TickingTracker tickingTicketsTracker;
|
@Final
|
||||||
|
private TicketStorage ticketStorage;
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
private DistanceManager.PlayerTicketTracker playerTicketManager;
|
private DistanceManager.PlayerTicketTracker playerTicketManager;
|
||||||
@@ -64,7 +71,8 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Destroy old chunk system state to prevent it from being used
|
* @reason Destroy old chunk system state to prevent it from being used, and set the chunk map
|
||||||
|
* for the ticket storage
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Inject(
|
@Inject(
|
||||||
@@ -74,15 +82,16 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
private void destroyFields(final CallbackInfo ci) {
|
private void destroyFields(final CallbackInfo ci) {
|
||||||
this.tickets = null;
|
this.loadingChunkTracker = null;
|
||||||
this.ticketTracker = null;
|
this.simulationChunkTracker = null;
|
||||||
this.tickingTicketsTracker = null;
|
|
||||||
this.playerTicketManager = null;
|
this.playerTicketManager = null;
|
||||||
this.chunksToUpdateFutures = null;
|
this.chunksToUpdateFutures = null;
|
||||||
this.ticketDispatcher = null;
|
this.ticketDispatcher = null;
|
||||||
this.ticketsToRelease = null;
|
this.ticketsToRelease = null;
|
||||||
this.mainThreadExecutor = null;
|
this.mainThreadExecutor = null;
|
||||||
this.simulationDistance = -1;
|
this.simulationDistance = -1;
|
||||||
|
|
||||||
|
((ChunkSystemTicketStorage)this.ticketStorage).moonrise$setChunkMap(this.moonrise$getChunkMap());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -90,15 +99,6 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
|
|||||||
return ((ChunkSystemServerLevel)this.moonrise$getChunkMap().level).moonrise$getChunkTaskScheduler().chunkHolderManager;
|
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
|
* @reason Route to new chunk system
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
@@ -108,46 +108,6 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
|
|||||||
return this.moonrise$getChunkHolderManager().processTicketUpdates();
|
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
|
* @reason Remove old chunk system hooks
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
@@ -170,11 +130,10 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
|
|||||||
method = "addPlayer",
|
method = "addPlayer",
|
||||||
at = @At(
|
at = @At(
|
||||||
value = "INVOKE",
|
value = "INVOKE",
|
||||||
target = "Lnet/minecraft/server/level/TickingTracker;addTicket(Lnet/minecraft/server/level/TicketType;Lnet/minecraft/world/level/ChunkPos;ILjava/lang/Object;)V"
|
target = "Lnet/minecraft/world/level/TicketStorage;addTicket(Lnet/minecraft/server/level/Ticket;Lnet/minecraft/world/level/ChunkPos;)V"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
private <T> void skipTickingTicketTrackerAdd(final TickingTracker instance, final TicketType<T> ticketType,
|
private void skipTickingTicketTrackerAdd(final TicketStorage instance, final Ticket ticket, final ChunkPos pos) {}
|
||||||
final ChunkPos chunkPos, final int i, final T object) {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Remove old chunk system hooks
|
* @reason Remove old chunk system hooks
|
||||||
@@ -213,11 +172,10 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
|
|||||||
method = "removePlayer",
|
method = "removePlayer",
|
||||||
at = @At(
|
at = @At(
|
||||||
value = "INVOKE",
|
value = "INVOKE",
|
||||||
target = "Lnet/minecraft/server/level/TickingTracker;removeTicket(Lnet/minecraft/server/level/TicketType;Lnet/minecraft/world/level/ChunkPos;ILjava/lang/Object;)V"
|
target = "Lnet/minecraft/world/level/TicketStorage;removeTicket(Lnet/minecraft/server/level/Ticket;Lnet/minecraft/world/level/ChunkPos;)V"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
private <T> void skipTickingTicketTrackerRemove(final TickingTracker instance, final TicketType<T> ticketType,
|
private void skipTickingTicketTrackerRemove(final TicketStorage instance, final Ticket ticket, final ChunkPos pos) {}
|
||||||
final ChunkPos chunkPos, final int i, final T object) {}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Remove old chunk system hooks
|
* @reason Remove old chunk system hooks
|
||||||
@@ -268,8 +226,9 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
|
|||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public String getTicketDebugString(final long pos) {
|
public int getChunkLevel(final long pos, final boolean simulation) {
|
||||||
return this.moonrise$getChunkHolderManager().getTicketDebugString(pos);
|
final NewChunkHolder chunkHolder = this.moonrise$getChunkHolderManager().getChunkHolder(pos);
|
||||||
|
return chunkHolder == null ? ChunkHolderManager.MAX_TICKET_LEVEL + 1 : chunkHolder.getTicketLevel();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -293,55 +252,30 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
|
|||||||
((ChunkSystemServerLevel)this.moonrise$getChunkMap().level).moonrise$getPlayerChunkLoader().setTickDistance(clamped);
|
((ChunkSystemServerLevel)this.moonrise$getChunkMap().level).moonrise$getPlayerChunkLoader().setTickDistance(clamped);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Route to new chunk system
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Overwrite
|
||||||
|
public void forEachEntityTickingChunk(final LongConsumer consumer) {
|
||||||
|
final ReferenceList<LevelChunk> chunks = ((ChunkSystemServerLevel)this.moonrise$getChunkMap().level).moonrise$getEntityTickingChunks();
|
||||||
|
final LevelChunk[] raw = chunks.getRawDataUnchecked();
|
||||||
|
final int size = chunks.size();
|
||||||
|
|
||||||
|
Objects.checkFromToIndex(0, size, raw.length);
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
final LevelChunk chunk = raw[i];
|
||||||
|
|
||||||
|
consumer.accept(CoordinateUtils.getChunkKey(chunk.getPos()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Route to new chunk system
|
* @reason Route to new chunk system
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public String getDebugStatus() {
|
public String getDebugStatus() {
|
||||||
return "No DistanceManager stats available";
|
return "N/A";
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @reason Remove old chunk system hooks
|
|
||||||
* @author Spottedleaf
|
|
||||||
*/
|
|
||||||
@Overwrite
|
|
||||||
public void dumpTickets(final String file) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @reason Remove old chunk system hooks
|
|
||||||
* @author Spottedleaf
|
|
||||||
*/
|
|
||||||
@Overwrite
|
|
||||||
public TickingTracker tickingTracker() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @reason Remove old chunk system hooks
|
|
||||||
* @author Spottedleaf
|
|
||||||
*/
|
|
||||||
@Overwrite
|
|
||||||
public LongSet getTickingChunks() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @reason This hack is not required anymore, see {@link MinecraftServerMixin}
|
|
||||||
* @author Spottedleaf
|
|
||||||
*/
|
|
||||||
@Overwrite
|
|
||||||
public void removeTicketsOnClosing() {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @reason This hack is not required anymore, see {@link MinecraftServerMixin}
|
|
||||||
* @author Spottedleaf
|
|
||||||
*/
|
|
||||||
@Overwrite
|
|
||||||
public boolean hasTickets() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
package ca.spottedleaf.moonrise.mixin.chunk_system;
|
||||||
|
|
||||||
|
import net.minecraft.core.SectionPos;
|
||||||
|
import net.minecraft.world.level.gameevent.DynamicGameEventListener;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(DynamicGameEventListener.class)
|
||||||
|
abstract class DynamicGameEventListenerMixin {
|
||||||
|
@Shadow
|
||||||
|
@Nullable
|
||||||
|
private SectionPos lastSection;
|
||||||
|
|
||||||
|
@Inject(
|
||||||
|
method = "remove",
|
||||||
|
at = @At("RETURN")
|
||||||
|
)
|
||||||
|
private void onRemove(final CallbackInfo ci) {
|
||||||
|
// We need to unset the last section when removed, otherwise if the same instance is re-added at the same position it
|
||||||
|
// will assume there was no change and fail to re-register.
|
||||||
|
// In vanilla, chunks rarely unload and re-load quickly enough to trigger this issue. However, our chunk system has a
|
||||||
|
// quirk where fast chunk reload cycles will often occur on player login (see PR #22).
|
||||||
|
// So we fix this vanilla oversight as our changes cause it to manifest in bugs much more often (see issue #87).
|
||||||
|
this.lastSection = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkData;
|
|||||||
import ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity;
|
import ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.mojang.logging.LogUtils;
|
||||||
import net.minecraft.server.level.FullChunkStatus;
|
import net.minecraft.server.level.FullChunkStatus;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.player.Player;
|
import net.minecraft.world.entity.player.Player;
|
||||||
@@ -32,10 +33,6 @@ abstract class EntityMixin implements ChunkSystemEntity {
|
|||||||
@Shadow
|
@Shadow
|
||||||
protected abstract Stream<Entity> getIndirectPassengersStream();
|
protected abstract Stream<Entity> getIndirectPassengersStream();
|
||||||
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
private static Logger LOGGER;
|
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
private Level level;
|
private Level level;
|
||||||
|
|
||||||
@@ -43,6 +40,8 @@ abstract class EntityMixin implements ChunkSystemEntity {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private Entity.RemovalReason removalReason;
|
private Entity.RemovalReason removalReason;
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private static final Logger LOGGER = LogUtils.getLogger();
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private final boolean isHardColliding = this.moonrise$isHardCollidingUncached();
|
private final boolean isHardColliding = this.moonrise$isHardCollidingUncached();
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ abstract class EntityTickListMixin {
|
|||||||
private Int2ObjectMap<Entity> passive;
|
private Int2ObjectMap<Entity> passive;
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private final IteratorSafeOrderedReferenceSet<Entity> entities = new IteratorSafeOrderedReferenceSet<>();
|
private final IteratorSafeOrderedReferenceSet<Entity> entities = new IteratorSafeOrderedReferenceSet<>(Entity.class);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Initialise new fields and destroy old state
|
* @reason Initialise new fields and destroy old state
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package ca.spottedleaf.moonrise.mixin.chunk_system;
|
package ca.spottedleaf.moonrise.mixin.chunk_system;
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk;
|
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 ca.spottedleaf.moonrise.patches.chunk_system.ticks.ChunkSystemLevelChunkTicks;
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.server.level.ServerChunkCache;
|
import net.minecraft.server.level.ServerChunkCache;
|
||||||
@@ -48,7 +49,7 @@ abstract class LevelChunkMixin extends ChunkAccess implements ChunkSystemLevelCh
|
|||||||
private boolean postProcessingDone;
|
private boolean postProcessingDone;
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private ServerChunkCache.ChunkAndHolder chunkAndHolder;
|
private NewChunkHolder chunkAndHolder;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean moonrise$isPostProcessingDone() {
|
public final boolean moonrise$isPostProcessingDone() {
|
||||||
@@ -56,12 +57,12 @@ abstract class LevelChunkMixin extends ChunkAccess implements ChunkSystemLevelCh
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final ServerChunkCache.ChunkAndHolder moonrise$getChunkAndHolder() {
|
public final NewChunkHolder moonrise$getChunkHolder() {
|
||||||
return this.chunkAndHolder;
|
return this.chunkAndHolder;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void moonrise$setChunkAndHolder(final ServerChunkCache.ChunkAndHolder holder) {
|
public final void moonrise$setChunkHolder(final NewChunkHolder holder) {
|
||||||
this.chunkAndHolder = holder;
|
this.chunkAndHolder = holder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -105,12 +105,12 @@ abstract class LevelChunkTicksMixin<T> implements ChunkSystemLevelChunkTicks, Se
|
|||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Inject(
|
@Inject(
|
||||||
method = "save(JLjava/util/function/Function;)Lnet/minecraft/nbt/ListTag;",
|
method = "pack",
|
||||||
at = @At(
|
at = @At(
|
||||||
value = "HEAD"
|
value = "HEAD"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
private void saveHook(final long time, final Function<T, String> idFunction, final CallbackInfoReturnable<ListTag> cir) {
|
private void saveHook(final long time, final CallbackInfoReturnable<ListTag> cir) {
|
||||||
this.lastSaved = time;
|
this.lastSaved = time;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -190,6 +190,11 @@ abstract class MinecraftServerMixin extends ReentrantBlockableEventLoop<TickTask
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
private boolean doNotWaitChunkSystemShutdown(final Stream<ServerLevel> instance, final Predicate<? super ServerLevel> predicate) {
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,9 +243,9 @@ abstract class MinecraftServerMixin extends ReentrantBlockableEventLoop<TickTask
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
private void closeIOThreads(final CallbackInfo ci) {
|
private void closeIOThreads(final CallbackInfo ci) {
|
||||||
LOGGER.info("Waiting for I/O tasks to complete...");
|
LOGGER.info("Waiting for all RegionFile I/O tasks to complete...");
|
||||||
MoonriseRegionFileIO.flush((MinecraftServer)(Object)this);
|
MoonriseRegionFileIO.flush((MinecraftServer)(Object)this);
|
||||||
LOGGER.info("All I/O tasks to complete");
|
LOGGER.info("All RegionFile I/O tasks to complete");
|
||||||
if ((Object)this instanceof DedicatedServer) {
|
if ((Object)this instanceof DedicatedServer) {
|
||||||
MoonriseCommon.haltExecutors();
|
MoonriseCommon.haltExecutors();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,18 +3,17 @@ package ca.spottedleaf.moonrise.mixin.chunk_system;
|
|||||||
import ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable;
|
import ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable;
|
||||||
import ca.spottedleaf.concurrentutil.util.Priority;
|
import ca.spottedleaf.concurrentutil.util.Priority;
|
||||||
import ca.spottedleaf.moonrise.common.PlatformHooks;
|
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.CoordinateUtils;
|
||||||
import ca.spottedleaf.moonrise.common.util.TickThread;
|
import ca.spottedleaf.moonrise.common.util.TickThread;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager;
|
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.ChunkTaskScheduler;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder;
|
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 ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemServerChunkCache;
|
||||||
import net.minecraft.server.level.ChunkHolder;
|
import net.minecraft.server.level.ChunkHolder;
|
||||||
import net.minecraft.server.level.ChunkLevel;
|
import net.minecraft.server.level.ChunkLevel;
|
||||||
import net.minecraft.server.level.ChunkResult;
|
import net.minecraft.server.level.ChunkResult;
|
||||||
|
import net.minecraft.server.level.DistanceManager;
|
||||||
import net.minecraft.server.level.FullChunkStatus;
|
import net.minecraft.server.level.FullChunkStatus;
|
||||||
import net.minecraft.server.level.ServerChunkCache;
|
import net.minecraft.server.level.ServerChunkCache;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
@@ -35,8 +34,6 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
|||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
@@ -59,9 +56,6 @@ abstract class ServerChunkCacheMixin extends ChunkSource implements ChunkSystemS
|
|||||||
@Unique
|
@Unique
|
||||||
private final ConcurrentLong2ReferenceChainedHashTable<LevelChunk> fullChunks = new ConcurrentLong2ReferenceChainedHashTable<>();
|
private final ConcurrentLong2ReferenceChainedHashTable<LevelChunk> fullChunks = new ConcurrentLong2ReferenceChainedHashTable<>();
|
||||||
|
|
||||||
@Unique
|
|
||||||
private long chunksTicked;
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void moonrise$setFullChunk(final int chunkX, final int chunkZ, final LevelChunk chunk) {
|
public final void moonrise$setFullChunk(final int chunkX, final int chunkZ, final LevelChunk chunk) {
|
||||||
final long key = CoordinateUtils.getChunkKey(chunkX, chunkZ);
|
final long key = CoordinateUtils.getChunkKey(chunkX, chunkZ);
|
||||||
@@ -339,38 +333,34 @@ abstract class ServerChunkCacheMixin extends ChunkSource implements ChunkSystemS
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Perform mid-tick chunk task processing during chunk tick
|
* @reason In the chunk system, spawn chunks will return only entity ticking chunks - we can elide the
|
||||||
* @author Spottedleaf
|
* entity ticking range check.
|
||||||
*/
|
|
||||||
@Inject(
|
|
||||||
method = "tickChunks(Lnet/minecraft/util/profiling/ProfilerFiller;JLjava/util/List;)V",
|
|
||||||
at = @At(
|
|
||||||
value = "INVOKE",
|
|
||||||
shift = At.Shift.AFTER,
|
|
||||||
target = "Lnet/minecraft/server/level/ServerLevel;tickChunk(Lnet/minecraft/world/level/chunk/LevelChunk;I)V"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
private void midTickChunks(final CallbackInfo ci) {
|
|
||||||
if ((++this.chunksTicked & 7L) != 0L) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
((ChunkSystemMinecraftServer)this.level.getServer()).moonrise$executeMidTickTasks();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @reason In the chunk system, ticking chunks always have loaded entities. Of course, they are also always
|
|
||||||
* marked to be as ticking as well.
|
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Redirect(
|
@Redirect(
|
||||||
method = "tickChunks(Lnet/minecraft/util/profiling/ProfilerFiller;JLjava/util/List;)V",
|
method = "tickSpawningChunk",
|
||||||
at = @At(
|
at = @At(
|
||||||
value = "INVOKE",
|
value = "INVOKE",
|
||||||
target = "Lnet/minecraft/server/level/ServerLevel;shouldTickBlocksAt(J)Z"
|
target = "Lnet/minecraft/server/level/DistanceManager;inEntityTickingRange(J)Z"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
private boolean shortShouldTickBlocks(final ServerLevel instance, final long pos) {
|
private boolean shortTickThunder(final DistanceManager instance, final long pos) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason In the chunk system, spawn chunks will return only entity ticking chunks - we can elide the
|
||||||
|
* entity ticking check.
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Redirect(
|
||||||
|
method = "tickSpawningChunk",
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "Lnet/minecraft/server/level/ServerLevel;canSpawnEntitiesInChunk(Lnet/minecraft/world/level/ChunkPos;)Z"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private boolean onlyCheckWBForSpawning(final ServerLevel instance, final ChunkPos pos) {
|
||||||
|
return instance.getWorldBorder().isWithinBounds(pos);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.EntityData
|
|||||||
import ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.PoiDataController;
|
import ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.PoiDataController;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevelReader;
|
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.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.level.entity.server.ServerEntityLookup;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader;
|
import ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager;
|
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager;
|
||||||
@@ -27,13 +26,11 @@ import net.minecraft.core.Holder;
|
|||||||
import net.minecraft.core.RegistryAccess;
|
import net.minecraft.core.RegistryAccess;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
import net.minecraft.server.level.ChunkHolder;
|
|
||||||
import net.minecraft.server.level.ChunkMap;
|
import net.minecraft.server.level.ChunkMap;
|
||||||
import net.minecraft.server.level.DistanceManager;
|
import net.minecraft.server.level.DistanceManager;
|
||||||
import net.minecraft.server.level.ServerChunkCache;
|
import net.minecraft.server.level.ServerChunkCache;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.progress.ChunkProgressListener;
|
import net.minecraft.server.level.progress.ChunkProgressListener;
|
||||||
import net.minecraft.util.profiling.ProfilerFiller;
|
|
||||||
import net.minecraft.world.RandomSequences;
|
import net.minecraft.world.RandomSequences;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
@@ -64,12 +61,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
import java.util.function.Supplier;
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@Mixin(ServerLevel.class)
|
@Mixin(ServerLevel.class)
|
||||||
@@ -121,16 +116,16 @@ abstract class ServerLevelMixin extends Level implements ChunkSystemServerLevel,
|
|||||||
private final NearbyPlayers nearbyPlayers = new NearbyPlayers((ServerLevel)(Object)this);
|
private final NearbyPlayers nearbyPlayers = new NearbyPlayers((ServerLevel)(Object)this);
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private static final ServerChunkCache.ChunkAndHolder[] EMPTY_CHUNK_AND_HOLDERS = new ServerChunkCache.ChunkAndHolder[0];
|
private static final LevelChunk[] EMPTY_LEVEL_CHUNKS = new LevelChunk[0];
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private final ReferenceList<ServerChunkCache.ChunkAndHolder> loadedChunks = new ReferenceList<>(EMPTY_CHUNK_AND_HOLDERS);
|
private final ReferenceList<LevelChunk> loadedChunks = new ReferenceList<>(EMPTY_LEVEL_CHUNKS);
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private final ReferenceList<ServerChunkCache.ChunkAndHolder> tickingChunks = new ReferenceList<>(EMPTY_CHUNK_AND_HOLDERS);
|
private final ReferenceList<LevelChunk> tickingChunks = new ReferenceList<>(EMPTY_LEVEL_CHUNKS);
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private final ReferenceList<ServerChunkCache.ChunkAndHolder> entityTickingChunks = new ReferenceList<>(EMPTY_CHUNK_AND_HOLDERS);
|
private final ReferenceList<LevelChunk> entityTickingChunks = new ReferenceList<>(EMPTY_LEVEL_CHUNKS);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Initialise fields / destroy entity manager state
|
* @reason Initialise fields / destroy entity manager state
|
||||||
@@ -334,17 +329,17 @@ abstract class ServerLevelMixin extends Level implements ChunkSystemServerLevel,
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final ReferenceList<ServerChunkCache.ChunkAndHolder> moonrise$getLoadedChunks() {
|
public final ReferenceList<LevelChunk> moonrise$getLoadedChunks() {
|
||||||
return this.loadedChunks;
|
return this.loadedChunks;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final ReferenceList<ServerChunkCache.ChunkAndHolder> moonrise$getTickingChunks() {
|
public final ReferenceList<LevelChunk> moonrise$getTickingChunks() {
|
||||||
return this.tickingChunks;
|
return this.tickingChunks;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final ReferenceList<ServerChunkCache.ChunkAndHolder> moonrise$getEntityTickingChunks() {
|
public final ReferenceList<LevelChunk> moonrise$getEntityTickingChunks() {
|
||||||
return this.entityTickingChunks;
|
return this.entityTickingChunks;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -612,6 +607,22 @@ abstract class ServerLevelMixin extends Level implements ChunkSystemServerLevel,
|
|||||||
this.moonrise$getEntityLookup().addWorldGenChunkEntities(stream.toList(), null); // TODO
|
this.moonrise$getEntityLookup().addWorldGenChunkEntities(stream.toList(), null); // TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Not needed in new chunk system, also avoid accessing old entity manager
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Redirect(
|
||||||
|
method = {
|
||||||
|
"method_72080",
|
||||||
|
"lambda$waitForChunkAndEntities$21"
|
||||||
|
},
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "Lnet/minecraft/world/level/entity/PersistentEntitySectionManager;processPendingLoads()V"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private void redirectWaitForChunks(final PersistentEntitySectionManager<Entity> instance) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Level close now handles this
|
* @reason Level close now handles this
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
@@ -666,7 +677,7 @@ abstract class ServerLevelMixin extends Level implements ChunkSystemServerLevel,
|
|||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public boolean isPositionEntityTicking(BlockPos pos) {
|
public boolean isPositionEntityTicking(final BlockPos pos) {
|
||||||
final NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(CoordinateUtils.getChunkKey(pos));
|
final NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(CoordinateUtils.getChunkKey(pos));
|
||||||
return chunkHolder != null && chunkHolder.isEntityTickingReady();
|
return chunkHolder != null && chunkHolder.isEntityTickingReady();
|
||||||
}
|
}
|
||||||
@@ -676,7 +687,7 @@ abstract class ServerLevelMixin extends Level implements ChunkSystemServerLevel,
|
|||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public boolean isNaturalSpawningAllowed(final BlockPos pos) {
|
public boolean areEntitiesActuallyLoadedAndTicking(final ChunkPos pos) {
|
||||||
final NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(CoordinateUtils.getChunkKey(pos));
|
final NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(CoordinateUtils.getChunkKey(pos));
|
||||||
return chunkHolder != null && chunkHolder.isEntityTickingReady();
|
return chunkHolder != null && chunkHolder.isEntityTickingReady();
|
||||||
}
|
}
|
||||||
@@ -685,8 +696,14 @@ abstract class ServerLevelMixin extends Level implements ChunkSystemServerLevel,
|
|||||||
* @reason Redirect to chunk system
|
* @reason Redirect to chunk system
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Redirect(
|
||||||
public boolean isNaturalSpawningAllowed(final ChunkPos pos) {
|
method = "canSpawnEntitiesInChunk",
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "Lnet/minecraft/world/level/entity/PersistentEntitySectionManager;canPositionTick(Lnet/minecraft/world/level/ChunkPos;)Z"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private <T extends EntityAccess> boolean redirectCanEntitiesSpawnTickCheck(final PersistentEntitySectionManager<T> instance, final ChunkPos pos) {
|
||||||
final NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(CoordinateUtils.getChunkKey(pos));
|
final NewChunkHolder chunkHolder = this.moonrise$getChunkTaskScheduler().chunkHolderManager.getChunkHolder(CoordinateUtils.getChunkKey(pos));
|
||||||
return chunkHolder != null && chunkHolder.isEntityTickingReady();
|
return chunkHolder != null && chunkHolder.isEntityTickingReady();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,8 +15,8 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
|
|
||||||
@Mixin(ServerPlayer.class)
|
@Mixin(ServerPlayer.class)
|
||||||
abstract class ServerPlayerMixin extends Player implements ChunkSystemServerPlayer {
|
abstract class ServerPlayerMixin extends Player implements ChunkSystemServerPlayer {
|
||||||
public ServerPlayerMixin(Level level, BlockPos blockPos, float f, GameProfile gameProfile) {
|
public ServerPlayerMixin(final Level p_250508_, final GameProfile p_252153_) {
|
||||||
super(level, blockPos, f, gameProfile);
|
super(p_250508_, p_252153_);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
|
|||||||
@@ -49,8 +49,7 @@ abstract class SortedArraySetMixin<T> extends AbstractSet<T> implements ChunkSys
|
|||||||
if (i >= len) {
|
if (i >= len) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!filter.test(backingArray[i])) {
|
if (!filter.test(backingArray[i++])) {
|
||||||
++i;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -58,7 +57,7 @@ abstract class SortedArraySetMixin<T> extends AbstractSet<T> implements ChunkSys
|
|||||||
|
|
||||||
// we only want to write back to backingArray if we really need to
|
// we only want to write back to backingArray if we really need to
|
||||||
|
|
||||||
int lastIndex = i; // this is where new elements are shifted to
|
int lastIndex = i - 1; // this is where new elements are shifted to
|
||||||
|
|
||||||
for (; i < len; ++i) {
|
for (; i < len; ++i) {
|
||||||
final T curr = backingArray[i];
|
final T curr = backingArray[i];
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package ca.spottedleaf.moonrise.mixin.chunk_system;
|
package ca.spottedleaf.moonrise.mixin.chunk_system;
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicket;
|
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.Ticket;
|
||||||
import net.minecraft.server.level.TicketType;
|
import net.minecraft.server.level.TicketType;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
import org.spongepowered.asm.mixin.Final;
|
||||||
@@ -8,61 +9,75 @@ import org.spongepowered.asm.mixin.Mixin;
|
|||||||
import org.spongepowered.asm.mixin.Overwrite;
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
@Mixin(Ticket.class)
|
@Mixin(Ticket.class)
|
||||||
abstract class TicketMixin<T> implements ChunkSystemTicket<T>, Comparable<Ticket<?>> {
|
abstract class TicketMixin<T> implements ChunkSystemTicket<T>, Comparable<Ticket> {
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
@Final
|
@Final
|
||||||
private TicketType<T> type;
|
private TicketType type;
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
@Final
|
@Final
|
||||||
private int ticketLevel;
|
private int ticketLevel;
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
@Final
|
private long ticksLeft;
|
||||||
public T key;
|
|
||||||
|
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private long removeDelay;
|
private T identifier;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final long moonrise$getRemoveDelay() {
|
public final long moonrise$getRemoveDelay() {
|
||||||
return this.removeDelay;
|
return this.ticksLeft;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void moonrise$setRemoveDelay(final long removeDelay) {
|
public final void moonrise$setRemoveDelay(final long removeDelay) {
|
||||||
this.removeDelay = removeDelay;
|
this.ticksLeft = removeDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final T moonrise$getIdentifier() {
|
||||||
|
return this.identifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void moonrise$setIdentifier(final T identifier) {
|
||||||
|
if ((identifier == null) != (((ChunkSystemTicketType<T>)(Object)this.type).moonrise$getIdentifierComparator() == null)) {
|
||||||
|
throw new IllegalStateException("Nullability of identifier should match nullability of comparator");
|
||||||
|
}
|
||||||
|
this.identifier = identifier;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Change debug to include remove delay
|
* @reason Change debug to include remove identifier
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Ticket[" + this.type + " " + this.ticketLevel + " (" + this.key + ")] to die in " + this.removeDelay;
|
return "Ticket[" + this.type + " " + this.ticketLevel + " (" + this.identifier + ")] to die in " + this.ticksLeft;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* @reason Remove old chunk system hook
|
public final int compareTo(final Ticket ticket) {
|
||||||
* @author Spottedleaf
|
final int levelCompare = Integer.compare(this.ticketLevel, ((TicketMixin<?>)(Object)ticket).ticketLevel);
|
||||||
*/
|
if (levelCompare != 0) {
|
||||||
@Overwrite
|
return levelCompare;
|
||||||
public void setCreatedTick(final long tickCreated) {
|
}
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
final int typeCompare = Long.compare(
|
||||||
* @reason Remove old chunk system hook
|
((ChunkSystemTicketType<T>)(Object)this.type).moonrise$getId(),
|
||||||
* @author Spottedleaf
|
((ChunkSystemTicketType<?>)(Object)((TicketMixin<?>)(Object)ticket).type).moonrise$getId()
|
||||||
*/
|
);
|
||||||
@Overwrite
|
if (typeCompare != 0) {
|
||||||
public boolean timedOut(final long currentTick) {
|
return typeCompare;
|
||||||
throw new UnsupportedOperationException();
|
}
|
||||||
|
|
||||||
|
final Comparator<T> comparator = ((ChunkSystemTicketType<T>)(Object)this.type).moonrise$getIdentifierComparator();
|
||||||
|
return comparator == null ? 0 : comparator.compare(this.identifier, ((TicketMixin<T>)(Object)ticket).identifier);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,261 @@
|
|||||||
|
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.BiPredicate;
|
||||||
|
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(final ChunkMap chunkMap) {
|
||||||
|
((ChunkSystemServerLevel)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/BiPredicate;Lit/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap;)V"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private void avoidRemovingTicketsOnShutdown(final TicketStorage instance,
|
||||||
|
final BiPredicate<Long, Ticket> predicate,
|
||||||
|
final Long2ObjectOpenHashMap<List<Ticket>> tickets) {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Destroy old chunk system hooks
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Overwrite
|
||||||
|
public void removeTicketIf(final BiPredicate<Long, Ticket> predicate, final Long2ObjectOpenHashMap<List<Ticket>> into) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Destroy old chunk system hooks
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Overwrite
|
||||||
|
public void replaceTicketLevelOfType(final int newLevel, final TicketType forType) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Route to new chunk system
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Overwrite
|
||||||
|
public LongSet getForceLoadedChunks() {
|
||||||
|
final Long2IntOpenHashMap forced = ((ChunkSystemServerLevel)this.chunkMap.level).moonrise$getChunkTaskScheduler()
|
||||||
|
.chunkHolderManager.getTicketCounters(ChunkSystemTicketType.COUNTER_TYPE_FORCED);
|
||||||
|
|
||||||
|
if (forced == null) {
|
||||||
|
return LongSet.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
return forced.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Destroy old chunk system hooks
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Overwrite
|
||||||
|
public LongSet getAllChunksWithTicketThat(final Predicate<Ticket> predicate) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package ca.spottedleaf.moonrise.mixin.chunk_system;
|
||||||
|
|
||||||
|
import ca.spottedleaf.moonrise.common.PlatformHooks;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType;
|
||||||
|
import net.minecraft.server.level.TicketType;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Mutable;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
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> {
|
||||||
|
|
||||||
|
@Final
|
||||||
|
@Shadow
|
||||||
|
@Mutable
|
||||||
|
private long timeout;
|
||||||
|
|
||||||
|
@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);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void moonrise$setTimeout(final long to) {
|
||||||
|
this.timeout = to;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
package ca.spottedleaf.moonrise.mixin.chunk_system;
|
||||||
|
|
||||||
|
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.player.ChunkSystemServerPlayer;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.world.level.ChunkPos;
|
||||||
|
import net.minecraft.world.waypoints.Waypoint;
|
||||||
|
import net.minecraft.world.waypoints.WaypointTransmitter;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
|
|
||||||
|
@Mixin(WaypointTransmitter.class)
|
||||||
|
interface WaypointTransmitterMixin extends Waypoint {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Redirect to the new player chunk loader, as the Vanilla chunk tracker is set to empty on Moonrise
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Overwrite
|
||||||
|
public static boolean isChunkVisible(final ChunkPos pos, final ServerPlayer player) {
|
||||||
|
final RegionizedPlayerChunkLoader.PlayerChunkLoaderData playerChunkLoader = ((ChunkSystemServerPlayer)player).moonrise$getChunkLoader();
|
||||||
|
return playerChunkLoader != null && playerChunkLoader.getSentChunksRaw().contains(CoordinateUtils.getChunkKey(pos));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -2,18 +2,27 @@ package ca.spottedleaf.moonrise.mixin.chunk_tick_iteration;
|
|||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.list.ReferenceList;
|
import ca.spottedleaf.moonrise.common.list.ReferenceList;
|
||||||
import ca.spottedleaf.moonrise.common.misc.NearbyPlayers;
|
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.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.ChunkTickDistanceManager;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickServerLevel;
|
||||||
import com.llamalad7.mixinextras.sugar.Local;
|
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.core.SectionPos;
|
||||||
import net.minecraft.server.level.ChunkMap;
|
import net.minecraft.server.level.ChunkMap;
|
||||||
|
import net.minecraft.server.level.ServerChunkCache;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.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.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
@@ -85,11 +94,15 @@ abstract class ChunkMapMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Avoid checking first if there are nearby players, as we make internal perform this implicitly.
|
* @reason Avoid checking for DEFAULT state, as we make internal perform this implicitly.
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public boolean anyPlayerCloseEnoughForSpawning(final ChunkPos pos) {
|
public boolean anyPlayerCloseEnoughForSpawning(final ChunkPos pos) {
|
||||||
|
if (((ChunkTickDistanceManager)this.distanceManager).moonrise$hasAnyNearbyNarrow(pos.x, pos.z)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
return this.anyPlayerCloseEnoughForSpawningInternal(pos);
|
return this.anyPlayerCloseEnoughForSpawningInternal(pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,4 +165,111 @@ abstract class ChunkMapMixin {
|
|||||||
|
|
||||||
return ret == null ? new ArrayList<>() : ret;
|
return ret == null ? new ArrayList<>() : ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private boolean isChunkNearPlayer(final ChunkMap chunkMap, final ChunkPos chunkPos, final LevelChunk levelChunk) {
|
||||||
|
final ChunkData chunkData = ((ChunkSystemLevelChunk)levelChunk).moonrise$getChunkHolder().holderData;
|
||||||
|
final NearbyPlayers.TrackedChunk nearbyPlayers = chunkData.nearbyPlayers;
|
||||||
|
if (nearbyPlayers == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((ChunkTickDistanceManager)this.distanceManager).moonrise$hasAnyNearbyNarrow(chunkPos.x, chunkPos.z)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ReferenceList<ServerPlayer> players = nearbyPlayers.getPlayers(NearbyPlayers.NearbyMapType.SPAWN_RANGE);
|
||||||
|
|
||||||
|
if (players == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final ServerPlayer[] raw = players.getRawDataUnchecked();
|
||||||
|
final int len = players.size();
|
||||||
|
|
||||||
|
Objects.checkFromIndexSize(0, len, raw.length);
|
||||||
|
for (int i = 0; i < len; ++i) {
|
||||||
|
if (chunkMap.playerIsCloseEnoughForSpawning(raw[i], chunkPos)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Use the player ticking chunks list, which already contains chunks that are:
|
||||||
|
* 1. entity ticking
|
||||||
|
* 2. within spawn range (8 chunks on any axis)
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Inject(
|
||||||
|
method = "collectSpawningChunks",
|
||||||
|
// use cancellable inject to be compatible with the chunk system's hook here
|
||||||
|
cancellable = true,
|
||||||
|
at = @At(
|
||||||
|
value = "HEAD"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
public void collectSpawningChunks(final List<LevelChunk> list, final CallbackInfo ci) {
|
||||||
|
final ReferenceList<LevelChunk> tickingChunks = ((ChunkTickServerLevel)this.level).moonrise$getPlayerTickingChunks();
|
||||||
|
|
||||||
|
final Long2IntOpenHashMap forceSpawningChunks = ((ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler()
|
||||||
|
.chunkHolderManager.getTicketCounters(ChunkSystemTicketType.COUNTER_TYPER_NATURAL_SPAWNING_FORCED);
|
||||||
|
|
||||||
|
final LevelChunk[] raw = tickingChunks.getRawDataUnchecked();
|
||||||
|
final int size = tickingChunks.size();
|
||||||
|
|
||||||
|
Objects.checkFromToIndex(0, size, raw.length);
|
||||||
|
|
||||||
|
if (forceSpawningChunks != null && !forceSpawningChunks.isEmpty()) {
|
||||||
|
// note: expect forceSpawningChunks.size <<< tickingChunks.size
|
||||||
|
final LongOpenHashSet seen = new LongOpenHashSet(forceSpawningChunks.size());
|
||||||
|
|
||||||
|
final ChunkHolderManager chunkHolderManager = ((ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager;
|
||||||
|
|
||||||
|
// note: this fixes a bug in neoforge where these chunks don't tick away from a player...
|
||||||
|
// note: this is NOT the only problem with their implementation, either...
|
||||||
|
for (final LongIterator iterator = forceSpawningChunks.keySet().longIterator(); iterator.hasNext();) {
|
||||||
|
final long pos = iterator.nextLong();
|
||||||
|
|
||||||
|
final NewChunkHolder holder = chunkHolderManager.getChunkHolder(pos);
|
||||||
|
|
||||||
|
if (holder == null || !holder.isEntityTickingReady()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
seen.add(pos);
|
||||||
|
|
||||||
|
list.add((LevelChunk)holder.getCurrentChunk());
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
final LevelChunk levelChunk = raw[i];
|
||||||
|
|
||||||
|
if (seen.contains(CoordinateUtils.getChunkKey(levelChunk.getPos()))) {
|
||||||
|
// do not add duplicate chunks
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.isChunkNearPlayer((ChunkMap)(Object)this, levelChunk.getPos(), levelChunk)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
list.add(levelChunk);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
final LevelChunk levelChunk = raw[i];
|
||||||
|
|
||||||
|
if (!this.isChunkNearPlayer((ChunkMap)(Object)this, levelChunk.getPos(), levelChunk)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
list.add(levelChunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import it.unimi.dsi.fastutil.longs.LongIterator;
|
|||||||
import net.minecraft.core.SectionPos;
|
import net.minecraft.core.SectionPos;
|
||||||
import net.minecraft.server.level.DistanceManager;
|
import net.minecraft.server.level.DistanceManager;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.util.TriState;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
@@ -21,20 +22,24 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
abstract class DistanceManagerMixin implements ChunkTickDistanceManager {
|
abstract class DistanceManagerMixin implements ChunkTickDistanceManager {
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
private DistanceManager.FixedPlayerDistanceChunkTracker naturalSpawnChunkCounter;
|
public DistanceManager.FixedPlayerDistanceChunkTracker naturalSpawnChunkCounter;
|
||||||
|
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private final PositionCountingAreaMap<ServerPlayer> spawnChunkTracker = new PositionCountingAreaMap<>();
|
private final PositionCountingAreaMap<ServerPlayer> spawnChunkTracker = new PositionCountingAreaMap<>();
|
||||||
|
@Unique
|
||||||
|
private final PositionCountingAreaMap<ServerPlayer> narrowSpawnChunkTracker = new PositionCountingAreaMap<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void moonrise$addPlayer(final ServerPlayer player, final SectionPos pos) {
|
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.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
|
@Override
|
||||||
public final void moonrise$removePlayer(final ServerPlayer player, final SectionPos pos) {
|
public final void moonrise$removePlayer(final ServerPlayer player, final SectionPos pos) {
|
||||||
this.spawnChunkTracker.remove(player);
|
this.spawnChunkTracker.remove(player);
|
||||||
|
this.narrowSpawnChunkTracker.remove(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -43,11 +48,18 @@ abstract class DistanceManagerMixin implements ChunkTickDistanceManager {
|
|||||||
final boolean oldIgnore, final boolean newIgnore) {
|
final boolean oldIgnore, final boolean newIgnore) {
|
||||||
if (newIgnore) {
|
if (newIgnore) {
|
||||||
this.spawnChunkTracker.remove(player);
|
this.spawnChunkTracker.remove(player);
|
||||||
|
this.narrowSpawnChunkTracker.remove(player);
|
||||||
} else {
|
} else {
|
||||||
this.spawnChunkTracker.addOrUpdate(player, newPos.x(), newPos.z(), ChunkTickConstants.PLAYER_SPAWN_TRACK_RANGE);
|
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
|
* @reason Destroy natural spawning tracker field to prevent it from being used
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
@@ -104,8 +116,11 @@ abstract class DistanceManagerMixin implements ChunkTickDistanceManager {
|
|||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public boolean hasPlayersNearby(final long pos) {
|
public TriState hasPlayersNearby(final long pos) {
|
||||||
return this.spawnChunkTracker.hasObjectsNear(CoordinateUtils.getChunkX(pos), CoordinateUtils.getChunkZ(pos));
|
if (this.narrowSpawnChunkTracker.hasObjectsNear(pos)) {
|
||||||
|
return TriState.TRUE;
|
||||||
|
}
|
||||||
|
return this.spawnChunkTracker.hasObjectsNear(pos) ? TriState.DEFAULT : TriState.FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,30 +1,26 @@
|
|||||||
package ca.spottedleaf.moonrise.mixin.chunk_tick_iteration;
|
package ca.spottedleaf.moonrise.mixin.chunk_tick_iteration;
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.list.ReferenceList;
|
import ca.spottedleaf.moonrise.common.list.ReferenceList;
|
||||||
import ca.spottedleaf.moonrise.common.misc.NearbyPlayers;
|
|
||||||
import ca.spottedleaf.moonrise.common.util.SimpleThreadUnsafeRandom;
|
import ca.spottedleaf.moonrise.common.util.SimpleThreadUnsafeRandom;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkData;
|
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.server.ChunkSystemMinecraftServer;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk;
|
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickServerLevel;
|
|
||||||
import net.minecraft.Util;
|
import net.minecraft.Util;
|
||||||
import net.minecraft.server.level.ChunkMap;
|
import net.minecraft.server.level.ChunkMap;
|
||||||
import net.minecraft.server.level.ServerChunkCache;
|
import net.minecraft.server.level.ServerChunkCache;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
|
||||||
import net.minecraft.util.RandomSource;
|
import net.minecraft.util.RandomSource;
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.GameRules;
|
||||||
import net.minecraft.world.level.chunk.ChunkSource;
|
import net.minecraft.world.level.chunk.ChunkSource;
|
||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
import org.spongepowered.asm.mixin.Final;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
@Mixin(ServerChunkCache.class)
|
@Mixin(ServerChunkCache.class)
|
||||||
abstract class ServerChunkCacheMixin extends ChunkSource {
|
abstract class ServerChunkCacheMixin extends ChunkSource {
|
||||||
@@ -41,69 +37,13 @@ abstract class ServerChunkCacheMixin extends ChunkSource {
|
|||||||
@Unique
|
@Unique
|
||||||
private final SimpleThreadUnsafeRandom shuffleRandom = new SimpleThreadUnsafeRandom(0L);
|
private final SimpleThreadUnsafeRandom shuffleRandom = new SimpleThreadUnsafeRandom(0L);
|
||||||
|
|
||||||
@Unique
|
|
||||||
private boolean isChunkNearPlayer(final ChunkMap chunkMap, final ChunkPos chunkPos, final LevelChunk levelChunk) {
|
|
||||||
final ChunkData chunkData = ((ChunkSystemChunkHolder)((ChunkSystemLevelChunk)levelChunk).moonrise$getChunkAndHolder().holder())
|
|
||||||
.moonrise$getRealChunkHolder().holderData;
|
|
||||||
final NearbyPlayers.TrackedChunk nearbyPlayers = chunkData.nearbyPlayers;
|
|
||||||
if (nearbyPlayers == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final ReferenceList<ServerPlayer> players = nearbyPlayers.getPlayers(NearbyPlayers.NearbyMapType.SPAWN_RANGE);
|
|
||||||
|
|
||||||
if (players == null) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
final ServerPlayer[] raw = players.getRawDataUnchecked();
|
|
||||||
final int len = players.size();
|
|
||||||
|
|
||||||
Objects.checkFromIndexSize(0, len, raw.length);
|
|
||||||
for (int i = 0; i < len; ++i) {
|
|
||||||
if (chunkMap.playerIsCloseEnoughForSpawning(raw[i], chunkPos)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @reason Use the player ticking chunks list, which already contains chunks that are:
|
|
||||||
* 1. block ticking
|
|
||||||
* 2. within spawn range (8 chunks on any axis)
|
|
||||||
* @author Spottedleaf
|
|
||||||
*/
|
|
||||||
@Overwrite
|
|
||||||
private void collectTickingChunks(final List<LevelChunk> list) {
|
|
||||||
final ReferenceList<ServerChunkCache.ChunkAndHolder> tickingChunks =
|
|
||||||
((ChunkTickServerLevel)this.level).moonrise$getPlayerTickingChunks();
|
|
||||||
|
|
||||||
final ServerChunkCache.ChunkAndHolder[] raw = tickingChunks.getRawDataUnchecked();
|
|
||||||
final int size = tickingChunks.size();
|
|
||||||
|
|
||||||
final ChunkMap chunkMap = this.chunkMap;
|
|
||||||
|
|
||||||
for (int i = 0; i < size; ++i) {
|
|
||||||
final ServerChunkCache.ChunkAndHolder chunkAndHolder = raw[i];
|
|
||||||
final LevelChunk levelChunk = chunkAndHolder.chunk();
|
|
||||||
|
|
||||||
if (!this.isChunkNearPlayer(chunkMap, levelChunk.getPos(), levelChunk)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
list.add(levelChunk);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Use random implementation which does not use CAS and has a faster nextInt(int)
|
* @reason Use random implementation which does not use CAS and has a faster nextInt(int)
|
||||||
* function
|
* function
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Redirect(
|
@Redirect(
|
||||||
method = "tickChunks()V",
|
method = "tickChunks(Lnet/minecraft/util/profiling/ProfilerFiller;J)V",
|
||||||
at = @At(
|
at = @At(
|
||||||
value = "INVOKE",
|
value = "INVOKE",
|
||||||
target = "Lnet/minecraft/Util;shuffle(Ljava/util/List;Lnet/minecraft/util/RandomSource;)V"
|
target = "Lnet/minecraft/Util;shuffle(Ljava/util/List;Lnet/minecraft/util/RandomSource;)V"
|
||||||
@@ -113,4 +53,41 @@ abstract class ServerChunkCacheMixin extends ChunkSource {
|
|||||||
this.shuffleRandom.setSeed(randomSource.nextLong());
|
this.shuffleRandom.setSeed(randomSource.nextLong());
|
||||||
Util.shuffle(list, this.shuffleRandom);
|
Util.shuffle(list, this.shuffleRandom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Do not iterate over entire chunk holder map; additionally perform mid-tick chunk task execution
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Redirect(
|
||||||
|
method = "tickChunks(Lnet/minecraft/util/profiling/ProfilerFiller;J)V",
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "Lnet/minecraft/server/level/ChunkMap;forEachBlockTickingChunk(Ljava/util/function/Consumer;)V"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private void iterateTickingChunksFaster(final ChunkMap instance, final Consumer<LevelChunk> consumer) {
|
||||||
|
final ServerLevel world = this.level;
|
||||||
|
final int randomTickSpeed = world.getGameRules().getInt(GameRules.RULE_RANDOMTICKING);
|
||||||
|
|
||||||
|
// TODO check on update: impl of forEachBlockTickingChunk will only iterate ENTITY ticking chunks!
|
||||||
|
// TODO check on update: consumer just runs tickChunk
|
||||||
|
final ReferenceList<LevelChunk> entityTickingChunks = ((ChunkSystemServerLevel)world).moonrise$getEntityTickingChunks();
|
||||||
|
|
||||||
|
// note: we can use the backing array here because:
|
||||||
|
// 1. we do not care about new additions
|
||||||
|
// 2. _removes_ are impossible at this stage in the tick
|
||||||
|
final LevelChunk[] raw = entityTickingChunks.getRawDataUnchecked();
|
||||||
|
final int size = entityTickingChunks.size();
|
||||||
|
|
||||||
|
Objects.checkFromToIndex(0, size, raw.length);
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
world.tickChunk(raw[i], randomTickSpeed);
|
||||||
|
|
||||||
|
// call mid-tick tasks for chunk system
|
||||||
|
if ((i & 7) == 0) {
|
||||||
|
((ChunkSystemMinecraftServer)this.level.getServer()).moonrise$executeMidTickTasks();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,16 +19,16 @@ import org.spongepowered.asm.mixin.Unique;
|
|||||||
abstract class ServerLevelMixin implements ChunkTickServerLevel {
|
abstract class ServerLevelMixin implements ChunkTickServerLevel {
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private static final ServerChunkCache.ChunkAndHolder[] EMPTY_PLAYER_CHUNK_HOLDERS = new ServerChunkCache.ChunkAndHolder[0];
|
private static final LevelChunk[] EMPTY_LEVEL_CHUNKS = new LevelChunk[0];
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private final ReferenceList<ServerChunkCache.ChunkAndHolder> playerTickingChunks = new ReferenceList<>(EMPTY_PLAYER_CHUNK_HOLDERS);
|
private final ReferenceList<LevelChunk> playerTickingChunks = new ReferenceList<>(EMPTY_LEVEL_CHUNKS);
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private final Long2IntOpenHashMap playerTickingRequests = new Long2IntOpenHashMap();
|
private final Long2IntOpenHashMap playerTickingRequests = new Long2IntOpenHashMap();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final ReferenceList<ServerChunkCache.ChunkAndHolder> moonrise$getPlayerTickingChunks() {
|
public final ReferenceList<LevelChunk> moonrise$getPlayerTickingChunks() {
|
||||||
return this.playerTickingChunks;
|
return this.playerTickingChunks;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,12 +39,12 @@ abstract class ServerLevelMixin implements ChunkTickServerLevel {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.playerTickingChunks.add(((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder());
|
this.playerTickingChunks.add(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final void moonrise$removeChunkForPlayerTicking(final LevelChunk chunk) {
|
public final void moonrise$removeChunkForPlayerTicking(final LevelChunk chunk) {
|
||||||
this.playerTickingChunks.remove(((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder());
|
this.playerTickingChunks.remove(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -65,9 +65,7 @@ abstract class ServerLevelMixin implements ChunkTickServerLevel {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.playerTickingChunks.add(
|
this.playerTickingChunks.add((LevelChunk)chunkHolder.getCurrentChunk());
|
||||||
((ChunkSystemLevelChunk)(LevelChunk)chunkHolder.getCurrentChunk()).moonrise$getChunkAndHolder()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -93,8 +91,6 @@ abstract class ServerLevelMixin implements ChunkTickServerLevel {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.playerTickingChunks.remove(
|
this.playerTickingChunks.remove((LevelChunk)chunkHolder.getCurrentChunk());
|
||||||
((ChunkSystemLevelChunk)(LevelChunk)chunkHolder.getCurrentChunk()).moonrise$getChunkAndHolder()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ interface EntityGetterMixin {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((entity == null && otherEntity.canBeCollidedWith()) || (entity != null && entity.canCollideWith(otherEntity))) {
|
if ((entity == null && otherEntity.canBeCollidedWith(entity)) || (entity != null && entity.canCollideWith(otherEntity))) {
|
||||||
ret.add(Shapes.create(otherEntity.getBoundingBox()));
|
ret.add(Shapes.create(otherEntity.getBoundingBox()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,7 +74,7 @@ interface EntityGetterMixin {
|
|||||||
@Overwrite
|
@Overwrite
|
||||||
default boolean isUnobstructed(final Entity entity, final VoxelShape voxel) {
|
default boolean isUnobstructed(final Entity entity, final VoxelShape voxel) {
|
||||||
if (voxel.isEmpty()) {
|
if (voxel.isEmpty()) {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
final AABB singleAABB = ((CollisionVoxelShape)voxel).moonrise$getSingleAABBRepresentation();
|
final AABB singleAABB = ((CollisionVoxelShape)voxel).moonrise$getSingleAABBRepresentation();
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ abstract class LevelMixin implements LevelAccessor, AutoCloseable {
|
|||||||
public boolean isUnobstructed(final Entity entity) {
|
public boolean isUnobstructed(final Entity entity) {
|
||||||
final AABB boundingBox = entity.getBoundingBox();
|
final AABB boundingBox = entity.getBoundingBox();
|
||||||
if (CollisionUtil.isEmpty(boundingBox)) {
|
if (CollisionUtil.isEmpty(boundingBox)) {
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<Entity> entities = this.getEntities(
|
final List<Entity> entities = this.getEntities(
|
||||||
|
|||||||
@@ -345,11 +345,8 @@ abstract class ShapesMixin {
|
|||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public static boolean blockOccudes(final VoxelShape first, final VoxelShape second, final Direction direction) {
|
public static boolean blockOccludes(final VoxelShape first, final VoxelShape second, final Direction direction) {
|
||||||
final boolean firstBlock = first == BLOCK;
|
if (first == BLOCK & second == BLOCK) {
|
||||||
final boolean secondBlock = second == BLOCK;
|
|
||||||
|
|
||||||
if (firstBlock & secondBlock) {
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,13 @@
|
|||||||
package ca.spottedleaf.moonrise.mixin.serverlist;
|
package ca.spottedleaf.moonrise.mixin.serverlist;
|
||||||
|
|
||||||
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
|
import net.minecraft.client.multiplayer.resolver.ServerAddress;
|
||||||
import net.minecraft.client.multiplayer.resolver.ServerAddressResolver;
|
import net.minecraft.client.multiplayer.resolver.ServerAddressResolver;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
|
import java.net.InetSocketAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
|
||||||
@Mixin(ServerAddressResolver.class)
|
@Mixin(ServerAddressResolver.class)
|
||||||
@@ -15,24 +18,23 @@ interface ServerAddressResolverMixin {
|
|||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Redirect(
|
@Redirect(
|
||||||
method = {
|
method = {
|
||||||
"method_36903",
|
"method_36903",
|
||||||
"*(Lnet/minecraft/client/multiplayer/resolver/ServerAddress;)Ljava/util/Optional;"
|
"lambda$static$0"
|
||||||
},
|
},
|
||||||
at = @At(
|
at = @At(
|
||||||
value = "INVOKE",
|
value = "NEW",
|
||||||
target = "Ljava/net/InetAddress;getByName(Ljava/lang/String;)Ljava/net/InetAddress;"
|
target = "(Ljava/net/InetAddress;I)Ljava/net/InetSocketAddress;"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
private static InetAddress eliminateRDNS(final String name) throws UnknownHostException {
|
private static InetSocketAddress eliminateRDNS(InetAddress addr, final int port,
|
||||||
final InetAddress ret = InetAddress.getByName(name);
|
@Local(ordinal = 0, argsOnly = true) final ServerAddress serverAddress) throws UnknownHostException {
|
||||||
|
final byte[] address = addr.getAddress();
|
||||||
final byte[] address = ret.getAddress();
|
|
||||||
if (address != null) {
|
if (address != null) {
|
||||||
// pass name to prevent rDNS
|
// pass name to prevent rDNS
|
||||||
return InetAddress.getByAddress(name, address);
|
addr = InetAddress.getByAddress(serverAddress.getHost(), address);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return new InetSocketAddress(addr, port);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,10 +49,10 @@ import java.util.function.Supplier;
|
|||||||
abstract class ThreadedLevelLightEngineMixin extends LevelLightEngine implements StarLightLightingProvider {
|
abstract class ThreadedLevelLightEngineMixin extends LevelLightEngine implements StarLightLightingProvider {
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
private ConsecutiveExecutor consecutiveExecutor;
|
public ConsecutiveExecutor consecutiveExecutor;
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
private ChunkTaskDispatcher taskDispatcher;
|
public ChunkTaskDispatcher taskDispatcher;
|
||||||
|
|
||||||
public ThreadedLevelLightEngineMixin(final LightChunkGetter chunkProvider, final boolean hasBlockLight, final boolean hasSkyLight) {
|
public ThreadedLevelLightEngineMixin(final LightChunkGetter chunkProvider, final boolean hasBlockLight, final boolean hasSkyLight) {
|
||||||
super(chunkProvider, hasBlockLight, hasSkyLight);
|
super(chunkProvider, hasBlockLight, hasSkyLight);
|
||||||
@@ -86,10 +86,10 @@ abstract class ThreadedLevelLightEngineMixin extends LevelLightEngine implements
|
|||||||
|
|
||||||
final Long ticketId = Long.valueOf(this.chunkWorkCounter.getAndIncrement());
|
final Long ticketId = Long.valueOf(this.chunkWorkCounter.getAndIncrement());
|
||||||
final ChunkPos pos = new ChunkPos(chunkX, chunkZ);
|
final ChunkPos pos = new ChunkPos(chunkX, chunkZ);
|
||||||
world.getChunkSource().addRegionTicket(StarLightInterface.CHUNK_WORK_TICKET, pos, StarLightInterface.REGION_LIGHT_TICKET_LEVEL, ticketId);
|
((ChunkSystemServerLevel)world).moonrise$getChunkTaskScheduler().chunkHolderManager.addTicketAtLevel(StarLightInterface.CHUNK_WORK_TICKET, pos, StarLightInterface.LIGHT_TICKET_LEVEL, ticketId);
|
||||||
|
|
||||||
scheduledTask.queueOrRunTask(() -> {
|
scheduledTask.queueOrRunTask(() -> {
|
||||||
world.getChunkSource().removeRegionTicket(StarLightInterface.CHUNK_WORK_TICKET, pos, StarLightInterface.REGION_LIGHT_TICKET_LEVEL, ticketId);
|
((ChunkSystemServerLevel)world).moonrise$getChunkTaskScheduler().chunkHolderManager.removeTicketAtLevel(StarLightInterface.CHUNK_WORK_TICKET, pos, StarLightInterface.LIGHT_TICKET_LEVEL, ticketId);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,7 +105,7 @@ abstract class ThreadedLevelLightEngineMixin extends LevelLightEngine implements
|
|||||||
final ChunkPos pos = iterator.next();
|
final ChunkPos pos = iterator.next();
|
||||||
|
|
||||||
final Long id = ChunkTaskScheduler.getNextChunkRelightId();
|
final Long id = ChunkTaskScheduler.getNextChunkRelightId();
|
||||||
world.getChunkSource().addRegionTicket(ChunkTaskScheduler.CHUNK_RELIGHT, pos, StarLightInterface.REGION_LIGHT_TICKET_LEVEL, id);
|
((ChunkSystemServerLevel)world).moonrise$getChunkTaskScheduler().chunkHolderManager.addTicketAtLevel(ChunkTaskScheduler.CHUNK_RELIGHT, pos, StarLightInterface.LIGHT_TICKET_LEVEL, id);
|
||||||
ticketIds.put(pos, id);
|
ticketIds.put(pos, id);
|
||||||
|
|
||||||
final ChunkAccess chunk = (ChunkAccess)world.getChunkSource().getChunkForLighting(pos.x, pos.z);
|
final ChunkAccess chunk = (ChunkAccess)world.getChunkSource().getChunkForLighting(pos.x, pos.z);
|
||||||
@@ -113,7 +113,7 @@ abstract class ThreadedLevelLightEngineMixin extends LevelLightEngine implements
|
|||||||
// cannot relight this chunk
|
// cannot relight this chunk
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
ticketIds.remove(pos);
|
ticketIds.remove(pos);
|
||||||
world.getChunkSource().removeRegionTicket(ChunkTaskScheduler.CHUNK_RELIGHT, pos, StarLightInterface.REGION_LIGHT_TICKET_LEVEL, id);
|
((ChunkSystemServerLevel)world).moonrise$getChunkTaskScheduler().chunkHolderManager.removeTicketAtLevel(ChunkTaskScheduler.CHUNK_RELIGHT, pos, StarLightInterface.LIGHT_TICKET_LEVEL, id);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,9 +160,9 @@ abstract class ThreadedLevelLightEngineMixin extends LevelLightEngine implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (final Map.Entry<ChunkPos, Long> entry : ticketIds.entrySet()) {
|
for (final Map.Entry<ChunkPos, Long> entry : ticketIds.entrySet()) {
|
||||||
world.getChunkSource().removeRegionTicket(
|
((ChunkSystemServerLevel)world).moonrise$getChunkTaskScheduler().chunkHolderManager.removeTicketAtLevel(
|
||||||
ChunkTaskScheduler.CHUNK_RELIGHT, entry.getKey(),
|
ChunkTaskScheduler.CHUNK_RELIGHT, entry.getKey(),
|
||||||
StarLightInterface.REGION_LIGHT_TICKET_LEVEL, entry.getValue()
|
StarLightInterface.LIGHT_TICKET_LEVEL, entry.getValue()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,13 +60,13 @@ abstract class SerializableChunkDataMixin {
|
|||||||
method = "parse",
|
method = "parse",
|
||||||
at = @At(
|
at = @At(
|
||||||
value = "INVOKE",
|
value = "INVOKE",
|
||||||
target = "Lnet/minecraft/nbt/CompoundTag;getBoolean(Ljava/lang/String;)Z",
|
target = "Lnet/minecraft/nbt/CompoundTag;getBooleanOr(Ljava/lang/String;Z)Z",
|
||||||
ordinal = 0
|
ordinal = 0
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
private static boolean setLightCorrect(final CompoundTag instance, final String string,
|
private static boolean setLightCorrect(final CompoundTag instance, final String string, final boolean dfl,
|
||||||
@Local(ordinal = 0, argsOnly = false) final ChunkStatus status) {
|
@Local(ordinal = 0, argsOnly = false) final ChunkStatus status) {
|
||||||
final boolean starlightCorrect = instance.get("isLightOn") != null && instance.getInt(SaveUtil.STARLIGHT_VERSION_TAG) == SaveUtil.STARLIGHT_LIGHT_VERSION;
|
final boolean starlightCorrect = instance.get("isLightOn") != null && instance.getIntOr(SaveUtil.STARLIGHT_VERSION_TAG, -1) == SaveUtil.STARLIGHT_LIGHT_VERSION;
|
||||||
return status.isOrAfter(ChunkStatus.LIGHT) && starlightCorrect;
|
return status.isOrAfter(ChunkStatus.LIGHT) && starlightCorrect;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,17 +84,17 @@ abstract class SerializableChunkDataMixin {
|
|||||||
)
|
)
|
||||||
private static SerializableChunkData.SectionData readStarlightState(final int y, final LevelChunkSection chunkSection,
|
private static SerializableChunkData.SectionData readStarlightState(final int y, final LevelChunkSection chunkSection,
|
||||||
final DataLayer blockLight, final DataLayer skyLight,
|
final DataLayer blockLight, final DataLayer skyLight,
|
||||||
@Local(ordinal = 3, argsOnly = false) final CompoundTag sectionData) {
|
@Local(ordinal = 2, argsOnly = false) final CompoundTag sectionData) {
|
||||||
final SerializableChunkData.SectionData ret = new SerializableChunkData.SectionData(
|
final SerializableChunkData.SectionData ret = new SerializableChunkData.SectionData(
|
||||||
y, chunkSection, blockLight, skyLight
|
y, chunkSection, blockLight, skyLight
|
||||||
);
|
);
|
||||||
|
|
||||||
if (sectionData.contains(SaveUtil.BLOCKLIGHT_STATE_TAG, Tag.TAG_ANY_NUMERIC)) {
|
if (sectionData.contains(SaveUtil.BLOCKLIGHT_STATE_TAG)) {
|
||||||
((StarlightSectionData)(Object)ret).starlight$setBlockLightState(sectionData.getInt(SaveUtil.BLOCKLIGHT_STATE_TAG));
|
((StarlightSectionData)(Object)ret).starlight$setBlockLightState(sectionData.getIntOr(SaveUtil.BLOCKLIGHT_STATE_TAG, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sectionData.contains(SaveUtil.SKYLIGHT_STATE_TAG, Tag.TAG_ANY_NUMERIC)) {
|
if (sectionData.contains(SaveUtil.SKYLIGHT_STATE_TAG)) {
|
||||||
((StarlightSectionData)(Object)ret).starlight$setSkyLightState(sectionData.getInt(SaveUtil.SKYLIGHT_STATE_TAG));
|
((StarlightSectionData)(Object)ret).starlight$setSkyLightState(sectionData.getIntOr(SaveUtil.SKYLIGHT_STATE_TAG, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -15,12 +15,11 @@ public final class ChunkSystemConverters {
|
|||||||
private static final int DEFAULT_ENTITY_CHUNK_DATA_VERSION = -1;
|
private static final int DEFAULT_ENTITY_CHUNK_DATA_VERSION = -1;
|
||||||
|
|
||||||
private static int getCurrentVersion() {
|
private static int getCurrentVersion() {
|
||||||
return SharedConstants.getCurrentVersion().getDataVersion().getVersion();
|
return SharedConstants.getCurrentVersion().dataVersion().version();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getDataVersion(final CompoundTag data, final int dfl) {
|
private static int getDataVersion(final CompoundTag data, final int dfl) {
|
||||||
return !data.contains(SharedConstants.DATA_VERSION_TAG, Tag.TAG_ANY_NUMERIC)
|
return data.getIntOr(SharedConstants.DATA_VERSION_TAG, dfl);
|
||||||
? dfl : data.getInt(SharedConstants.DATA_VERSION_TAG);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CompoundTag convertPoiCompoundTag(final CompoundTag data, final ServerLevel world) {
|
public static CompoundTag convertPoiCompoundTag(final CompoundTag data, final ServerLevel world) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package ca.spottedleaf.moonrise.patches.chunk_system.entity;
|
|||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkData;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkData;
|
||||||
import net.minecraft.server.level.FullChunkStatus;
|
import net.minecraft.server.level.FullChunkStatus;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.animal.HappyGhast;
|
||||||
import net.minecraft.world.entity.monster.Shulker;
|
import net.minecraft.world.entity.monster.Shulker;
|
||||||
import net.minecraft.world.entity.vehicle.AbstractMinecart;
|
import net.minecraft.world.entity.vehicle.AbstractMinecart;
|
||||||
import net.minecraft.world.entity.vehicle.Boat;
|
import net.minecraft.world.entity.vehicle.Boat;
|
||||||
@@ -13,7 +14,7 @@ public interface ChunkSystemEntity {
|
|||||||
|
|
||||||
// for mods to override
|
// for mods to override
|
||||||
public default boolean moonrise$isHardCollidingUncached() {
|
public default boolean moonrise$isHardCollidingUncached() {
|
||||||
return this instanceof Boat || this instanceof AbstractMinecart || this instanceof Shulker || ((Entity)this).canBeCollidedWith();
|
return this instanceof Boat || this instanceof AbstractMinecart || this instanceof Shulker || this instanceof HappyGhast || ((Entity)this).canBeCollidedWith(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FullChunkStatus moonrise$getChunkStatus();
|
public FullChunkStatus moonrise$getChunkStatus();
|
||||||
|
|||||||
@@ -1143,7 +1143,7 @@ public final class MoonriseRegionFileIO {
|
|||||||
LOGGER.error("Failed to decompress chunk data for task: " + this.toString(), thr);
|
LOGGER.error("Failed to decompress chunk data for task: " + this.toString(), thr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compoundTag == null) {
|
if (throwable == null && compoundTag == null) {
|
||||||
// need to re-try from the start
|
// need to re-try from the start
|
||||||
this.scheduleReadIO();
|
this.scheduleReadIO();
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ public final class EntityDataController extends MoonriseRegionFileIO.RegionDataC
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void checkPosition(final ChunkPos pos, final CompoundTag nbt) {
|
private static void checkPosition(final ChunkPos pos, final CompoundTag nbt) {
|
||||||
final ChunkPos nbtPos = nbt == null ? null : EntityStorage.readChunkPos(nbt);
|
final ChunkPos nbtPos = nbt == null ? null : nbt.read("Position", ChunkPos.CODEC).orElse(null);
|
||||||
if (nbtPos != null && !pos.equals(nbtPos)) {
|
if (nbtPos != null && !pos.equals(nbtPos)) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Entity chunk coordinate and serialized data do not have matching coordinates, trying to serialize coordinate " + pos.toString()
|
"Entity chunk coordinate and serialized data do not have matching coordinates, trying to serialize coordinate " + pos.toString()
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package ca.spottedleaf.moonrise.patches.chunk_system.level;
|
package ca.spottedleaf.moonrise.patches.chunk_system.level;
|
||||||
|
|
||||||
import ca.spottedleaf.concurrentutil.util.Priority;
|
import ca.spottedleaf.concurrentutil.util.Priority;
|
||||||
|
import ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet;
|
||||||
import ca.spottedleaf.moonrise.common.list.ReferenceList;
|
import ca.spottedleaf.moonrise.common.list.ReferenceList;
|
||||||
import ca.spottedleaf.moonrise.common.misc.NearbyPlayers;
|
import ca.spottedleaf.moonrise.common.misc.NearbyPlayers;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;
|
import ca.spottedleaf.moonrise.patches.chunk_system.io.MoonriseRegionFileIO;
|
||||||
@@ -10,6 +11,7 @@ import net.minecraft.core.BlockPos;
|
|||||||
import net.minecraft.server.level.ChunkHolder;
|
import net.minecraft.server.level.ChunkHolder;
|
||||||
import net.minecraft.server.level.ServerChunkCache;
|
import net.minecraft.server.level.ServerChunkCache;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
@@ -56,9 +58,9 @@ public interface ChunkSystemServerLevel extends ChunkSystemLevel {
|
|||||||
|
|
||||||
public NearbyPlayers moonrise$getNearbyPlayers();
|
public NearbyPlayers moonrise$getNearbyPlayers();
|
||||||
|
|
||||||
public ReferenceList<ServerChunkCache.ChunkAndHolder> moonrise$getLoadedChunks();
|
public ReferenceList<LevelChunk> moonrise$getLoadedChunks();
|
||||||
|
|
||||||
public ReferenceList<ServerChunkCache.ChunkAndHolder> moonrise$getTickingChunks();
|
public ReferenceList<LevelChunk> moonrise$getTickingChunks();
|
||||||
|
|
||||||
public ReferenceList<ServerChunkCache.ChunkAndHolder> moonrise$getEntityTickingChunks();
|
public ReferenceList<LevelChunk> moonrise$getEntityTickingChunks();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
package ca.spottedleaf.moonrise.patches.chunk_system.level.chunk;
|
package ca.spottedleaf.moonrise.patches.chunk_system.level.chunk;
|
||||||
|
|
||||||
import net.minecraft.server.level.ServerChunkCache;
|
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder;
|
||||||
|
|
||||||
public interface ChunkSystemLevelChunk {
|
public interface ChunkSystemLevelChunk {
|
||||||
|
|
||||||
public boolean moonrise$isPostProcessingDone();
|
public boolean moonrise$isPostProcessingDone();
|
||||||
|
|
||||||
public ServerChunkCache.ChunkAndHolder moonrise$getChunkAndHolder();
|
public NewChunkHolder moonrise$getChunkHolder();
|
||||||
|
|
||||||
public void moonrise$setChunkAndHolder(final ServerChunkCache.ChunkAndHolder holder);
|
public void moonrise$setChunkHolder(final NewChunkHolder holder);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import ca.spottedleaf.moonrise.common.list.EntityList;
|
|||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkData;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkData;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity;
|
import ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import com.mojang.logging.LogUtils;
|
||||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectMap;
|
import it.unimi.dsi.fastutil.objects.Reference2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Reference2ObjectOpenHashMap;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
@@ -14,6 +15,7 @@ import net.minecraft.nbt.Tag;
|
|||||||
import net.minecraft.server.level.FullChunkStatus;
|
import net.minecraft.server.level.FullChunkStatus;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.util.ProblemReporter;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.EntitySpawnReason;
|
import net.minecraft.world.entity.EntitySpawnReason;
|
||||||
import net.minecraft.world.entity.EntityType;
|
import net.minecraft.world.entity.EntityType;
|
||||||
@@ -21,9 +23,14 @@ import net.minecraft.world.entity.boss.EnderDragonPart;
|
|||||||
import net.minecraft.world.entity.boss.enderdragon.EnderDragon;
|
import net.minecraft.world.entity.boss.enderdragon.EnderDragon;
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.storage.EntityStorage;
|
import net.minecraft.world.level.chunk.storage.EntityStorage;
|
||||||
import net.minecraft.world.level.entity.Visibility;
|
import net.minecraft.world.level.entity.Visibility;
|
||||||
|
import net.minecraft.world.level.storage.TagValueInput;
|
||||||
|
import net.minecraft.world.level.storage.TagValueOutput;
|
||||||
|
import net.minecraft.world.level.storage.ValueInput;
|
||||||
import net.minecraft.world.phys.AABB;
|
import net.minecraft.world.phys.AABB;
|
||||||
|
import org.slf4j.Logger;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
@@ -32,6 +39,8 @@ import java.util.function.Predicate;
|
|||||||
|
|
||||||
public final class ChunkEntitySlices {
|
public final class ChunkEntitySlices {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LogUtils.getLogger();
|
||||||
|
|
||||||
public final int minSection;
|
public final int minSection;
|
||||||
public final int maxSection;
|
public final int maxSection;
|
||||||
public final int chunkX;
|
public final int chunkX;
|
||||||
@@ -74,9 +83,12 @@ public final class ChunkEntitySlices {
|
|||||||
this.chunkData = chunkData;
|
this.chunkData = chunkData;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Entity> readEntities(final ServerLevel world, final CompoundTag compoundTag) {
|
public static List<Entity> readEntities(final ServerLevel world, final ChunkPos pos, final CompoundTag compoundTag) {
|
||||||
// TODO check this and below on update for format changes
|
try (final ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(ChunkAccess.problemPath(pos), LOGGER)) {
|
||||||
return EntityType.loadEntitiesRecursive(compoundTag.getList("Entities", 10), world, EntitySpawnReason.LOAD).collect(ImmutableList.toImmutableList());
|
ValueInput valueinput = TagValueInput.create(scopedCollector, world.registryAccess(), compoundTag);
|
||||||
|
// TODO check this and below on update for format changes
|
||||||
|
return EntityType.loadEntitiesRecursive(valueinput.childrenListOrEmpty("Entities"), world, EntitySpawnReason.LOAD).collect(ImmutableList.toImmutableList());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Paper start - rewrite chunk system
|
// Paper start - rewrite chunk system
|
||||||
@@ -84,12 +96,12 @@ public final class ChunkEntitySlices {
|
|||||||
if (from == null) {
|
if (from == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final ListTag entitiesFrom = from.getList("Entities", Tag.TAG_COMPOUND);
|
final ListTag entitiesFrom = from.getListOrEmpty("Entities");
|
||||||
if (entitiesFrom == null || entitiesFrom.isEmpty()) {
|
if (entitiesFrom == null || entitiesFrom.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final ListTag entitiesInto = into.getList("Entities", Tag.TAG_COMPOUND);
|
final ListTag entitiesInto = into.getListOrEmpty("Entities");
|
||||||
into.put("Entities", entitiesInto); // this is in case into doesn't have any entities
|
into.put("Entities", entitiesInto); // this is in case into doesn't have any entities
|
||||||
entitiesInto.addAll(0, entitiesFrom);
|
entitiesInto.addAll(0, entitiesFrom);
|
||||||
}
|
}
|
||||||
@@ -104,15 +116,25 @@ public final class ChunkEntitySlices {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final ListTag entitiesTag = new ListTag();
|
final ListTag entitiesTag = new ListTag();
|
||||||
for (final Entity entity : PlatformHooks.get().modifySavedEntities(world, chunkPos.x, chunkPos.z, entities)) {
|
try (final ProblemReporter.ScopedCollector scopedCollector = new ProblemReporter.ScopedCollector(ChunkAccess.problemPath(chunkPos), LOGGER)) {
|
||||||
CompoundTag compoundTag = new CompoundTag();
|
for (final Entity entity : PlatformHooks.get().modifySavedEntities(world, chunkPos.x, chunkPos.z, entities)) {
|
||||||
if (entity.save(compoundTag)) {
|
final TagValueOutput savedEntity = TagValueOutput.createWithContext(
|
||||||
entitiesTag.add(compoundTag);
|
scopedCollector.forChild(entity.problemPath()), entity.registryAccess()
|
||||||
|
);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (entity.save(savedEntity)) {
|
||||||
|
entitiesTag.add(savedEntity.buildResult());
|
||||||
|
}
|
||||||
|
} catch (final Exception ex) {
|
||||||
|
LOGGER.error("Entity type " + entity.getType() + " failed to serialize", ex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final CompoundTag ret = NbtUtils.addCurrentDataVersion(new CompoundTag());
|
final CompoundTag ret = NbtUtils.addCurrentDataVersion(new CompoundTag());
|
||||||
ret.put("Entities", entitiesTag);
|
ret.put("Entities", entitiesTag);
|
||||||
EntityStorage.writeChunkPos(ret, chunkPos);
|
ret.store("Position", ChunkPos.CODEC, chunkPos);
|
||||||
|
|
||||||
return !force && entitiesTag.isEmpty() ? null : ret;
|
return !force && entitiesTag.isEmpty() ? null : ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -179,6 +179,10 @@ public abstract class EntityLookup implements LevelEntityGetter<Entity> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Iterable<Entity> getAllMapped() {
|
||||||
|
return this.entityByUUID.values();
|
||||||
|
}
|
||||||
|
|
||||||
public int getEntityCount() {
|
public int getEntityCount() {
|
||||||
synchronized (this.accessibleEntities) {
|
synchronized (this.accessibleEntities) {
|
||||||
return this.accessibleEntities.size();
|
return this.accessibleEntities.size();
|
||||||
|
|||||||
@@ -45,8 +45,7 @@ public final class ClientEntityLookup extends EntityLookup {
|
|||||||
final boolean ticking = this.tickingChunks.contains(CoordinateUtils.getChunkKey(chunkX, chunkZ));
|
final boolean ticking = this.tickingChunks.contains(CoordinateUtils.getChunkKey(chunkX, chunkZ));
|
||||||
|
|
||||||
final ChunkEntitySlices ret = new ChunkEntitySlices(
|
final ChunkEntitySlices ret = new ChunkEntitySlices(
|
||||||
this.world, chunkX, chunkZ,
|
this.world, chunkX, chunkZ, ticking ? FullChunkStatus.ENTITY_TICKING : FullChunkStatus.FULL, null,
|
||||||
ticking ? FullChunkStatus.ENTITY_TICKING : FullChunkStatus.FULL, null,
|
|
||||||
WorldUtil.getMinSection(this.world), WorldUtil.getMaxSection(this.world)
|
WorldUtil.getMinSection(this.world), WorldUtil.getMaxSection(this.world)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,14 @@ import ca.spottedleaf.moonrise.common.util.TickThread;
|
|||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.ChunkEntitySlices;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.ChunkEntitySlices;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.EntityLookup;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.EntityLookup;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType;
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.server.level.TicketType;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.projectile.ThrownEnderpearl;
|
||||||
import net.minecraft.world.level.entity.LevelCallback;
|
import net.minecraft.world.level.entity.LevelCallback;
|
||||||
|
|
||||||
public final class ServerEntityLookup extends EntityLookup {
|
public final class ServerEntityLookup extends EntityLookup {
|
||||||
@@ -19,9 +24,18 @@ public final class ServerEntityLookup extends EntityLookup {
|
|||||||
private final ServerLevel serverWorld;
|
private final ServerLevel serverWorld;
|
||||||
public final ReferenceList<Entity> trackerEntities = new ReferenceList<>(EMPTY_ENTITY_ARRAY); // Moonrise - entity tracker
|
public final ReferenceList<Entity> trackerEntities = new ReferenceList<>(EMPTY_ENTITY_ARRAY); // Moonrise - entity tracker
|
||||||
|
|
||||||
|
// Vanilla does not increment ticket timeouts if the chunk is progressing in generation. They made this change in 1.21.6 so that the ender pearl
|
||||||
|
// ticket does not expire if the chunk fails to generate before the timeout expires. Rather than blindly adjusting the entire system behavior
|
||||||
|
// to fix this small issue, we instead add non-expirable tickets here to keep ender pearls ticking. This is how the original feature should have
|
||||||
|
// been implemented, but I don't think Vanilla has proper entity add/remove hooks like we do. Fixes MC-297591
|
||||||
|
private static final TicketType ENDER_PEARL_TICKER = ChunkSystemTicketType.create("chunk_system:ender_pearl_ticker", null);
|
||||||
|
private final Long2IntOpenHashMap enderPearlChunkCount = new Long2IntOpenHashMap();
|
||||||
|
private final boolean keepEnderPearlsTicking;
|
||||||
|
|
||||||
public ServerEntityLookup(final ServerLevel world, final LevelCallback<Entity> worldCallback) {
|
public ServerEntityLookup(final ServerLevel world, final LevelCallback<Entity> worldCallback) {
|
||||||
super(world, worldCallback);
|
super(world, worldCallback);
|
||||||
this.serverWorld = world;
|
this.serverWorld = world;
|
||||||
|
this.keepEnderPearlsTicking = PlatformHooks.get().addTicketForEnderPearls(world);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -63,6 +77,10 @@ public final class ServerEntityLookup extends EntityLookup {
|
|||||||
if (entity instanceof ServerPlayer player) {
|
if (entity instanceof ServerPlayer player) {
|
||||||
((ChunkSystemServerLevel)this.serverWorld).moonrise$getNearbyPlayers().tickPlayer(player);
|
((ChunkSystemServerLevel)this.serverWorld).moonrise$getNearbyPlayers().tickPlayer(player);
|
||||||
}
|
}
|
||||||
|
if (entity instanceof ThrownEnderpearl enderpearl && (oldSectionX != newSectionX || oldSectionZ != newSectionZ)) {
|
||||||
|
this.removeEnderPearl(CoordinateUtils.getChunkKey(oldSectionX, oldSectionZ));
|
||||||
|
this.addEnderPearl(CoordinateUtils.getChunkKey(newSectionX, newSectionZ));
|
||||||
|
}
|
||||||
PlatformHooks.get().entityMove(
|
PlatformHooks.get().entityMove(
|
||||||
entity,
|
entity,
|
||||||
CoordinateUtils.getChunkSectionKey(oldSectionX, oldSectionY, oldSectionZ),
|
CoordinateUtils.getChunkSectionKey(oldSectionX, oldSectionY, oldSectionZ),
|
||||||
@@ -75,6 +93,9 @@ public final class ServerEntityLookup extends EntityLookup {
|
|||||||
if (entity instanceof ServerPlayer player) {
|
if (entity instanceof ServerPlayer player) {
|
||||||
((ChunkSystemServerLevel)this.serverWorld).moonrise$getNearbyPlayers().addPlayer(player);
|
((ChunkSystemServerLevel)this.serverWorld).moonrise$getNearbyPlayers().addPlayer(player);
|
||||||
}
|
}
|
||||||
|
if (entity instanceof ThrownEnderpearl enderpearl) {
|
||||||
|
this.addEnderPearl(CoordinateUtils.getChunkKey(enderpearl.chunkPosition()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -82,6 +103,9 @@ public final class ServerEntityLookup extends EntityLookup {
|
|||||||
if (entity instanceof ServerPlayer player) {
|
if (entity instanceof ServerPlayer player) {
|
||||||
((ChunkSystemServerLevel)this.serverWorld).moonrise$getNearbyPlayers().removePlayer(player);
|
((ChunkSystemServerLevel)this.serverWorld).moonrise$getNearbyPlayers().removePlayer(player);
|
||||||
}
|
}
|
||||||
|
if (entity instanceof ThrownEnderpearl enderpearl) {
|
||||||
|
this.removeEnderPearl(CoordinateUtils.getChunkKey(enderpearl.chunkPosition()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -112,4 +136,31 @@ public final class ServerEntityLookup extends EntityLookup {
|
|||||||
protected boolean screenEntity(final Entity entity, final boolean fromDisk, final boolean event) {
|
protected boolean screenEntity(final Entity entity, final boolean fromDisk, final boolean event) {
|
||||||
return PlatformHooks.get().screenEntity(this.serverWorld, entity, fromDisk, event);
|
return PlatformHooks.get().screenEntity(this.serverWorld, entity, fromDisk, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addEnderPearl(final long coordinate) {
|
||||||
|
if (!this.keepEnderPearlsTicking) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int oldCount = this.enderPearlChunkCount.addTo(coordinate, 1);
|
||||||
|
if (oldCount != 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
((ChunkSystemServerLevel)this.serverWorld).moonrise$getChunkTaskScheduler().chunkHolderManager
|
||||||
|
.addTicketAtLevel(ENDER_PEARL_TICKER, coordinate, ChunkHolderManager.ENTITY_TICKING_TICKET_LEVEL, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeEnderPearl(final long coordinate) {
|
||||||
|
if (!this.keepEnderPearlsTicking) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final int oldCount = this.enderPearlChunkCount.addTo(coordinate, -1);
|
||||||
|
if (oldCount != 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.enderPearlChunkCount.remove(coordinate);
|
||||||
|
((ChunkSystemServerLevel)this.serverWorld).moonrise$getChunkTaskScheduler().chunkHolderManager
|
||||||
|
.removeTicketAtLevel(ENDER_PEARL_TICKER, coordinate, ChunkHolderManager.ENTITY_TICKING_TICKET_LEVEL, null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ public final class PoiChunk {
|
|||||||
final CompoundTag sections = new CompoundTag();
|
final CompoundTag sections = new CompoundTag();
|
||||||
ret.put("Sections", sections);
|
ret.put("Sections", sections);
|
||||||
|
|
||||||
ret.putInt("DataVersion", SharedConstants.getCurrentVersion().getDataVersion().getVersion());
|
ret.putInt("DataVersion", SharedConstants.getCurrentVersion().dataVersion().version());
|
||||||
|
|
||||||
final ServerLevel world = this.world;
|
final ServerLevel world = this.world;
|
||||||
final int chunkX = this.chunkX;
|
final int chunkX = this.chunkX;
|
||||||
@@ -159,7 +159,7 @@ public final class PoiChunk {
|
|||||||
|
|
||||||
final RegistryOps<Tag> registryOps = RegistryOps.create(NbtOps.INSTANCE, world.registryAccess());
|
final RegistryOps<Tag> registryOps = RegistryOps.create(NbtOps.INSTANCE, world.registryAccess());
|
||||||
|
|
||||||
final CompoundTag sections = data.getCompound("Sections");
|
final CompoundTag sections = data.getCompoundOrEmpty("Sections");
|
||||||
|
|
||||||
if (sections.isEmpty()) {
|
if (sections.isEmpty()) {
|
||||||
// nothing to parse
|
// nothing to parse
|
||||||
@@ -176,7 +176,7 @@ public final class PoiChunk {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
final CompoundTag section = sections.getCompound(key);
|
final CompoundTag section = sections.getCompoundOrEmpty(key);
|
||||||
final DataResult<PoiSection.Packed> deserializeResult = PoiSection.Packed.CODEC.parse(registryOps, section);
|
final DataResult<PoiSection.Packed> deserializeResult = PoiSection.Packed.CODEC.parse(registryOps, section);
|
||||||
final int finalSectionY = sectionY;
|
final int finalSectionY = sectionY;
|
||||||
final PoiSection.Packed packed = deserializeResult.resultOrPartial((final String description) -> {
|
final PoiSection.Packed packed = deserializeResult.resultOrPartial((final String description) -> {
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunk
|
|||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager;
|
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.ChunkTaskScheduler;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.util.ParallelSearchRadiusIteration;
|
import ca.spottedleaf.moonrise.patches.chunk_system.util.ParallelSearchRadiusIteration;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap;
|
||||||
@@ -45,16 +46,17 @@ import java.util.function.Function;
|
|||||||
|
|
||||||
public final class RegionizedPlayerChunkLoader {
|
public final class RegionizedPlayerChunkLoader {
|
||||||
|
|
||||||
public static final TicketType<Long> PLAYER_TICKET = TicketType.create("chunk_system:player_ticket", Long::compareTo);
|
public static final TicketType PLAYER_TICKET = ChunkSystemTicketType.create("chunk_system:player_ticket", Long::compareTo);
|
||||||
public static final TicketType<Long> PLAYER_TICKET_DELAYED = TicketType.create("chunk_system:player_ticket_delayed", Long::compareTo, 5 * 20);
|
public static final TicketType PLAYER_TICKET_DELAYED = ChunkSystemTicketType.create("chunk_system:player_ticket_delayed", Long::compareTo, 1L);
|
||||||
|
|
||||||
public static final int MIN_VIEW_DISTANCE = 2;
|
|
||||||
public static final int MAX_VIEW_DISTANCE = 32;
|
|
||||||
|
|
||||||
public static final int GENERATED_TICKET_LEVEL = ChunkHolderManager.FULL_LOADED_TICKET_LEVEL;
|
public static final int GENERATED_TICKET_LEVEL = ChunkHolderManager.FULL_LOADED_TICKET_LEVEL;
|
||||||
public static final int LOADED_TICKET_LEVEL = ChunkTaskScheduler.getTicketLevel(ChunkStatus.EMPTY);
|
public static final int LOADED_TICKET_LEVEL = ChunkTaskScheduler.getTicketLevel(ChunkStatus.EMPTY);
|
||||||
public static final int TICK_TICKET_LEVEL = ChunkHolderManager.ENTITY_TICKING_TICKET_LEVEL;
|
public static final int TICK_TICKET_LEVEL = ChunkHolderManager.ENTITY_TICKING_TICKET_LEVEL;
|
||||||
|
|
||||||
|
public static void setUnloadDelay(final long ticks) {
|
||||||
|
((ChunkSystemTicketType)(Object)PLAYER_TICKET_DELAYED).moonrise$setTimeout(Math.max(1, ticks));
|
||||||
|
}
|
||||||
|
|
||||||
public static final class ViewDistanceHolder {
|
public static final class ViewDistanceHolder {
|
||||||
|
|
||||||
private volatile ViewDistances viewDistances;
|
private volatile ViewDistances viewDistances;
|
||||||
@@ -149,7 +151,7 @@ public final class RegionizedPlayerChunkLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static int getAPITickViewDistance(final ServerPlayer player) {
|
public static int getAPITickViewDistance(final ServerPlayer player) {
|
||||||
final ServerLevel level = player.serverLevel();
|
final ServerLevel level = player.level();
|
||||||
final PlayerChunkLoaderData data = ((ChunkSystemServerPlayer)player).moonrise$getChunkLoader();
|
final PlayerChunkLoaderData data = ((ChunkSystemServerPlayer)player).moonrise$getChunkLoader();
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
return ((ChunkSystemServerLevel)level).moonrise$getPlayerChunkLoader().getAPITickDistance();
|
return ((ChunkSystemServerLevel)level).moonrise$getPlayerChunkLoader().getAPITickDistance();
|
||||||
@@ -158,7 +160,7 @@ public final class RegionizedPlayerChunkLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static int getAPIViewDistance(final ServerPlayer player) {
|
public static int getAPIViewDistance(final ServerPlayer player) {
|
||||||
final ServerLevel level = player.serverLevel();
|
final ServerLevel level = player.level();
|
||||||
final PlayerChunkLoaderData data = ((ChunkSystemServerPlayer)player).moonrise$getChunkLoader();
|
final PlayerChunkLoaderData data = ((ChunkSystemServerPlayer)player).moonrise$getChunkLoader();
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
return ((ChunkSystemServerLevel)level).moonrise$getPlayerChunkLoader().getAPIViewDistance();
|
return ((ChunkSystemServerLevel)level).moonrise$getPlayerChunkLoader().getAPIViewDistance();
|
||||||
@@ -168,7 +170,7 @@ public final class RegionizedPlayerChunkLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static int getAPISendViewDistance(final ServerPlayer player) {
|
public static int getAPISendViewDistance(final ServerPlayer player) {
|
||||||
final ServerLevel level = player.serverLevel();
|
final ServerLevel level = player.level();
|
||||||
final PlayerChunkLoaderData data = ((ChunkSystemServerPlayer)player).moonrise$getChunkLoader();
|
final PlayerChunkLoaderData data = ((ChunkSystemServerPlayer)player).moonrise$getChunkLoader();
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
return ((ChunkSystemServerLevel)level).moonrise$getPlayerChunkLoader().getAPISendViewDistance();
|
return ((ChunkSystemServerLevel)level).moonrise$getPlayerChunkLoader().getAPISendViewDistance();
|
||||||
@@ -685,8 +687,7 @@ public final class RegionizedPlayerChunkLoader {
|
|||||||
}
|
}
|
||||||
this.pushDelayedTicketOp(
|
this.pushDelayedTicketOp(
|
||||||
ChunkHolderManager.TicketOperation.addOp(
|
ChunkHolderManager.TicketOperation.addOp(
|
||||||
chunk,
|
chunk, PLAYER_TICKET, LOADED_TICKET_LEVEL, this.idBoxed
|
||||||
PLAYER_TICKET, LOADED_TICKET_LEVEL, this.idBoxed
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
chunks.add(chunk);
|
chunks.add(chunk);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package ca.spottedleaf.moonrise.patches.chunk_system.scheduling;
|
package ca.spottedleaf.moonrise.patches.chunk_system.scheduling;
|
||||||
|
|
||||||
|
import ca.spottedleaf.concurrentutil.collection.MultiThreadedQueue;
|
||||||
import ca.spottedleaf.concurrentutil.lock.ReentrantAreaLock;
|
import ca.spottedleaf.concurrentutil.lock.ReentrantAreaLock;
|
||||||
import ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable;
|
import ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable;
|
||||||
import ca.spottedleaf.concurrentutil.util.Priority;
|
import ca.spottedleaf.concurrentutil.util.Priority;
|
||||||
@@ -16,9 +17,11 @@ import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.ChunkLoadTas
|
|||||||
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.ChunkProgressionTask;
|
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.ChunkProgressionTask;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.GenericDataLoadTask;
|
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.GenericDataLoadTask;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicket;
|
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicket;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.util.ChunkSystemSortedArraySet;
|
import ca.spottedleaf.moonrise.patches.chunk_system.util.ChunkSystemSortedArraySet;
|
||||||
import com.google.gson.JsonArray;
|
import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ByteLinkedOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2ByteLinkedOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ByteMap;
|
import it.unimi.dsi.fastutil.longs.Long2ByteMap;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2IntMap;
|
import it.unimi.dsi.fastutil.longs.Long2IntMap;
|
||||||
@@ -65,13 +68,12 @@ public final class ChunkHolderManager {
|
|||||||
public static final int ENTITY_TICKING_TICKET_LEVEL = ChunkLevel.ENTITY_TICKING_LEVEL;
|
public static final int ENTITY_TICKING_TICKET_LEVEL = ChunkLevel.ENTITY_TICKING_LEVEL;
|
||||||
public static final int MAX_TICKET_LEVEL = ChunkLevel.MAX_LEVEL; // inclusive
|
public static final int MAX_TICKET_LEVEL = ChunkLevel.MAX_LEVEL; // inclusive
|
||||||
|
|
||||||
public static final TicketType<Unit> UNLOAD_COOLDOWN = TicketType.create("unload_cooldown", (u1, u2) -> 0, 5 * 20);
|
public static final TicketType UNLOAD_COOLDOWN = ChunkSystemTicketType.create("chunk_system:unload_cooldown", null, 5L * 20L);
|
||||||
|
|
||||||
private static final long NO_TIMEOUT_MARKER = Long.MIN_VALUE;
|
private static final long NO_TIMEOUT_MARKER = Long.MIN_VALUE;
|
||||||
private static final long PROBE_MARKER = Long.MIN_VALUE + 1;
|
|
||||||
public final ReentrantAreaLock ticketLockArea;
|
public final ReentrantAreaLock ticketLockArea;
|
||||||
|
|
||||||
private final ConcurrentLong2ReferenceChainedHashTable<SortedArraySet<Ticket<?>>> tickets = new ConcurrentLong2ReferenceChainedHashTable<>();
|
private final ConcurrentLong2ReferenceChainedHashTable<SortedArraySet<Ticket>> tickets = new ConcurrentLong2ReferenceChainedHashTable<>();
|
||||||
private final ConcurrentLong2ReferenceChainedHashTable<Long2IntOpenHashMap> sectionToChunkToExpireCount = new ConcurrentLong2ReferenceChainedHashTable<>();
|
private final ConcurrentLong2ReferenceChainedHashTable<Long2IntOpenHashMap> sectionToChunkToExpireCount = new ConcurrentLong2ReferenceChainedHashTable<>();
|
||||||
final ChunkUnloadQueue unloadQueue;
|
final ChunkUnloadQueue unloadQueue;
|
||||||
|
|
||||||
@@ -81,6 +83,7 @@ public final class ChunkHolderManager {
|
|||||||
private long currentTick;
|
private long currentTick;
|
||||||
|
|
||||||
private final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = new ArrayDeque<>();
|
private final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = new ArrayDeque<>();
|
||||||
|
private final MultiThreadedQueue<NewChunkHolder> offThreadPendingFullLoadUpdate = new MultiThreadedQueue<>();
|
||||||
private final ObjectRBTreeSet<NewChunkHolder> autoSaveQueue = new ObjectRBTreeSet<>((final NewChunkHolder c1, final NewChunkHolder c2) -> {
|
private final ObjectRBTreeSet<NewChunkHolder> autoSaveQueue = new ObjectRBTreeSet<>((final NewChunkHolder c1, final NewChunkHolder c2) -> {
|
||||||
if (c1 == c2) {
|
if (c1 == c2) {
|
||||||
return 0;
|
return 0;
|
||||||
@@ -102,6 +105,8 @@ public final class ChunkHolderManager {
|
|||||||
return Long.compare(coord1, coord2);
|
return Long.compare(coord1, coord2);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
private final ConcurrentLong2ReferenceChainedHashTable<Long2IntOpenHashMap> ticketCounters = new ConcurrentLong2ReferenceChainedHashTable<>();
|
||||||
|
|
||||||
public ChunkHolderManager(final ServerLevel world, final ChunkTaskScheduler taskScheduler) {
|
public ChunkHolderManager(final ServerLevel world, final ChunkTaskScheduler taskScheduler) {
|
||||||
this.world = world;
|
this.world = world;
|
||||||
this.taskScheduler = taskScheduler;
|
this.taskScheduler = taskScheduler;
|
||||||
@@ -109,20 +114,20 @@ public final class ChunkHolderManager {
|
|||||||
this.unloadQueue = new ChunkUnloadQueue(((ChunkSystemServerLevel)world).moonrise$getRegionChunkShift());
|
this.unloadQueue = new ChunkUnloadQueue(((ChunkSystemServerLevel)world).moonrise$getRegionChunkShift());
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean processTicketUpdates(final int posX, final int posZ) {
|
public boolean processTicketUpdates(final int chunkX, final int chunkZ) {
|
||||||
final int ticketShift = ThreadedTicketLevelPropagator.SECTION_SHIFT;
|
final int ticketShift = ThreadedTicketLevelPropagator.SECTION_SHIFT;
|
||||||
final int ticketMask = (1 << ticketShift) - 1;
|
final int ticketMask = (1 << ticketShift) - 1;
|
||||||
final List<ChunkProgressionTask> scheduledTasks = new ArrayList<>();
|
final List<ChunkProgressionTask> scheduledTasks = new ArrayList<>();
|
||||||
final List<NewChunkHolder> changedFullStatus = new ArrayList<>();
|
final List<NewChunkHolder> changedFullStatus = new ArrayList<>();
|
||||||
final boolean ret;
|
final boolean ret;
|
||||||
final ReentrantAreaLock.Node ticketLock = this.ticketLockArea.lock(
|
final ReentrantAreaLock.Node ticketLock = this.ticketLockArea.lock(
|
||||||
((posX >> ticketShift) - 1) << ticketShift,
|
((chunkX >> ticketShift) - 1) << ticketShift,
|
||||||
((posZ >> ticketShift) - 1) << ticketShift,
|
((chunkZ >> ticketShift) - 1) << ticketShift,
|
||||||
(((posX >> ticketShift) + 1) << ticketShift) | ticketMask,
|
(((chunkX >> ticketShift) + 1) << ticketShift) | ticketMask,
|
||||||
(((posZ >> ticketShift) + 1) << ticketShift) | ticketMask
|
(((chunkZ >> ticketShift) + 1) << ticketShift) | ticketMask
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
ret = this.processTicketUpdatesNoLock(posX >> ticketShift, posZ >> ticketShift, scheduledTasks, changedFullStatus);
|
ret = this.processTicketUpdatesNoLock(chunkX >> ticketShift, chunkZ >> ticketShift, scheduledTasks, changedFullStatus);
|
||||||
} finally {
|
} finally {
|
||||||
this.ticketLockArea.unlock(ticketLock);
|
this.ticketLockArea.unlock(ticketLock);
|
||||||
}
|
}
|
||||||
@@ -163,7 +168,6 @@ public final class ChunkHolderManager {
|
|||||||
return this.chunkHolders.size();
|
return this.chunkHolders.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO replace the need for this, specifically: optimise ServerChunkCache#tickChunks
|
|
||||||
public Iterable<ChunkHolder> getOldChunkHoldersIterable() {
|
public Iterable<ChunkHolder> getOldChunkHoldersIterable() {
|
||||||
return new Iterable<ChunkHolder>() {
|
return new Iterable<ChunkHolder>() {
|
||||||
@Override
|
@Override
|
||||||
@@ -411,7 +415,7 @@ public final class ChunkHolderManager {
|
|||||||
public String getTicketDebugString(final long coordinate) {
|
public String getTicketDebugString(final long coordinate) {
|
||||||
final ReentrantAreaLock.Node ticketLock = this.ticketLockArea.lock(CoordinateUtils.getChunkX(coordinate), CoordinateUtils.getChunkZ(coordinate));
|
final ReentrantAreaLock.Node ticketLock = this.ticketLockArea.lock(CoordinateUtils.getChunkX(coordinate), CoordinateUtils.getChunkZ(coordinate));
|
||||||
try {
|
try {
|
||||||
final SortedArraySet<Ticket<?>> tickets = this.tickets.get(coordinate);
|
final SortedArraySet<Ticket> tickets = this.tickets.get(coordinate);
|
||||||
|
|
||||||
return tickets != null ? tickets.first().toString() : "no_ticket";
|
return tickets != null ? tickets.first().toString() : "no_ticket";
|
||||||
} finally {
|
} finally {
|
||||||
@@ -421,8 +425,40 @@ public final class ChunkHolderManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Long2ObjectOpenHashMap<SortedArraySet<Ticket<?>>> getTicketsCopy() {
|
public boolean hasTickets() {
|
||||||
final Long2ObjectOpenHashMap<SortedArraySet<Ticket<?>>> ret = new Long2ObjectOpenHashMap<>();
|
return !this.tickets.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<Ticket> getTicketsAt(final int chunkX, final int chunkZ) {
|
||||||
|
final long key = CoordinateUtils.getChunkKey(chunkX, chunkZ);
|
||||||
|
|
||||||
|
if (!this.tickets.containsKey(key)) {
|
||||||
|
// avoid contending lock
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
final ReentrantAreaLock.Node lock = this.ticketLockArea.lock(chunkX, chunkZ);
|
||||||
|
try {
|
||||||
|
final SortedArraySet<Ticket> tickets = this.tickets.get(key);
|
||||||
|
|
||||||
|
if (tickets == null) {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<Ticket> ret = new ArrayList<>(tickets.size());
|
||||||
|
|
||||||
|
for (final Ticket ticket : tickets) {
|
||||||
|
ret.add(ticket);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
} finally {
|
||||||
|
this.ticketLockArea.unlock(lock);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long2ObjectOpenHashMap<SortedArraySet<Ticket>> getTicketsCopy() {
|
||||||
|
final Long2ObjectOpenHashMap<SortedArraySet<Ticket>> ret = new Long2ObjectOpenHashMap<>();
|
||||||
final Long2ObjectOpenHashMap<LongArrayList> sections = new Long2ObjectOpenHashMap<>();
|
final Long2ObjectOpenHashMap<LongArrayList> sections = new Long2ObjectOpenHashMap<>();
|
||||||
final int sectionShift = this.taskScheduler.getChunkSystemLockShift();
|
final int sectionShift = this.taskScheduler.getChunkSystemLockShift();
|
||||||
for (final PrimitiveIterator.OfLong iterator = this.tickets.keyIterator(); iterator.hasNext();) {
|
for (final PrimitiveIterator.OfLong iterator = this.tickets.keyIterator(); iterator.hasNext();) {
|
||||||
@@ -451,12 +487,12 @@ public final class ChunkHolderManager {
|
|||||||
try {
|
try {
|
||||||
for (final LongIterator iterator2 = coordinates.iterator(); iterator2.hasNext();) {
|
for (final LongIterator iterator2 = coordinates.iterator(); iterator2.hasNext();) {
|
||||||
final long coord = iterator2.nextLong();
|
final long coord = iterator2.nextLong();
|
||||||
final SortedArraySet<Ticket<?>> tickets = this.tickets.get(coord);
|
final SortedArraySet<Ticket> tickets = this.tickets.get(coord);
|
||||||
if (tickets == null) {
|
if (tickets == null) {
|
||||||
// removed before we acquired lock
|
// removed before we acquired lock
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
ret.put(coord, ((ChunkSystemSortedArraySet<Ticket<?>>)tickets).moonrise$copy());
|
ret.put(coord, ((ChunkSystemSortedArraySet<Ticket>)tickets).moonrise$copy());
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
this.ticketLockArea.unlock(ticketLock);
|
this.ticketLockArea.unlock(ticketLock);
|
||||||
@@ -474,16 +510,16 @@ public final class ChunkHolderManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getTicketLevelAt(SortedArraySet<Ticket<?>> tickets) {
|
private static int getTicketLevelAt(final SortedArraySet<Ticket> tickets) {
|
||||||
return !tickets.isEmpty() ? tickets.first().getTicketLevel() : MAX_TICKET_LEVEL + 1;
|
return !tickets.isEmpty() ? tickets.first().getTicketLevel() : MAX_TICKET_LEVEL + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> boolean addTicketAtLevel(final TicketType<T> type, final ChunkPos chunkPos, final int level,
|
public <T> boolean addTicketAtLevel(final TicketType type, final ChunkPos chunkPos, final int level,
|
||||||
final T identifier) {
|
final T identifier) {
|
||||||
return this.addTicketAtLevel(type, CoordinateUtils.getChunkKey(chunkPos), level, identifier);
|
return this.addTicketAtLevel(type, CoordinateUtils.getChunkKey(chunkPos), level, identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> boolean addTicketAtLevel(final TicketType<T> type, final int chunkX, final int chunkZ, final int level,
|
public <T> boolean addTicketAtLevel(final TicketType type, final int chunkX, final int chunkZ, final int level,
|
||||||
final T identifier) {
|
final T identifier) {
|
||||||
return this.addTicketAtLevel(type, CoordinateUtils.getChunkKey(chunkX, chunkZ), level, identifier);
|
return this.addTicketAtLevel(type, CoordinateUtils.getChunkKey(chunkX, chunkZ), level, identifier);
|
||||||
}
|
}
|
||||||
@@ -524,29 +560,29 @@ public final class ChunkHolderManager {
|
|||||||
|
|
||||||
// supposed to return true if the ticket was added and did not replace another
|
// supposed to return true if the ticket was added and did not replace another
|
||||||
// but, we always return false if the ticket cannot be added
|
// but, we always return false if the ticket cannot be added
|
||||||
public <T> boolean addTicketAtLevel(final TicketType<T> type, final long chunk, final int level, final T identifier) {
|
public <T> boolean addTicketAtLevel(final TicketType type, final long chunk, final int level, final T identifier) {
|
||||||
return this.addTicketAtLevel(type, chunk, level, identifier, true);
|
return this.addTicketAtLevel(type, chunk, level, identifier, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
<T> boolean addTicketAtLevel(final TicketType<T> type, final long chunk, final int level, final T identifier, final boolean lock) {
|
<T> boolean addTicketAtLevel(final TicketType type, final long chunk, final int level, final T identifier, final boolean lock) {
|
||||||
final long removeDelay = type.timeout <= 0 ? NO_TIMEOUT_MARKER : type.timeout;
|
final long removeDelay = type.timeout() <= 0 ? NO_TIMEOUT_MARKER : type.timeout();
|
||||||
if (level > MAX_TICKET_LEVEL) {
|
if (level > MAX_TICKET_LEVEL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int chunkX = CoordinateUtils.getChunkX(chunk);
|
final int chunkX = CoordinateUtils.getChunkX(chunk);
|
||||||
final int chunkZ = CoordinateUtils.getChunkZ(chunk);
|
final int chunkZ = CoordinateUtils.getChunkZ(chunk);
|
||||||
final Ticket<T> ticket = new Ticket<>(type, level, identifier);
|
final Ticket ticket = new Ticket(type, level, removeDelay);
|
||||||
((ChunkSystemTicket<T>)(Object)ticket).moonrise$setRemoveDelay(removeDelay);
|
((ChunkSystemTicket<T>)(Object)ticket).moonrise$setIdentifier(identifier);
|
||||||
|
|
||||||
final ReentrantAreaLock.Node ticketLock = lock ? this.ticketLockArea.lock(chunkX, chunkZ) : null;
|
final ReentrantAreaLock.Node ticketLock = lock ? this.ticketLockArea.lock(chunkX, chunkZ) : null;
|
||||||
try {
|
try {
|
||||||
final SortedArraySet<Ticket<?>> ticketsAtChunk = this.tickets.computeIfAbsent(chunk, (final long keyInMap) -> {
|
final SortedArraySet<Ticket> ticketsAtChunk = this.tickets.computeIfAbsent(chunk, (final long keyInMap) -> {
|
||||||
return SortedArraySet.create(4);
|
return (SortedArraySet)SortedArraySet.create(4);
|
||||||
});
|
});
|
||||||
|
|
||||||
final int levelBefore = getTicketLevelAt(ticketsAtChunk);
|
final int levelBefore = getTicketLevelAt(ticketsAtChunk);
|
||||||
final Ticket<T> current = (Ticket<T>)((ChunkSystemSortedArraySet<Ticket<?>>)ticketsAtChunk).moonrise$replace(ticket);
|
final Ticket current = (Ticket)((ChunkSystemSortedArraySet<Ticket>)ticketsAtChunk).moonrise$replace(ticket);
|
||||||
final int levelAfter = getTicketLevelAt(ticketsAtChunk);
|
final int levelAfter = getTicketLevelAt(ticketsAtChunk);
|
||||||
|
|
||||||
if (current != ticket) {
|
if (current != ticket) {
|
||||||
@@ -563,6 +599,7 @@ public final class ChunkHolderManager {
|
|||||||
if (removeDelay != NO_TIMEOUT_MARKER) {
|
if (removeDelay != NO_TIMEOUT_MARKER) {
|
||||||
this.addExpireCount(chunkX, chunkZ);
|
this.addExpireCount(chunkX, chunkZ);
|
||||||
}
|
}
|
||||||
|
this.addTicketCounter(type, chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (levelBefore != levelAfter) {
|
if (levelBefore != levelAfter) {
|
||||||
@@ -577,36 +614,85 @@ public final class ChunkHolderManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> boolean removeTicketAtLevel(final TicketType<T> type, final ChunkPos chunkPos, final int level, final T identifier) {
|
private void addTicketCounter(final TicketType type, final long pos) {
|
||||||
|
final long[] counterTypes = ((ChunkSystemTicketType<?>)(Object)type).moonrise$getCounterTypes();
|
||||||
|
if (counterTypes.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (this.ticketCounters) {
|
||||||
|
for (final long counterType : counterTypes) {
|
||||||
|
final Long2IntOpenHashMap oldCounters = this.ticketCounters.get(counterType);
|
||||||
|
final Long2IntOpenHashMap newCounters = oldCounters == null ? new Long2IntOpenHashMap() : oldCounters.clone();
|
||||||
|
|
||||||
|
newCounters.addTo(pos, 1);
|
||||||
|
|
||||||
|
this.ticketCounters.put(counterType, newCounters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void removeTicketCounter(final TicketType type, final long pos) {
|
||||||
|
final long[] counterTypes = ((ChunkSystemTicketType<?>)(Object)type).moonrise$getCounterTypes();
|
||||||
|
if (counterTypes.length == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
synchronized (this.ticketCounters) {
|
||||||
|
for (final long counterType : counterTypes) {
|
||||||
|
final Long2IntOpenHashMap oldCounters = this.ticketCounters.get(counterType);
|
||||||
|
final Long2IntOpenHashMap newCounters = oldCounters == null ? new Long2IntOpenHashMap() : oldCounters.clone();
|
||||||
|
|
||||||
|
final int currCount = newCounters.get(pos);
|
||||||
|
if (currCount <= 0) {
|
||||||
|
throw new IllegalStateException("Count must be > 0 at this stage");
|
||||||
|
}
|
||||||
|
if (currCount == 1) {
|
||||||
|
newCounters.remove(pos);
|
||||||
|
} else {
|
||||||
|
newCounters.put(pos, currCount - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ticketCounters.put(counterType, newCounters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Long2IntOpenHashMap getTicketCounters(final long counterType) {
|
||||||
|
return this.ticketCounters.get(counterType);
|
||||||
|
}
|
||||||
|
|
||||||
|
public <T> boolean removeTicketAtLevel(final TicketType type, final ChunkPos chunkPos, final int level, final T identifier) {
|
||||||
return this.removeTicketAtLevel(type, CoordinateUtils.getChunkKey(chunkPos), level, identifier);
|
return this.removeTicketAtLevel(type, CoordinateUtils.getChunkKey(chunkPos), level, identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> boolean removeTicketAtLevel(final TicketType<T> type, final int chunkX, final int chunkZ, final int level, final T identifier) {
|
public <T> boolean removeTicketAtLevel(final TicketType type, final int chunkX, final int chunkZ, final int level, final T identifier) {
|
||||||
return this.removeTicketAtLevel(type, CoordinateUtils.getChunkKey(chunkX, chunkZ), level, identifier);
|
return this.removeTicketAtLevel(type, CoordinateUtils.getChunkKey(chunkX, chunkZ), level, identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> boolean removeTicketAtLevel(final TicketType<T> type, final long chunk, final int level, final T identifier) {
|
public <T> boolean removeTicketAtLevel(final TicketType type, final long chunk, final int level, final T identifier) {
|
||||||
return this.removeTicketAtLevel(type, chunk, level, identifier, true);
|
return this.removeTicketAtLevel(type, chunk, level, identifier, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
<T> boolean removeTicketAtLevel(final TicketType<T> type, final long chunk, final int level, final T identifier, final boolean lock) {
|
<T> boolean removeTicketAtLevel(final TicketType type, final long chunk, final int level, final T identifier, final boolean lock) {
|
||||||
if (level > MAX_TICKET_LEVEL) {
|
if (level > MAX_TICKET_LEVEL) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int chunkX = CoordinateUtils.getChunkX(chunk);
|
final int chunkX = CoordinateUtils.getChunkX(chunk);
|
||||||
final int chunkZ = CoordinateUtils.getChunkZ(chunk);
|
final int chunkZ = CoordinateUtils.getChunkZ(chunk);
|
||||||
final Ticket<T> probe = new Ticket<>(type, level, identifier);
|
final Ticket probe = new Ticket(type, level, 0L);
|
||||||
|
((ChunkSystemTicket<T>)(Object)probe).moonrise$setIdentifier(identifier);
|
||||||
|
|
||||||
final ReentrantAreaLock.Node ticketLock = lock ? this.ticketLockArea.lock(chunkX, chunkZ) : null;
|
final ReentrantAreaLock.Node ticketLock = lock ? this.ticketLockArea.lock(chunkX, chunkZ) : null;
|
||||||
try {
|
try {
|
||||||
final SortedArraySet<Ticket<?>> ticketsAtChunk = this.tickets.get(chunk);
|
final SortedArraySet<Ticket> ticketsAtChunk = this.tickets.get(chunk);
|
||||||
if (ticketsAtChunk == null) {
|
if (ticketsAtChunk == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int oldLevel = getTicketLevelAt(ticketsAtChunk);
|
final int oldLevel = getTicketLevelAt(ticketsAtChunk);
|
||||||
final Ticket<T> ticket = (Ticket<T>)((ChunkSystemSortedArraySet<Ticket<?>>)ticketsAtChunk).moonrise$removeAndGet(probe);
|
final Ticket ticket = (Ticket)((ChunkSystemSortedArraySet<Ticket>)ticketsAtChunk).moonrise$removeAndGet(probe);
|
||||||
|
|
||||||
if (ticket == null) {
|
if (ticket == null) {
|
||||||
return false;
|
return false;
|
||||||
@@ -615,8 +701,7 @@ public final class ChunkHolderManager {
|
|||||||
final int newLevel = getTicketLevelAt(ticketsAtChunk);
|
final int newLevel = getTicketLevelAt(ticketsAtChunk);
|
||||||
// we should not change the ticket levels while the target region may be ticking
|
// we should not change the ticket levels while the target region may be ticking
|
||||||
if (oldLevel != newLevel) {
|
if (oldLevel != newLevel) {
|
||||||
final Ticket<ChunkPos> unknownTicket = new Ticket<>(TicketType.UNKNOWN, level, new ChunkPos(chunk));
|
final Ticket unknownTicket = new Ticket(TicketType.UNKNOWN, level);
|
||||||
((ChunkSystemTicket<ChunkPos>)(Object)unknownTicket).moonrise$setRemoveDelay(Math.max(1, TicketType.UNKNOWN.timeout));
|
|
||||||
if (ticketsAtChunk.add(unknownTicket)) {
|
if (ticketsAtChunk.add(unknownTicket)) {
|
||||||
this.addExpireCount(chunkX, chunkZ);
|
this.addExpireCount(chunkX, chunkZ);
|
||||||
} else {
|
} else {
|
||||||
@@ -629,6 +714,8 @@ public final class ChunkHolderManager {
|
|||||||
this.removeExpireCount(chunkX, chunkZ);
|
this.removeExpireCount(chunkX, chunkZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.removeTicketCounter(type, chunk);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} finally {
|
} finally {
|
||||||
if (ticketLock != null) {
|
if (ticketLock != null) {
|
||||||
@@ -638,8 +725,8 @@ public final class ChunkHolderManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// atomic with respect to all add/remove/addandremove ticket calls for the given chunk
|
// atomic with respect to all add/remove/addandremove ticket calls for the given chunk
|
||||||
public <T, V> void addAndRemoveTickets(final long chunk, final TicketType<T> addType, final int addLevel, final T addIdentifier,
|
public <T, V> void addAndRemoveTickets(final long chunk, final TicketType addType, final int addLevel, final T addIdentifier,
|
||||||
final TicketType<V> removeType, final int removeLevel, final V removeIdentifier) {
|
final TicketType removeType, final int removeLevel, final V removeIdentifier) {
|
||||||
final ReentrantAreaLock.Node ticketLock = this.ticketLockArea.lock(CoordinateUtils.getChunkX(chunk), CoordinateUtils.getChunkZ(chunk));
|
final ReentrantAreaLock.Node ticketLock = this.ticketLockArea.lock(CoordinateUtils.getChunkX(chunk), CoordinateUtils.getChunkZ(chunk));
|
||||||
try {
|
try {
|
||||||
this.addTicketAtLevel(addType, chunk, addLevel, addIdentifier, false);
|
this.addTicketAtLevel(addType, chunk, addLevel, addIdentifier, false);
|
||||||
@@ -650,8 +737,8 @@ public final class ChunkHolderManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// atomic with respect to all add/remove/addandremove ticket calls for the given chunk
|
// atomic with respect to all add/remove/addandremove ticket calls for the given chunk
|
||||||
public <T, V> boolean addIfRemovedTicket(final long chunk, final TicketType<T> addType, final int addLevel, final T addIdentifier,
|
public <T, V> boolean addIfRemovedTicket(final long chunk, final TicketType addType, final int addLevel, final T addIdentifier,
|
||||||
final TicketType<V> removeType, final int removeLevel, final V removeIdentifier) {
|
final TicketType removeType, final int removeLevel, final V removeIdentifier) {
|
||||||
final ReentrantAreaLock.Node ticketLock = this.ticketLockArea.lock(CoordinateUtils.getChunkX(chunk), CoordinateUtils.getChunkZ(chunk));
|
final ReentrantAreaLock.Node ticketLock = this.ticketLockArea.lock(CoordinateUtils.getChunkX(chunk), CoordinateUtils.getChunkZ(chunk));
|
||||||
try {
|
try {
|
||||||
if (this.removeTicketAtLevel(removeType, chunk, removeLevel, removeIdentifier, false)) {
|
if (this.removeTicketAtLevel(removeType, chunk, removeLevel, removeIdentifier, false)) {
|
||||||
@@ -664,7 +751,7 @@ public final class ChunkHolderManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public <T> void removeAllTicketsFor(final TicketType<T> ticketType, final int ticketLevel, final T ticketIdentifier) {
|
public <T> void removeAllTicketsFor(final TicketType ticketType, final int ticketLevel, final T ticketIdentifier) {
|
||||||
if (ticketLevel > MAX_TICKET_LEVEL) {
|
if (ticketLevel > MAX_TICKET_LEVEL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -710,7 +797,7 @@ public final class ChunkHolderManager {
|
|||||||
|
|
||||||
final int sectionShift = ((ChunkSystemServerLevel)this.world).moonrise$getRegionChunkShift();
|
final int sectionShift = ((ChunkSystemServerLevel)this.world).moonrise$getRegionChunkShift();
|
||||||
|
|
||||||
final Predicate<Ticket<?>> expireNow = (final Ticket<?> ticket) -> {
|
final Predicate<Ticket> expireNow = (final Ticket ticket) -> {
|
||||||
long removeDelay = ((ChunkSystemTicket<?>)(Object)ticket).moonrise$getRemoveDelay();
|
long removeDelay = ((ChunkSystemTicket<?>)(Object)ticket).moonrise$getRemoveDelay();
|
||||||
if (removeDelay == NO_TIMEOUT_MARKER) {
|
if (removeDelay == NO_TIMEOUT_MARKER) {
|
||||||
return false;
|
return false;
|
||||||
@@ -720,6 +807,9 @@ public final class ChunkHolderManager {
|
|||||||
return removeDelay <= 0L;
|
return removeDelay <= 0L;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
final List<ChunkProgressionTask> scheduledTasks = new ArrayList<>();
|
||||||
|
final List<NewChunkHolder> changedFullStatus = new ArrayList<>();
|
||||||
|
|
||||||
for (final PrimitiveIterator.OfLong iterator = this.sectionToChunkToExpireCount.keyIterator(); iterator.hasNext();) {
|
for (final PrimitiveIterator.OfLong iterator = this.sectionToChunkToExpireCount.keyIterator(); iterator.hasNext();) {
|
||||||
final long sectionKey = iterator.nextLong();
|
final long sectionKey = iterator.nextLong();
|
||||||
|
|
||||||
@@ -728,9 +818,16 @@ public final class ChunkHolderManager {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final int lowerChunkX = CoordinateUtils.getChunkX(sectionKey) << sectionShift;
|
||||||
|
final int lowerChunkZ = CoordinateUtils.getChunkZ(sectionKey) << sectionShift;
|
||||||
|
|
||||||
|
final int ticketShift = ThreadedTicketLevelPropagator.SECTION_SHIFT;
|
||||||
|
final int ticketMask = (1 << ticketShift) - 1;
|
||||||
final ReentrantAreaLock.Node ticketLock = this.ticketLockArea.lock(
|
final ReentrantAreaLock.Node ticketLock = this.ticketLockArea.lock(
|
||||||
CoordinateUtils.getChunkX(sectionKey) << sectionShift,
|
((lowerChunkX >> ticketShift) - 1) << ticketShift,
|
||||||
CoordinateUtils.getChunkZ(sectionKey) << sectionShift
|
((lowerChunkZ >> ticketShift) - 1) << ticketShift,
|
||||||
|
(((lowerChunkX >> ticketShift) + 1) << ticketShift) | ticketMask,
|
||||||
|
(((lowerChunkZ >> ticketShift) + 1) << ticketShift) | ticketMask
|
||||||
);
|
);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -746,7 +843,7 @@ public final class ChunkHolderManager {
|
|||||||
final long chunkKey = entry.getLongKey();
|
final long chunkKey = entry.getLongKey();
|
||||||
final int expireCount = entry.getIntValue();
|
final int expireCount = entry.getIntValue();
|
||||||
|
|
||||||
final SortedArraySet<Ticket<?>> tickets = this.tickets.get(chunkKey);
|
final SortedArraySet<Ticket> tickets = this.tickets.get(chunkKey);
|
||||||
final int levelBefore = getTicketLevelAt(tickets);
|
final int levelBefore = getTicketLevelAt(tickets);
|
||||||
|
|
||||||
final int sizeBefore = tickets.size();
|
final int sizeBefore = tickets.size();
|
||||||
@@ -777,9 +874,23 @@ public final class ChunkHolderManager {
|
|||||||
if (chunkToExpireCount.isEmpty()) {
|
if (chunkToExpireCount.isEmpty()) {
|
||||||
this.sectionToChunkToExpireCount.remove(sectionKey);
|
this.sectionToChunkToExpireCount.remove(sectionKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// In order to prevent a race condition where an off-thread invokes processTicketUpdates(), we need to process ticket updates here
|
||||||
|
// so that we catch any additions to the changed full status list. If an off-thread were to process tickets here, it would not be guaranteed
|
||||||
|
// that it would be added to the full changed status set by the end of the call - possibly allowing ticket level decreases to be processed
|
||||||
|
// outside of this call, which is not an intended or expected of this chunk system.
|
||||||
|
this.processTicketUpdatesNoLock(lowerChunkX >> ThreadedTicketLevelPropagator.SECTION_SHIFT, lowerChunkZ >> ThreadedTicketLevelPropagator.SECTION_SHIFT, scheduledTasks, changedFullStatus);
|
||||||
} finally {
|
} finally {
|
||||||
this.ticketLockArea.unlock(ticketLock);
|
this.ticketLockArea.unlock(ticketLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.addChangedStatuses(changedFullStatus);
|
||||||
|
changedFullStatus.clear(); // clear for next loop iteration
|
||||||
|
|
||||||
|
for (int i = 0, len = scheduledTasks.size(); i < len; ++i) {
|
||||||
|
scheduledTasks.get(i).schedule();
|
||||||
|
}
|
||||||
|
scheduledTasks.clear(); // clear for next loop iteration
|
||||||
}
|
}
|
||||||
|
|
||||||
this.processTicketUpdates();
|
this.processTicketUpdates();
|
||||||
@@ -1006,14 +1117,9 @@ public final class ChunkHolderManager {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!TickThread.isTickThread()) {
|
if (!TickThread.isTickThread()) {
|
||||||
this.taskScheduler.scheduleChunkTask(() -> {
|
// These will be handled on the next ServerChunkCache$MainThreadExecutor#pollTask, as it runs the distance manager update
|
||||||
final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = ChunkHolderManager.this.pendingFullLoadUpdate;
|
// which will invoke processTicketUpdates
|
||||||
for (int i = 0, len = changedFullStatus.size(); i < len; ++i) {
|
this.offThreadPendingFullLoadUpdate.addAll(changedFullStatus);
|
||||||
pendingFullLoadUpdate.add(changedFullStatus.get(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
ChunkHolderManager.this.processPendingFullUpdate();
|
|
||||||
}, Priority.HIGHEST);
|
|
||||||
} else {
|
} else {
|
||||||
final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = this.pendingFullLoadUpdate;
|
final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = this.pendingFullLoadUpdate;
|
||||||
for (int i = 0, len = changedFullStatus.size(); i < len; ++i) {
|
for (int i = 0, len = changedFullStatus.size(); i < len; ++i) {
|
||||||
@@ -1164,7 +1270,7 @@ public final class ChunkHolderManager {
|
|||||||
this.removeChunkHolder(holder);
|
this.removeChunkHolder(holder);
|
||||||
} else {
|
} else {
|
||||||
// add cooldown so the next unload check is not immediately next tick
|
// add cooldown so the next unload check is not immediately next tick
|
||||||
this.addTicketAtLevel(UNLOAD_COOLDOWN, CoordinateUtils.getChunkKey(holder.chunkX, holder.chunkZ), MAX_TICKET_LEVEL, Unit.INSTANCE, false);
|
this.addTicketAtLevel(UNLOAD_COOLDOWN, CoordinateUtils.getChunkKey(holder.chunkX, holder.chunkZ), MAX_TICKET_LEVEL, null, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
@@ -1188,42 +1294,42 @@ public final class ChunkHolderManager {
|
|||||||
|
|
||||||
public static record TicketOperation<T, V> (
|
public static record TicketOperation<T, V> (
|
||||||
TicketOperationType op, long chunkCoord,
|
TicketOperationType op, long chunkCoord,
|
||||||
TicketType<T> ticketType, int ticketLevel, T identifier,
|
TicketType ticketType, int ticketLevel, T identifier,
|
||||||
TicketType<V> ticketType2, int ticketLevel2, V identifier2
|
TicketType ticketType2, int ticketLevel2, V identifier2
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private TicketOperation(TicketOperationType op, long chunkCoord,
|
private TicketOperation(TicketOperationType op, long chunkCoord,
|
||||||
TicketType<T> ticketType, int ticketLevel, T identifier) {
|
TicketType ticketType, int ticketLevel, T identifier) {
|
||||||
this(op, chunkCoord, ticketType, ticketLevel, identifier, null, 0, null);
|
this(op, chunkCoord, ticketType, ticketLevel, identifier, null, 0, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> TicketOperation<T, T> addOp(final ChunkPos chunk, final TicketType<T> type, final int ticketLevel, final T identifier) {
|
public static <T> TicketOperation<T, T> addOp(final ChunkPos chunk, final TicketType type, final int ticketLevel, final T identifier) {
|
||||||
return addOp(CoordinateUtils.getChunkKey(chunk), type, ticketLevel, identifier);
|
return addOp(CoordinateUtils.getChunkKey(chunk), type, ticketLevel, identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> TicketOperation<T, T> addOp(final int chunkX, final int chunkZ, final TicketType<T> type, final int ticketLevel, final T identifier) {
|
public static <T> TicketOperation<T, T> addOp(final int chunkX, final int chunkZ, final TicketType type, final int ticketLevel, final T identifier) {
|
||||||
return addOp(CoordinateUtils.getChunkKey(chunkX, chunkZ), type, ticketLevel, identifier);
|
return addOp(CoordinateUtils.getChunkKey(chunkX, chunkZ), type, ticketLevel, identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> TicketOperation<T, T> addOp(final long chunk, final TicketType<T> type, final int ticketLevel, final T identifier) {
|
public static <T> TicketOperation<T, T> addOp(final long chunk, final TicketType type, final int ticketLevel, final T identifier) {
|
||||||
return new TicketOperation<>(TicketOperationType.ADD, chunk, type, ticketLevel, identifier);
|
return new TicketOperation<>(TicketOperationType.ADD, chunk, type, ticketLevel, identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> TicketOperation<T, T> removeOp(final ChunkPos chunk, final TicketType<T> type, final int ticketLevel, final T identifier) {
|
public static <T> TicketOperation<T, T> removeOp(final ChunkPos chunk, final TicketType type, final int ticketLevel, final T identifier) {
|
||||||
return removeOp(CoordinateUtils.getChunkKey(chunk), type, ticketLevel, identifier);
|
return removeOp(CoordinateUtils.getChunkKey(chunk), type, ticketLevel, identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> TicketOperation<T, T> removeOp(final int chunkX, final int chunkZ, final TicketType<T> type, final int ticketLevel, final T identifier) {
|
public static <T> TicketOperation<T, T> removeOp(final int chunkX, final int chunkZ, final TicketType type, final int ticketLevel, final T identifier) {
|
||||||
return removeOp(CoordinateUtils.getChunkKey(chunkX, chunkZ), type, ticketLevel, identifier);
|
return removeOp(CoordinateUtils.getChunkKey(chunkX, chunkZ), type, ticketLevel, identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T> TicketOperation<T, T> removeOp(final long chunk, final TicketType<T> type, final int ticketLevel, final T identifier) {
|
public static <T> TicketOperation<T, T> removeOp(final long chunk, final TicketType type, final int ticketLevel, final T identifier) {
|
||||||
return new TicketOperation<>(TicketOperationType.REMOVE, chunk, type, ticketLevel, identifier);
|
return new TicketOperation<>(TicketOperationType.REMOVE, chunk, type, ticketLevel, identifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static <T, V> TicketOperation<T, V> addIfRemovedOp(final long chunk,
|
public static <T, V> TicketOperation<T, V> addIfRemovedOp(final long chunk,
|
||||||
final TicketType<T> addType, final int addLevel, final T addIdentifier,
|
final TicketType addType, final int addLevel, final T addIdentifier,
|
||||||
final TicketType<V> removeType, final int removeLevel, final V removeIdentifier) {
|
final TicketType removeType, final int removeLevel, final V removeIdentifier) {
|
||||||
return new TicketOperation<>(
|
return new TicketOperation<>(
|
||||||
TicketOperationType.ADD_IF_REMOVED, chunk, addType, addLevel, addIdentifier,
|
TicketOperationType.ADD_IF_REMOVED, chunk, addType, addLevel, addIdentifier,
|
||||||
removeType, removeLevel, removeIdentifier
|
removeType, removeLevel, removeIdentifier
|
||||||
@@ -1231,8 +1337,8 @@ public final class ChunkHolderManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static <T, V> TicketOperation<T, V> addAndRemove(final long chunk,
|
public static <T, V> TicketOperation<T, V> addAndRemove(final long chunk,
|
||||||
final TicketType<T> addType, final int addLevel, final T addIdentifier,
|
final TicketType addType, final int addLevel, final T addIdentifier,
|
||||||
final TicketType<V> removeType, final int removeLevel, final V removeIdentifier) {
|
final TicketType removeType, final int removeLevel, final V removeIdentifier) {
|
||||||
return new TicketOperation<>(
|
return new TicketOperation<>(
|
||||||
TicketOperationType.ADD_AND_REMOVE, chunk, addType, addLevel, addIdentifier,
|
TicketOperationType.ADD_AND_REMOVE, chunk, addType, addLevel, addIdentifier,
|
||||||
removeType, removeLevel, removeIdentifier
|
removeType, removeLevel, removeIdentifier
|
||||||
@@ -1294,36 +1400,20 @@ public final class ChunkHolderManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public boolean processTicketUpdates() {
|
public boolean processTicketUpdates() {
|
||||||
return this.processTicketUpdates(true, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final ThreadLocal<List<ChunkProgressionTask>> CURRENT_TICKET_UPDATE_SCHEDULING = new ThreadLocal<>();
|
|
||||||
|
|
||||||
static List<ChunkProgressionTask> getCurrentTicketUpdateScheduling() {
|
|
||||||
return CURRENT_TICKET_UPDATE_SCHEDULING.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean processTicketUpdates(final boolean processFullUpdates, List<ChunkProgressionTask> scheduledTasks) {
|
|
||||||
if (BLOCK_TICKET_UPDATES.get() == Boolean.TRUE) {
|
if (BLOCK_TICKET_UPDATES.get() == Boolean.TRUE) {
|
||||||
throw new IllegalStateException("Cannot update ticket level while unloading chunks or updating entity manager");
|
throw new IllegalStateException("Cannot update ticket level while unloading chunks or updating entity manager");
|
||||||
}
|
}
|
||||||
if (!PlatformHooks.get().allowAsyncTicketUpdates() && !TickThread.isTickThread()) {
|
final boolean isTickThread = TickThread.isTickThread();
|
||||||
|
|
||||||
|
if (!PlatformHooks.get().allowAsyncTicketUpdates() && isTickThread) {
|
||||||
TickThread.ensureTickThread("Cannot asynchronously process ticket updates");
|
TickThread.ensureTickThread("Cannot asynchronously process ticket updates");
|
||||||
}
|
}
|
||||||
|
|
||||||
List<NewChunkHolder> changedFullStatus = null;
|
|
||||||
|
|
||||||
final boolean isTickThread = TickThread.isTickThread();
|
|
||||||
|
|
||||||
boolean ret = false;
|
boolean ret = false;
|
||||||
final boolean canProcessFullUpdates = processFullUpdates & isTickThread;
|
|
||||||
final boolean canProcessScheduling = scheduledTasks == null;
|
|
||||||
|
|
||||||
if (this.ticketLevelPropagator.hasPendingUpdates()) {
|
if (this.ticketLevelPropagator.hasPendingUpdates()) {
|
||||||
if (scheduledTasks == null) {
|
final List<ChunkProgressionTask> scheduledTasks = new ArrayList<>();
|
||||||
scheduledTasks = new ArrayList<>();
|
final List<NewChunkHolder> changedFullStatus = new ArrayList<>();
|
||||||
}
|
|
||||||
changedFullStatus = new ArrayList<>();
|
|
||||||
|
|
||||||
this.blockTicketUpdates();
|
this.blockTicketUpdates();
|
||||||
try {
|
try {
|
||||||
@@ -1334,27 +1424,42 @@ public final class ChunkHolderManager {
|
|||||||
} finally {
|
} finally {
|
||||||
this.unblockTicketUpdates(Boolean.FALSE);
|
this.unblockTicketUpdates(Boolean.FALSE);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (changedFullStatus != null) {
|
|
||||||
this.addChangedStatuses(changedFullStatus);
|
this.addChangedStatuses(changedFullStatus);
|
||||||
}
|
|
||||||
|
|
||||||
if (canProcessScheduling && scheduledTasks != null) {
|
|
||||||
for (int i = 0, len = scheduledTasks.size(); i < len; ++i) {
|
for (int i = 0, len = scheduledTasks.size(); i < len; ++i) {
|
||||||
scheduledTasks.get(i).schedule();
|
scheduledTasks.get(i).schedule();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canProcessFullUpdates) {
|
if (isTickThread) {
|
||||||
ret |= this.processPendingFullUpdate();
|
ret |= this.processPendingFullUpdate();
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static final ThreadLocal<List<ChunkProgressionTask>> CURRENT_TICKET_UPDATE_SCHEDULING = new ThreadLocal<>();
|
||||||
|
|
||||||
|
static List<ChunkProgressionTask> getCurrentTicketUpdateScheduling() {
|
||||||
|
return CURRENT_TICKET_UPDATE_SCHEDULING.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
// only call on tick thread
|
||||||
|
private void processOffThreadFullUpdates() {
|
||||||
|
final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = this.pendingFullLoadUpdate;
|
||||||
|
final MultiThreadedQueue<NewChunkHolder> offThreadPendingFullLoadUpdate = this.offThreadPendingFullLoadUpdate;
|
||||||
|
|
||||||
|
NewChunkHolder toUpdate;
|
||||||
|
while ((toUpdate = offThreadPendingFullLoadUpdate.poll()) != null) {
|
||||||
|
pendingFullLoadUpdate.add(toUpdate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// only call on tick thread
|
// only call on tick thread
|
||||||
private boolean processPendingFullUpdate() {
|
private boolean processPendingFullUpdate() {
|
||||||
|
this.processOffThreadFullUpdates();
|
||||||
|
|
||||||
final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = this.pendingFullLoadUpdate;
|
final ArrayDeque<NewChunkHolder> pendingFullLoadUpdate = this.pendingFullLoadUpdate;
|
||||||
|
|
||||||
boolean ret = false;
|
boolean ret = false;
|
||||||
@@ -1391,11 +1496,11 @@ public final class ChunkHolderManager {
|
|||||||
final JsonArray allTicketsJson = new JsonArray();
|
final JsonArray allTicketsJson = new JsonArray();
|
||||||
ret.add("tickets", allTicketsJson);
|
ret.add("tickets", allTicketsJson);
|
||||||
|
|
||||||
for (final Iterator<ConcurrentLong2ReferenceChainedHashTable.TableEntry<SortedArraySet<Ticket<?>>>> iterator = this.tickets.entryIterator();
|
for (final Iterator<ConcurrentLong2ReferenceChainedHashTable.TableEntry<SortedArraySet<Ticket>>> iterator = this.tickets.entryIterator();
|
||||||
iterator.hasNext();) {
|
iterator.hasNext();) {
|
||||||
final ConcurrentLong2ReferenceChainedHashTable.TableEntry<SortedArraySet<Ticket<?>>> coordinateTickets = iterator.next();
|
final ConcurrentLong2ReferenceChainedHashTable.TableEntry<SortedArraySet<Ticket>> coordinateTickets = iterator.next();
|
||||||
final long coordinate = coordinateTickets.getKey();
|
final long coordinate = coordinateTickets.getKey();
|
||||||
final SortedArraySet<Ticket<?>> tickets = coordinateTickets.getValue();
|
final SortedArraySet<Ticket> tickets = coordinateTickets.getValue();
|
||||||
|
|
||||||
final JsonObject coordinateJson = new JsonObject();
|
final JsonObject coordinateJson = new JsonObject();
|
||||||
allTicketsJson.add(coordinateJson);
|
allTicketsJson.add(coordinateJson);
|
||||||
@@ -1410,17 +1515,17 @@ public final class ChunkHolderManager {
|
|||||||
// directly over the set using the iterator
|
// directly over the set using the iterator
|
||||||
// however, it also means we need to null-check the values, and there is a possibility that we _miss_ an
|
// however, it also means we need to null-check the values, and there is a possibility that we _miss_ an
|
||||||
// entry OR iterate over an entry multiple times
|
// entry OR iterate over an entry multiple times
|
||||||
for (final Object ticketUncasted : ((ChunkSystemSortedArraySet<Ticket<?>>)tickets).moonrise$copyBackingArray()) {
|
for (final Object ticketUncasted : ((ChunkSystemSortedArraySet<Ticket>)tickets).moonrise$copyBackingArray()) {
|
||||||
if (ticketUncasted == null) {
|
if (ticketUncasted == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
final Ticket<?> ticket = (Ticket<?>)ticketUncasted;
|
final Ticket ticket = (Ticket)ticketUncasted;
|
||||||
final JsonObject ticketSerialized = new JsonObject();
|
final JsonObject ticketSerialized = new JsonObject();
|
||||||
ticketsSerialized.add(ticketSerialized);
|
ticketsSerialized.add(ticketSerialized);
|
||||||
|
|
||||||
ticketSerialized.addProperty("type", ticket.getType().toString());
|
ticketSerialized.addProperty("type", ticket.getType().toString());
|
||||||
ticketSerialized.addProperty("level", Integer.valueOf(ticket.getTicketLevel()));
|
ticketSerialized.addProperty("level", Integer.valueOf(ticket.getTicketLevel()));
|
||||||
ticketSerialized.addProperty("identifier", Objects.toString(ticket.key));
|
ticketSerialized.addProperty("identifier", Objects.toString(((ChunkSystemTicket<?>)(Object)ticket).moonrise$getIdentifier()));
|
||||||
ticketSerialized.addProperty("remove_tick", Long.valueOf(((ChunkSystemTicket<?>)(Object)ticket).moonrise$getRemoveDelay()));
|
ticketSerialized.addProperty("remove_tick", Long.valueOf(((ChunkSystemTicket<?>)(Object)ticket).moonrise$getRemoveDelay()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.ChunkProgres
|
|||||||
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.ChunkUpgradeGenericStatusTask;
|
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.task.ChunkUpgradeGenericStatusTask;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer;
|
import ca.spottedleaf.moonrise.patches.chunk_system.server.ChunkSystemMinecraftServer;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.status.ChunkSystemChunkStep;
|
import ca.spottedleaf.moonrise.patches.chunk_system.status.ChunkSystemChunkStep;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.util.ParallelSearchRadiusIteration;
|
import ca.spottedleaf.moonrise.patches.chunk_system.util.ParallelSearchRadiusIteration;
|
||||||
import com.google.gson.JsonArray;
|
import com.google.gson.JsonArray;
|
||||||
import com.google.gson.JsonObject;
|
import com.google.gson.JsonObject;
|
||||||
@@ -73,35 +74,35 @@ public final class ChunkTaskScheduler {
|
|||||||
LOGGER.info("Chunk system is using population gen parallelism: " + useParallelGen);
|
LOGGER.info("Chunk system is using population gen parallelism: " + useParallelGen);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final TicketType<Long> CHUNK_LOAD = TicketType.create("chunk_system:chunk_load", Long::compareTo);
|
public static final TicketType CHUNK_LOAD = ChunkSystemTicketType.create("chunk_system:chunk_load", Long::compareTo);
|
||||||
private static final AtomicLong CHUNK_LOAD_IDS = new AtomicLong();
|
private static final AtomicLong CHUNK_LOAD_IDS = new AtomicLong();
|
||||||
|
|
||||||
public static Long getNextChunkLoadId() {
|
public static Long getNextChunkLoadId() {
|
||||||
return Long.valueOf(CHUNK_LOAD_IDS.getAndIncrement());
|
return Long.valueOf(CHUNK_LOAD_IDS.getAndIncrement());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final TicketType<Long> NON_FULL_CHUNK_LOAD = TicketType.create("chunk_system:non_full_load", Long::compareTo);
|
public static final TicketType NON_FULL_CHUNK_LOAD = ChunkSystemTicketType.create("chunk_system:non_full_load", Long::compareTo);
|
||||||
private static final AtomicLong NON_FULL_CHUNK_LOAD_IDS = new AtomicLong();
|
private static final AtomicLong NON_FULL_CHUNK_LOAD_IDS = new AtomicLong();
|
||||||
|
|
||||||
public static Long getNextNonFullLoadId() {
|
public static Long getNextNonFullLoadId() {
|
||||||
return Long.valueOf(NON_FULL_CHUNK_LOAD_IDS.getAndIncrement());
|
return Long.valueOf(NON_FULL_CHUNK_LOAD_IDS.getAndIncrement());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final TicketType<Long> ENTITY_LOAD = TicketType.create("chunk_system:entity_load", Long::compareTo);
|
public static final TicketType ENTITY_LOAD = ChunkSystemTicketType.create("chunk_system:entity_load", Long::compareTo);
|
||||||
private static final AtomicLong ENTITY_LOAD_IDS = new AtomicLong();
|
private static final AtomicLong ENTITY_LOAD_IDS = new AtomicLong();
|
||||||
|
|
||||||
public static Long getNextEntityLoadId() {
|
public static Long getNextEntityLoadId() {
|
||||||
return Long.valueOf(ENTITY_LOAD_IDS.getAndIncrement());
|
return Long.valueOf(ENTITY_LOAD_IDS.getAndIncrement());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final TicketType<Long> POI_LOAD = TicketType.create("chunk_system:poi_load", Long::compareTo);
|
public static final TicketType POI_LOAD = ChunkSystemTicketType.create("chunk_system:poi_load", Long::compareTo);
|
||||||
private static final AtomicLong POI_LOAD_IDS = new AtomicLong();
|
private static final AtomicLong POI_LOAD_IDS = new AtomicLong();
|
||||||
|
|
||||||
public static Long getNextPoiLoadId() {
|
public static Long getNextPoiLoadId() {
|
||||||
return Long.valueOf(POI_LOAD_IDS.getAndIncrement());
|
return Long.valueOf(POI_LOAD_IDS.getAndIncrement());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final TicketType<Long> CHUNK_RELIGHT = TicketType.create("starlight:chunk_relight", Long::compareTo);
|
public static final TicketType CHUNK_RELIGHT = ChunkSystemTicketType.create("starlight:chunk_relight", Long::compareTo);
|
||||||
private static final AtomicLong CHUNK_RELIGHT_IDS = new AtomicLong();
|
private static final AtomicLong CHUNK_RELIGHT_IDS = new AtomicLong();
|
||||||
|
|
||||||
public static Long getNextChunkRelightId() {
|
public static Long getNextChunkRelightId() {
|
||||||
|
|||||||
@@ -117,9 +117,11 @@ public final class NewChunkHolder {
|
|||||||
|
|
||||||
if (!transientChunk) {
|
if (!transientChunk) {
|
||||||
if (entityChunk != null) {
|
if (entityChunk != null) {
|
||||||
final List<Entity> entities = ChunkEntitySlices.readEntities(this.world, entityChunk);
|
final ChunkPos pos = new ChunkPos(this.chunkX, this.chunkZ);
|
||||||
|
|
||||||
((ChunkSystemServerLevel)this.world).moonrise$getEntityLookup().addEntityChunkEntities(entities, new ChunkPos(this.chunkX, this.chunkZ));
|
final List<Entity> entities = ChunkEntitySlices.readEntities(this.world, pos, entityChunk);
|
||||||
|
|
||||||
|
((ChunkSystemServerLevel)this.world).moonrise$getEntityLookup().addEntityChunkEntities(entities, pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ public final class ChunkFullTask extends ChunkProgressionTask implements Runnabl
|
|||||||
this.chunkHolder.replaceProtoChunk(new ImposterProtoChunk(chunk, false));
|
this.chunkHolder.replaceProtoChunk(new ImposterProtoChunk(chunk, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
((ChunkSystemLevelChunk)chunk).moonrise$setChunkAndHolder(new ServerChunkCache.ChunkAndHolder(chunk, this.chunkHolder.vanillaChunkHolder));
|
((ChunkSystemLevelChunk)chunk).moonrise$setChunkHolder(this.chunkHolder);
|
||||||
|
|
||||||
final NewChunkHolder chunkHolder = this.chunkHolder;
|
final NewChunkHolder chunkHolder = this.chunkHolder;
|
||||||
|
|
||||||
|
|||||||
@@ -6,4 +6,8 @@ public interface ChunkSystemTicket<T> {
|
|||||||
|
|
||||||
public void moonrise$setRemoveDelay(final long removeDelay);
|
public void moonrise$setRemoveDelay(final long removeDelay);
|
||||||
|
|
||||||
|
public T moonrise$getIdentifier();
|
||||||
|
|
||||||
|
public void moonrise$setIdentifier(final T identifier);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package ca.spottedleaf.moonrise.patches.chunk_system.ticket;
|
||||||
|
|
||||||
|
import net.minecraft.server.level.ChunkMap;
|
||||||
|
|
||||||
|
public interface ChunkSystemTicketStorage {
|
||||||
|
|
||||||
|
public ChunkMap moonrise$getChunkMap();
|
||||||
|
|
||||||
|
public void moonrise$setChunkMap(final ChunkMap chunkMap);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package ca.spottedleaf.moonrise.patches.chunk_system.ticket;
|
||||||
|
|
||||||
|
import net.minecraft.server.level.TicketType;
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
|
public interface ChunkSystemTicketType<T> {
|
||||||
|
|
||||||
|
public static final long COUNTER_TYPE_FORCED = 0L;
|
||||||
|
// used only by neoforge
|
||||||
|
public static final long COUNTER_TYPER_NATURAL_SPAWNING_FORCED = 1L;
|
||||||
|
|
||||||
|
public static <T> TicketType create(final String name, final Comparator<T> identifierComparator) {
|
||||||
|
return create(name, identifierComparator, 0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static <T> TicketType create(final String name, final Comparator<T> identifierComparator, final long timeout) {
|
||||||
|
// note: cannot persist unless registered
|
||||||
|
final TicketType ret = new TicketType(timeout, false, TicketType.TicketUse.LOADING_AND_SIMULATION);
|
||||||
|
|
||||||
|
((ChunkSystemTicketType<T>)(Object)ret).moonrise$setIdentifierComparator(identifierComparator);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long moonrise$getId();
|
||||||
|
|
||||||
|
public Comparator<T> moonrise$getIdentifierComparator();
|
||||||
|
|
||||||
|
public void moonrise$setIdentifierComparator(final Comparator<T> comparator);
|
||||||
|
|
||||||
|
public long[] moonrise$getCounterTypes();
|
||||||
|
|
||||||
|
public void moonrise$setTimeout(final long to);
|
||||||
|
}
|
||||||
@@ -3,5 +3,13 @@ package ca.spottedleaf.moonrise.patches.chunk_tick_iteration;
|
|||||||
public final class ChunkTickConstants {
|
public final class ChunkTickConstants {
|
||||||
|
|
||||||
public static final int PLAYER_SPAWN_TRACK_RANGE = 8;
|
public static final int PLAYER_SPAWN_TRACK_RANGE = 8;
|
||||||
|
// the smallest distance on x/z is at 45 degrees, we need to subtract 0.5 since this is calculated from chunk center and not chunk perimeter
|
||||||
|
// note: vanilla does not subtract 0.5 but the result is (luckily!) the same
|
||||||
|
public static final int NARROW_SPAWN_TRACK_RANGE = (int)Math.floor(((double)PLAYER_SPAWN_TRACK_RANGE / Math.sqrt(2.0)) - 0.5);
|
||||||
|
static {
|
||||||
|
if (NARROW_SPAWN_TRACK_RANGE < 0) {
|
||||||
|
throw new IllegalStateException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,4 +13,6 @@ public interface ChunkTickDistanceManager {
|
|||||||
final SectionPos oldPos, final SectionPos newPos,
|
final SectionPos oldPos, final SectionPos newPos,
|
||||||
final boolean oldIgnore, final boolean newIgnore);
|
final boolean oldIgnore, final boolean newIgnore);
|
||||||
|
|
||||||
|
public boolean moonrise$hasAnyNearbyNarrow(final int chunkX, final int chunkZ);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import net.minecraft.world.level.chunk.LevelChunk;
|
|||||||
|
|
||||||
public interface ChunkTickServerLevel {
|
public interface ChunkTickServerLevel {
|
||||||
|
|
||||||
public ReferenceList<ServerChunkCache.ChunkAndHolder> moonrise$getPlayerTickingChunks();
|
public ReferenceList<LevelChunk> moonrise$getPlayerTickingChunks();
|
||||||
|
|
||||||
public void moonrise$markChunkForPlayerTicking(final LevelChunk chunk);
|
public void moonrise$markChunkForPlayerTicking(final LevelChunk chunk);
|
||||||
|
|
||||||
|
|||||||
@@ -2004,11 +2004,10 @@ public final class CollisionUtil {
|
|||||||
VoxelShape blockCollision = ((CollisionBlockState)blockData).moonrise$getConstantContextCollisionShape();
|
VoxelShape blockCollision = ((CollisionBlockState)blockData).moonrise$getConstantContextCollisionShape();
|
||||||
|
|
||||||
if (edgeCount == 0 || ((edgeCount != 1 || blockData.hasLargeCollisionShape()) && (edgeCount != 2 || blockData.getBlock() == Blocks.MOVING_PISTON))) {
|
if (edgeCount == 0 || ((edgeCount != 1 || blockData.hasLargeCollisionShape()) && (edgeCount != 2 || blockData.getBlock() == Blocks.MOVING_PISTON))) {
|
||||||
|
mutablePos.set(blockX, blockY, blockZ);
|
||||||
if (useEntityCollisionShape) {
|
if (useEntityCollisionShape) {
|
||||||
mutablePos.set(blockX, blockY, blockZ);
|
|
||||||
blockCollision = collisionShape.getCollisionShape(blockData, world, mutablePos);
|
blockCollision = collisionShape.getCollisionShape(blockData, world, mutablePos);
|
||||||
} else if (blockCollision == null) {
|
} else if (blockCollision == null) {
|
||||||
mutablePos.set(blockX, blockY, blockZ);
|
|
||||||
blockCollision = blockData.getCollisionShape(world, mutablePos, collisionShape);
|
blockCollision = blockData.getCollisionShape(world, mutablePos, collisionShape);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2020,7 +2019,6 @@ public final class CollisionUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (predicate != null) {
|
if (predicate != null) {
|
||||||
mutablePos.set(blockX, blockY, blockZ);
|
|
||||||
if (!predicate.test(blockData, mutablePos)) {
|
if (!predicate.test(blockData, mutablePos)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -2046,7 +2044,6 @@ public final class CollisionUtil {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (predicate != null) {
|
if (predicate != null) {
|
||||||
mutablePos.set(blockX, blockY, blockZ);
|
|
||||||
if (!predicate.test(blockData, mutablePos)) {
|
if (!predicate.test(blockData, mutablePos)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -2094,7 +2091,7 @@ public final class CollisionUtil {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((entity == null && otherEntity.canBeCollidedWith()) || (entity != null && entity.canCollideWith(otherEntity))) {
|
if ((entity == null && otherEntity.canBeCollidedWith(entity)) || (entity != null && entity.canCollideWith(otherEntity))) {
|
||||||
if (checkOnly) {
|
if (checkOnly) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
@@ -2126,7 +2123,7 @@ public final class CollisionUtil {
|
|||||||
private boolean delegated;
|
private boolean delegated;
|
||||||
|
|
||||||
public LazyEntityCollisionContext(final Entity entity) {
|
public LazyEntityCollisionContext(final Entity entity) {
|
||||||
super(false, 0.0, null, null, entity);
|
super(false, false, 0.0, null, null, entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean useEntityCollisionShape(final Level world, final Entity entity) {
|
public static boolean useEntityCollisionShape(final Level world, final Entity entity) {
|
||||||
@@ -2156,6 +2153,11 @@ public final class CollisionUtil {
|
|||||||
return this.getDelegate().isDescending();
|
return this.getDelegate().isDescending();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isPlacement() {
|
||||||
|
return this.getDelegate().isPlacement();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isAbove(final VoxelShape shape, final BlockPos pos, final boolean defaultValue) {
|
public boolean isAbove(final VoxelShape shape, final BlockPos pos, final boolean defaultValue) {
|
||||||
return this.getDelegate().isAbove(shape, pos, defaultValue);
|
return this.getDelegate().isAbove(shape, pos, defaultValue);
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ public abstract class StarLightEngine {
|
|||||||
for (int dx = -radius; dx <= radius; ++dx) {
|
for (int dx = -radius; dx <= radius; ++dx) {
|
||||||
final int cx = centerChunkX + dx;
|
final int cx = centerChunkX + dx;
|
||||||
final int cz = centerChunkZ + dz;
|
final int cz = centerChunkZ + dz;
|
||||||
final boolean isTwoRadius = Math.max(IntegerUtil.branchlessAbs(dx), IntegerUtil.branchlessAbs(dz)) == 2;
|
final boolean isTwoRadius = Math.max(Math.abs(dx), Math.abs(dz)) == 2;
|
||||||
final ChunkAccess chunk = (ChunkAccess)chunkProvider.getChunkForLighting(cx, cz);
|
final ChunkAccess chunk = (ChunkAccess)chunkProvider.getChunkForLighting(cx, cz);
|
||||||
|
|
||||||
if (chunk == null) {
|
if (chunk == null) {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import ca.spottedleaf.moonrise.common.util.WorldUtil;
|
|||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunkStatus;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunkStatus;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.ticket.ChunkSystemTicketType;
|
||||||
import ca.spottedleaf.moonrise.patches.starlight.chunk.StarlightChunk;
|
import ca.spottedleaf.moonrise.patches.starlight.chunk.StarlightChunk;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.shorts.ShortCollection;
|
import it.unimi.dsi.fastutil.shorts.ShortCollection;
|
||||||
@@ -39,10 +40,8 @@ import java.util.function.IntConsumer;
|
|||||||
|
|
||||||
public final class StarLightInterface {
|
public final class StarLightInterface {
|
||||||
|
|
||||||
public static final TicketType<Long> CHUNK_WORK_TICKET = TicketType.create("starlight:chunk_work_ticket", Long::compareTo);
|
public static final TicketType CHUNK_WORK_TICKET = ChunkSystemTicketType.create("starlight:chunk_work_ticket", Long::compareTo);
|
||||||
public static final int LIGHT_TICKET_LEVEL = ChunkLevel.byStatus(ChunkStatus.LIGHT);
|
public static final int LIGHT_TICKET_LEVEL = ChunkLevel.byStatus(ChunkStatus.LIGHT);
|
||||||
// ticket level = ChunkLevel.byStatus(FullChunkStatus.FULL) - input
|
|
||||||
public static final int REGION_LIGHT_TICKET_LEVEL = ChunkLevel.byStatus(FullChunkStatus.FULL) - LIGHT_TICKET_LEVEL;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Can be {@code null}, indicating the light is all empty.
|
* Can be {@code null}, indicating the light is all empty.
|
||||||
|
|||||||
@@ -56,15 +56,18 @@ public final class SaveUtil {
|
|||||||
tag.putBoolean("isLightOn", false);
|
tag.putBoolean("isLightOn", false);
|
||||||
}
|
}
|
||||||
// diff end - store our tag for whether light data is init'd
|
// diff end - store our tag for whether light data is init'd
|
||||||
ChunkStatus status = ChunkStatus.byName(tag.getString("Status"));
|
ChunkStatus status = tag.read("Status", ChunkStatus.CODEC).orElse(ChunkStatus.EMPTY);
|
||||||
|
|
||||||
CompoundTag[] sections = new CompoundTag[maxSection - minSection + 1];
|
CompoundTag[] sections = new CompoundTag[maxSection - minSection + 1];
|
||||||
|
|
||||||
ListTag sectionsStored = tag.getList("sections", 10);
|
ListTag sectionsStored = tag.getListOrEmpty("sections");
|
||||||
|
|
||||||
for (int i = 0; i < sectionsStored.size(); ++i) {
|
for (int i = 0; i < sectionsStored.size(); ++i) {
|
||||||
CompoundTag sectionStored = sectionsStored.getCompound(i);
|
CompoundTag sectionStored = sectionsStored.getCompound(i).orElse(null);
|
||||||
int k = sectionStored.getByte("Y");
|
if (sectionStored == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int k = sectionStored.getByteOr("Y", (byte)0);
|
||||||
|
|
||||||
// strip light data
|
// strip light data
|
||||||
sectionStored.remove("BlockLight");
|
sectionStored.remove("BlockLight");
|
||||||
@@ -147,33 +150,38 @@ public final class SaveUtil {
|
|||||||
|
|
||||||
|
|
||||||
// start copy from the original method
|
// start copy from the original method
|
||||||
boolean lit = tag.get("isLightOn") != null && tag.getInt(STARLIGHT_VERSION_TAG) == STARLIGHT_LIGHT_VERSION;
|
boolean lit = tag.get("isLightOn") != null && tag.getIntOr(STARLIGHT_VERSION_TAG, -1) == STARLIGHT_LIGHT_VERSION;
|
||||||
boolean canReadSky = world.dimensionType().hasSkyLight();
|
boolean canReadSky = world.dimensionType().hasSkyLight();
|
||||||
ChunkStatus status = ChunkStatus.byName(tag.getString("Status"));
|
ChunkStatus status = tag.read("Status", ChunkStatus.CODEC).orElse(ChunkStatus.EMPTY);
|
||||||
if (lit && status.isOrAfter(ChunkStatus.LIGHT)) { // diff - we add the status check here
|
if (lit && status.isOrAfter(ChunkStatus.LIGHT)) { // diff - we add the status check here
|
||||||
ListTag sections = tag.getList("sections", 10);
|
ListTag sections = tag.getListOrEmpty("sections");
|
||||||
|
|
||||||
for (int i = 0; i < sections.size(); ++i) {
|
for (int i = 0; i < sections.size(); ++i) {
|
||||||
CompoundTag sectionData = sections.getCompound(i);
|
CompoundTag sectionData = sections.getCompound(i).orElse(null);
|
||||||
int y = sectionData.getByte("Y");
|
if (sectionData == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
int y = sectionData.getByteOr("Y", (byte)0);
|
||||||
|
|
||||||
if (sectionData.contains("BlockLight", 7)) {
|
final byte[] blockLight = sectionData.getByteArray("BlockLight").orElse(null);
|
||||||
|
if (blockLight != null) {
|
||||||
// this is where our diff is
|
// this is where our diff is
|
||||||
blockNibbles[y - minSection] = new SWMRNibbleArray(sectionData.getByteArray("BlockLight").clone(), sectionData.getInt(BLOCKLIGHT_STATE_TAG)); // clone for data safety
|
blockNibbles[y - minSection] = new SWMRNibbleArray(blockLight.clone(), sectionData.getIntOr(BLOCKLIGHT_STATE_TAG, 0)); // clone for data safety
|
||||||
} else {
|
} else {
|
||||||
blockNibbles[y - minSection] = new SWMRNibbleArray(null, sectionData.getInt(BLOCKLIGHT_STATE_TAG));
|
blockNibbles[y - minSection] = new SWMRNibbleArray(null, sectionData.getIntOr(BLOCKLIGHT_STATE_TAG, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (canReadSky) {
|
if (canReadSky) {
|
||||||
if (sectionData.contains("SkyLight", 7)) {
|
final byte[] skyLight = sectionData.getByteArray("SkyLight").orElse(null);
|
||||||
|
if (skyLight != null) {
|
||||||
// we store under the same key so mod programs editing nbt
|
// we store under the same key so mod programs editing nbt
|
||||||
// can still read the data, hopefully.
|
// can still read the data, hopefully.
|
||||||
// however, for compatibility we store chunks as unlit so vanilla
|
// however, for compatibility we store chunks as unlit so vanilla
|
||||||
// is forced to re-light them if it encounters our data. It's too much of a burden
|
// is forced to re-light them if it encounters our data. It's too much of a burden
|
||||||
// to try and maintain compatibility with a broken and inferior skylight management system.
|
// to try and maintain compatibility with a broken and inferior skylight management system.
|
||||||
skyNibbles[y - minSection] = new SWMRNibbleArray(sectionData.getByteArray("SkyLight").clone(), sectionData.getInt(SKYLIGHT_STATE_TAG)); // clone for data safety
|
skyNibbles[y - minSection] = new SWMRNibbleArray(skyLight.clone(), sectionData.getIntOr(SKYLIGHT_STATE_TAG, 0)); // clone for data safety
|
||||||
} else {
|
} else {
|
||||||
skyNibbles[y - minSection] = new SWMRNibbleArray(null, sectionData.getInt(SKYLIGHT_STATE_TAG));
|
skyNibbles[y - minSection] = new SWMRNibbleArray(null, sectionData.getIntOr(SKYLIGHT_STATE_TAG, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -177,7 +177,7 @@ accessible method net/minecraft/server/network/PlayerChunkSender sendChunk (Lnet
|
|||||||
|
|
||||||
|
|
||||||
# ChunkStatusTasks
|
# ChunkStatusTasks
|
||||||
accessible method net/minecraft/world/level/chunk/status/ChunkStatusTasks postLoadProtoChunk (Lnet/minecraft/server/level/ServerLevel;Ljava/util/List;)V
|
accessible method net/minecraft/world/level/chunk/status/ChunkStatusTasks postLoadProtoChunk (Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/level/storage/ValueInput$ValueInputList;)V
|
||||||
accessible method net/minecraft/world/level/chunk/status/ChunkStatusTasks light (Lnet/minecraft/world/level/chunk/status/WorldGenContext;Lnet/minecraft/world/level/chunk/status/ChunkStep;Lnet/minecraft/util/StaticCache2D;Lnet/minecraft/world/level/chunk/ChunkAccess;)Ljava/util/concurrent/CompletableFuture;
|
accessible method net/minecraft/world/level/chunk/status/ChunkStatusTasks light (Lnet/minecraft/world/level/chunk/status/WorldGenContext;Lnet/minecraft/world/level/chunk/status/ChunkStep;Lnet/minecraft/util/StaticCache2D;Lnet/minecraft/world/level/chunk/ChunkAccess;)Ljava/util/concurrent/CompletableFuture;
|
||||||
|
|
||||||
|
|
||||||
@@ -194,9 +194,8 @@ accessible class net/minecraft/server/level/ChunkMap$DistanceManager
|
|||||||
|
|
||||||
# DistanceManager
|
# DistanceManager
|
||||||
mutable field net/minecraft/server/level/DistanceManager playersPerChunk Lit/unimi/dsi/fastutil/longs/Long2ObjectMap;
|
mutable field net/minecraft/server/level/DistanceManager playersPerChunk Lit/unimi/dsi/fastutil/longs/Long2ObjectMap;
|
||||||
mutable field net/minecraft/server/level/DistanceManager tickets Lit/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap;
|
mutable field net/minecraft/server/level/DistanceManager loadingChunkTracker Lnet/minecraft/server/level/LoadingChunkTracker;
|
||||||
mutable field net/minecraft/server/level/DistanceManager ticketTracker Lnet/minecraft/server/level/DistanceManager$ChunkTicketTracker;
|
mutable field net/minecraft/server/level/DistanceManager simulationChunkTracker Lnet/minecraft/server/level/SimulationChunkTracker;
|
||||||
mutable field net/minecraft/server/level/DistanceManager tickingTicketsTracker Lnet/minecraft/server/level/TickingTracker;
|
|
||||||
mutable field net/minecraft/server/level/DistanceManager playerTicketManager Lnet/minecraft/server/level/DistanceManager$PlayerTicketTracker;
|
mutable field net/minecraft/server/level/DistanceManager playerTicketManager Lnet/minecraft/server/level/DistanceManager$PlayerTicketTracker;
|
||||||
mutable field net/minecraft/server/level/DistanceManager chunksToUpdateFutures Ljava/util/Set;
|
mutable field net/minecraft/server/level/DistanceManager chunksToUpdateFutures Ljava/util/Set;
|
||||||
mutable field net/minecraft/server/level/DistanceManager ticketDispatcher Lnet/minecraft/server/level/ThrottlingChunkTaskDispatcher;
|
mutable field net/minecraft/server/level/DistanceManager ticketDispatcher Lnet/minecraft/server/level/ThrottlingChunkTaskDispatcher;
|
||||||
@@ -205,10 +204,6 @@ mutable field net/minecraft/server/level/DistanceManager mainThreadExecutor Ljav
|
|||||||
mutable field net/minecraft/server/level/DistanceManager naturalSpawnChunkCounter Lnet/minecraft/server/level/DistanceManager$FixedPlayerDistanceChunkTracker;
|
mutable field net/minecraft/server/level/DistanceManager naturalSpawnChunkCounter Lnet/minecraft/server/level/DistanceManager$FixedPlayerDistanceChunkTracker;
|
||||||
|
|
||||||
|
|
||||||
# DistanceManager$ChunkTicketTracker
|
|
||||||
accessible class net/minecraft/server/level/DistanceManager$ChunkTicketTracker
|
|
||||||
|
|
||||||
|
|
||||||
# DistanceManager$PlayerTicketTracker
|
# DistanceManager$PlayerTicketTracker
|
||||||
accessible class net/minecraft/server/level/DistanceManager$PlayerTicketTracker
|
accessible class net/minecraft/server/level/DistanceManager$PlayerTicketTracker
|
||||||
|
|
||||||
@@ -217,11 +212,6 @@ accessible class net/minecraft/server/level/DistanceManager$PlayerTicketTracker
|
|||||||
accessible class net/minecraft/server/level/DistanceManager$FixedPlayerDistanceChunkTracker
|
accessible class net/minecraft/server/level/DistanceManager$FixedPlayerDistanceChunkTracker
|
||||||
|
|
||||||
|
|
||||||
# Ticket
|
|
||||||
accessible field net/minecraft/server/level/Ticket key Ljava/lang/Object;
|
|
||||||
accessible field net/minecraft/server/level/TicketType timeout J
|
|
||||||
|
|
||||||
|
|
||||||
# ServerChunkCache
|
# ServerChunkCache
|
||||||
accessible method net/minecraft/server/level/ServerChunkCache runDistanceManagerUpdates ()Z
|
accessible method net/minecraft/server/level/ServerChunkCache runDistanceManagerUpdates ()Z
|
||||||
accessible field net/minecraft/server/level/ServerChunkCache level Lnet/minecraft/server/level/ServerLevel;
|
accessible field net/minecraft/server/level/ServerChunkCache level Lnet/minecraft/server/level/ServerLevel;
|
||||||
@@ -241,14 +231,6 @@ accessible class net/minecraft/server/level/ServerLevel$EntityCallbacks
|
|||||||
accessible method net/minecraft/server/level/ServerLevel$EntityCallbacks <init> (Lnet/minecraft/server/level/ServerLevel;)V
|
accessible method net/minecraft/server/level/ServerLevel$EntityCallbacks <init> (Lnet/minecraft/server/level/ServerLevel;)V
|
||||||
|
|
||||||
|
|
||||||
# EntityStorage
|
|
||||||
accessible method net/minecraft/world/level/chunk/storage/EntityStorage readChunkPos (Lnet/minecraft/nbt/CompoundTag;)Lnet/minecraft/world/level/ChunkPos;
|
|
||||||
accessible method net/minecraft/world/level/chunk/storage/EntityStorage writeChunkPos (Lnet/minecraft/nbt/CompoundTag;Lnet/minecraft/world/level/ChunkPos;)V
|
|
||||||
|
|
||||||
# Ticket
|
|
||||||
accessible method net/minecraft/server/level/Ticket <init> (Lnet/minecraft/server/level/TicketType;ILjava/lang/Object;)V
|
|
||||||
|
|
||||||
|
|
||||||
# ChunkStorage
|
# ChunkStorage
|
||||||
accessible field net/minecraft/world/level/chunk/storage/ChunkStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker;
|
accessible field net/minecraft/world/level/chunk/storage/ChunkStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker;
|
||||||
mutable field net/minecraft/world/level/chunk/storage/ChunkStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker;
|
mutable field net/minecraft/world/level/chunk/storage/ChunkStorage worker Lnet/minecraft/world/level/chunk/storage/IOWorker;
|
||||||
@@ -285,11 +267,6 @@ accessible class net/minecraft/server/level/ChunkMap$TrackedEntity
|
|||||||
accessible field net/minecraft/server/level/ChunkMap$TrackedEntity serverEntity Lnet/minecraft/server/level/ServerEntity;
|
accessible field net/minecraft/server/level/ChunkMap$TrackedEntity serverEntity Lnet/minecraft/server/level/ServerEntity;
|
||||||
|
|
||||||
|
|
||||||
# ServerChunkCache$ChunkAndHolder
|
|
||||||
accessible class net/minecraft/server/level/ServerChunkCache$ChunkAndHolder
|
|
||||||
accessible method net/minecraft/server/level/ServerChunkCache$ChunkAndHolder <init> (Lnet/minecraft/world/level/chunk/LevelChunk;Lnet/minecraft/server/level/ChunkHolder;)V
|
|
||||||
|
|
||||||
|
|
||||||
# LevelLoadStatusManager$Status
|
# LevelLoadStatusManager$Status
|
||||||
accessible class net/minecraft/client/multiplayer/LevelLoadStatusManager$Status
|
accessible class net/minecraft/client/multiplayer/LevelLoadStatusManager$Status
|
||||||
|
|
||||||
@@ -314,3 +291,15 @@ accessible class net/minecraft/world/level/LocalMobCapCalculator$MobCounts
|
|||||||
accessible class net/minecraft/world/level/chunk/storage/SectionStorage$PackedChunk
|
accessible class net/minecraft/world/level/chunk/storage/SectionStorage$PackedChunk
|
||||||
# MDG requires we AT the constructor if we AT the class
|
# MDG requires we AT the constructor if we AT the class
|
||||||
accessible method net/minecraft/world/level/chunk/storage/SectionStorage$PackedChunk <init> (Lit/unimi/dsi/fastutil/ints/Int2ObjectMap;Z)V
|
accessible method net/minecraft/world/level/chunk/storage/SectionStorage$PackedChunk <init> (Lit/unimi/dsi/fastutil/ints/Int2ObjectMap;Z)V
|
||||||
|
|
||||||
|
|
||||||
|
# Ticket
|
||||||
|
accessible method net/minecraft/server/level/Ticket <init> (Lnet/minecraft/server/level/TicketType;IJ)V
|
||||||
|
|
||||||
|
|
||||||
|
# LoadingChunkTracker
|
||||||
|
accessible class net/minecraft/server/level/LoadingChunkTracker
|
||||||
|
|
||||||
|
|
||||||
|
# TicketStorage
|
||||||
|
mutable field net/minecraft/world/level/TicketStorage tickets Lit/unimi/dsi/fastutil/longs/Long2ObjectOpenHashMap;
|
||||||
|
|||||||
@@ -26,6 +26,7 @@
|
|||||||
"chunk_system.ChunkStepMixin",
|
"chunk_system.ChunkStepMixin",
|
||||||
"chunk_system.ChunkStorageMixin",
|
"chunk_system.ChunkStorageMixin",
|
||||||
"chunk_system.DistanceManagerMixin",
|
"chunk_system.DistanceManagerMixin",
|
||||||
|
"chunk_system.DynamicGameEventListenerMixin",
|
||||||
"chunk_system.EntityGetterMixin",
|
"chunk_system.EntityGetterMixin",
|
||||||
"chunk_system.EntityMixin",
|
"chunk_system.EntityMixin",
|
||||||
"chunk_system.EntityTickListMixin",
|
"chunk_system.EntityTickListMixin",
|
||||||
@@ -51,6 +52,9 @@
|
|||||||
"chunk_system.StructureCheckMixin",
|
"chunk_system.StructureCheckMixin",
|
||||||
"chunk_system.StructureTemplate$PaletteMixin",
|
"chunk_system.StructureTemplate$PaletteMixin",
|
||||||
"chunk_system.TicketMixin",
|
"chunk_system.TicketMixin",
|
||||||
|
"chunk_system.TicketStorageMixin",
|
||||||
|
"chunk_system.TicketTypeMixin",
|
||||||
|
"chunk_system.WaypointTransmitterMixin",
|
||||||
"chunk_tick_iteration.ChunkMapMixin",
|
"chunk_tick_iteration.ChunkMapMixin",
|
||||||
"chunk_tick_iteration.DistanceManagerMixin",
|
"chunk_tick_iteration.DistanceManagerMixin",
|
||||||
"chunk_tick_iteration.ServerChunkCacheMixin",
|
"chunk_tick_iteration.ServerChunkCacheMixin",
|
||||||
@@ -141,5 +145,5 @@
|
|||||||
},
|
},
|
||||||
"overwrites": {
|
"overwrites": {
|
||||||
"conformVisibility": true
|
"conformVisibility": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user