Compare commits
29 Commits
mc/1.21.6
...
v0.1.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9a16a91fb8 | ||
|
|
580041a1a1 | ||
|
|
fb31d0e1f7 | ||
|
|
0b2070d781 | ||
|
|
30a79469e3 | ||
|
|
254b331259 | ||
|
|
a21c44ad31 | ||
|
|
77ba4a4584 | ||
|
|
a510acbd78 | ||
|
|
6fdc3cb1df | ||
|
|
04e2b976ac | ||
|
|
bd938e6e35 | ||
|
|
3624d261f8 | ||
|
|
6c75d6935e | ||
|
|
e40c40613d | ||
|
|
84e7106762 | ||
|
|
0218cb5979 | ||
|
|
7d0d5a56dd | ||
|
|
4597f04a6d | ||
|
|
20764890a7 | ||
|
|
f719abdb64 | ||
|
|
0dce47bba6 | ||
|
|
47584ceee1 | ||
|
|
2fc858a683 | ||
|
|
68ea18bc51 | ||
|
|
9944946b29 | ||
|
|
ec1120ed10 | ||
|
|
8040c7a264 | ||
|
|
a9e36795e5 |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -31,8 +31,6 @@ jobs:
|
|||||||
key: ${{ runner.os }}-project-local-gradle-caches-${{ hashFiles('**/libs.versions.toml', '**/*.gradle*', '**/gradle-wrapper.properties') }}
|
key: ${{ runner.os }}-project-local-gradle-caches-${{ hashFiles('**/libs.versions.toml', '**/*.gradle*', '**/gradle-wrapper.properties') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ runner.os }}-project-local-gradle-caches-
|
${{ runner.os }}-project-local-gradle-caches-
|
||||||
- name: "setup concurrentutil"
|
|
||||||
run: ./installConcurrentUtil.sh
|
|
||||||
- name: "execute gradle build"
|
- name: "execute gradle build"
|
||||||
run: ./gradlew build
|
run: ./gradlew build
|
||||||
- name: Determine Snapshot Status
|
- name: Determine Snapshot Status
|
||||||
|
|||||||
3
.gitmodules
vendored
3
.gitmodules
vendored
@@ -1,3 +0,0 @@
|
|||||||
[submodule "ConcurrentUtil"]
|
|
||||||
path = ConcurrentUtil
|
|
||||||
url = https://github.com/Spottedleaf/ConcurrentUtil.git
|
|
||||||
|
|||||||
Submodule ConcurrentUtil deleted from 08d3ca3241
@@ -24,7 +24,7 @@ patches. Listed below are notable patches:
|
|||||||
| Mod | Status |
|
| Mod | Status |
|
||||||
|-------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|-------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| Lithium | <details><summary>✅ compatible</summary>Lithium optimises many of the same parts of the game as Moonrise, for example the chunk system. Moonrise will automatically disable conflicting parts of Lithium. This mechanism needs to be manually validated for each Moonrise and Lithium release.</details> |
|
| Lithium | <details><summary>✅ compatible</summary>Lithium optimises many of the same parts of the game as Moonrise, for example the chunk system. Moonrise will automatically disable conflicting parts of Lithium. This mechanism needs to be manually validated for each Moonrise and Lithium release.</details> |
|
||||||
| FerriteCore | <details><summary>📝 requires config changes</summary>In `config/ferritecore-mixin.toml`:<br/>Set `replaceNeighborLookup` and `replacePropertyMap` to `false`</details> |
|
| FerriteCore | <details><summary>✅ compatible</summary>FerriteCore optimises some of the same parts of the game as Moonrise. Moonrise will automatically disable conflicting parts of FerriteCore. This mechanism needs to be manually validated for each Moonrise and FerriteCore release.</details> |
|
||||||
| C2ME | <details><summary>❌ incompatible</summary>C2ME is based around modifications to the chunk system, which Moonrise replaces wholesale. This makes them fundamentally incompatible.</details> |
|
| C2ME | <details><summary>❌ incompatible</summary>C2ME is based around modifications to the chunk system, which Moonrise replaces wholesale. This makes them fundamentally incompatible.</details> |
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|||||||
@@ -22,7 +22,8 @@ def getGitCommit = { ->
|
|||||||
dependencies {
|
dependencies {
|
||||||
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
|
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
|
||||||
|
|
||||||
api("ca.spottedleaf:concurrentutil:${rootProject.concurrentutil_version}")
|
api("ca.spottedleaf:concurrentutil:${rootProject.concurrentutil_version}") { setTransitive(false) }
|
||||||
|
api("ca.spottedleaf:yamlconfig:${rootProject.yamlconfig_version}") { setTransitive(false) }
|
||||||
api("org.yaml:snakeyaml:${rootProject.snakeyaml_version}")
|
api("org.yaml:snakeyaml:${rootProject.snakeyaml_version}")
|
||||||
|
|
||||||
modImplementation "me.shedaniel.cloth:cloth-config:${rootProject.cloth_version}"
|
modImplementation "me.shedaniel.cloth:cloth-config:${rootProject.cloth_version}"
|
||||||
@@ -45,9 +46,10 @@ allprojects {
|
|||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenLocal {
|
maven {
|
||||||
|
url "https://repo.papermc.io/repository/maven-public/"
|
||||||
mavenContent {
|
mavenContent {
|
||||||
includeModule("ca.spottedleaf", "concurrentutil")
|
includeGroup("ca.spottedleaf")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
maven {
|
maven {
|
||||||
|
|||||||
@@ -17,14 +17,16 @@ dependencies {
|
|||||||
runtimeOnly(project(":").sourceSets.main.output)
|
runtimeOnly(project(":").sourceSets.main.output)
|
||||||
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
|
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
|
||||||
|
|
||||||
libs("ca.spottedleaf:concurrentutil:${rootProject.concurrentutil_version}")
|
libs("ca.spottedleaf:concurrentutil:${rootProject.concurrentutil_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}"
|
modImplementation "me.shedaniel.cloth:cloth-config-fabric:${rootProject.cloth_version}"
|
||||||
include "me.shedaniel.cloth:cloth-config-fabric:${rootProject.cloth_version}"
|
include "me.shedaniel.cloth:cloth-config-fabric:${rootProject.cloth_version}"
|
||||||
modImplementation "com.terraformersmc:modmenu:11.0.1"
|
modImplementation "com.terraformersmc:modmenu:11.0.1"
|
||||||
|
|
||||||
modImplementation fabricApiLibs.fabric.api
|
modImplementation fabricApiLibs.command.api.v2
|
||||||
|
modImplementation fabricApiLibs.lifecycle.events.v1
|
||||||
include fabricApiLibs.command.api.v2
|
include fabricApiLibs.command.api.v2
|
||||||
include fabricApiLibs.base
|
include fabricApiLibs.base
|
||||||
}
|
}
|
||||||
@@ -42,6 +44,7 @@ shadowJar {
|
|||||||
destinationDirectory = layout.buildDirectory.dir("libs")
|
destinationDirectory = layout.buildDirectory.dir("libs")
|
||||||
configurations = [project.configurations.shadow]
|
configurations = [project.configurations.shadow]
|
||||||
relocate 'ca.spottedleaf.concurrentutil', 'ca.spottedleaf.moonrise.libs.ca.spottedleaf.concurrentutil'
|
relocate 'ca.spottedleaf.concurrentutil', 'ca.spottedleaf.moonrise.libs.ca.spottedleaf.concurrentutil'
|
||||||
|
relocate 'ca.spottedleaf.yamlconfig', 'ca.spottedleaf.moonrise.libs.ca.spottedleaf.yamlconfig'
|
||||||
relocate 'org.yaml.snakeyaml', 'ca.spottedleaf.moonrise.libs.org.yaml.snakeyaml'
|
relocate 'org.yaml.snakeyaml', 'ca.spottedleaf.moonrise.libs.org.yaml.snakeyaml'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +62,7 @@ publishMods {
|
|||||||
incompatible(
|
incompatible(
|
||||||
"not-enough-crashes",
|
"not-enough-crashes",
|
||||||
"starlight",
|
"starlight",
|
||||||
"c2me-fabric"
|
"c2me"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder;
|
|||||||
import net.fabricmc.fabric.api.event.Event;
|
import net.fabricmc.fabric.api.event.Event;
|
||||||
import net.fabricmc.fabric.api.event.EventFactory;
|
import net.fabricmc.fabric.api.event.EventFactory;
|
||||||
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.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.server.level.GenerationChunkHolder;
|
import net.minecraft.server.level.GenerationChunkHolder;
|
||||||
@@ -18,6 +19,7 @@ import net.minecraft.world.level.Explosion;
|
|||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
|
import net.minecraft.world.level.chunk.ImposterProtoChunk;
|
||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||||
import net.minecraft.world.level.entity.EntityTypeTest;
|
import net.minecraft.world.level.entity.EntityTypeTest;
|
||||||
@@ -28,6 +30,8 @@ import java.util.function.Predicate;
|
|||||||
|
|
||||||
public final class FabricHooks implements PlatformHooks {
|
public final class FabricHooks implements PlatformHooks {
|
||||||
|
|
||||||
|
private static final boolean HAS_FABRIC_LIFECYCLE_EVENTS = FabricLoader.getInstance().isModLoaded("fabric-lifecycle-events-v1");
|
||||||
|
|
||||||
public interface OnExplosionDetonate {
|
public interface OnExplosionDetonate {
|
||||||
void onExplosion(final Level world, final Explosion explosion, final List<Entity> possiblyAffecting, final double diameter);
|
void onExplosion(final Level world, final Explosion explosion, final List<Entity> possiblyAffecting, final double diameter);
|
||||||
}
|
}
|
||||||
@@ -85,7 +89,12 @@ public final class FabricHooks implements PlatformHooks {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void chunkFullStatusComplete(final LevelChunk newChunk, final ProtoChunk original) {
|
public void chunkFullStatusComplete(final LevelChunk newChunk, final ProtoChunk original) {
|
||||||
ServerChunkEvents.CHUNK_LOAD.invoker().onChunkLoad((ServerLevel) newChunk.getLevel(), newChunk);
|
if (HAS_FABRIC_LIFECYCLE_EVENTS) {
|
||||||
|
ServerChunkEvents.CHUNK_LOAD.invoker().onChunkLoad((ServerLevel) newChunk.getLevel(), newChunk);
|
||||||
|
if (!(original instanceof ImposterProtoChunk)) {
|
||||||
|
ServerChunkEvents.CHUNK_GENERATE.invoker().onChunkGenerate((ServerLevel)newChunk.getLevel(), newChunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -100,7 +109,9 @@ public final class FabricHooks implements PlatformHooks {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void chunkUnloadFromWorld(final LevelChunk chunk) {
|
public void chunkUnloadFromWorld(final LevelChunk chunk) {
|
||||||
ServerChunkEvents.CHUNK_UNLOAD.invoker().onChunkUnload((ServerLevel) chunk.getLevel(), chunk);
|
if (HAS_FABRIC_LIFECYCLE_EVENTS) {
|
||||||
|
ServerChunkEvents.CHUNK_UNLOAD.invoker().onChunkUnload((ServerLevel) chunk.getLevel(), chunk);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -69,6 +69,10 @@
|
|||||||
"mixin.world.explosions.cache_exposure": false,
|
"mixin.world.explosions.cache_exposure": false,
|
||||||
"mixin.world.temperature_cache": false,
|
"mixin.world.temperature_cache": false,
|
||||||
"mixin.world.tick_scheduler": false
|
"mixin.world.tick_scheduler": false
|
||||||
}
|
},
|
||||||
|
"ferritecore:disabled_options": [
|
||||||
|
"replaceNeighborLookup",
|
||||||
|
"replacePropertyMap"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,14 +6,15 @@ org.gradle.daemon=false
|
|||||||
minecraft_version=1.21.1
|
minecraft_version=1.21.1
|
||||||
supported_minecraft_versions=1.21,1.21.1
|
supported_minecraft_versions=1.21,1.21.1
|
||||||
loader_version=0.16.5
|
loader_version=0.16.5
|
||||||
neoforge_version=21.1.62
|
neoforge_version=21.1.79
|
||||||
snakeyaml_version=2.2
|
snakeyaml_version=2.3
|
||||||
concurrentutil_version=0.0.2-SNAPSHOT
|
concurrentutil_version=0.0.2
|
||||||
|
yamlconfig_version=1.0.2
|
||||||
cloth_version=15.0.128
|
cloth_version=15.0.128
|
||||||
# version ids from modrinth
|
# version ids from modrinth
|
||||||
fabric_lithium_version=mc1.21.1-0.14.0-beta.1
|
fabric_lithium_version=frXUdgvL
|
||||||
neo_lithium_version=BrMIoIMv
|
neo_lithium_version=KhdehJ6l
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
mod_version=0.1.0-SNAPSHOT
|
mod_version=0.1.0-beta.12
|
||||||
maven_group=ca.spottedleaf.moonrise
|
maven_group=ca.spottedleaf.moonrise
|
||||||
archives_base_name=moonrise
|
archives_base_name=moonrise
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -eou pipefail
|
|
||||||
|
|
||||||
git submodule update --init --recursive
|
|
||||||
cd ConcurrentUtil
|
|
||||||
mvn install
|
|
||||||
@@ -21,7 +21,8 @@ dependencies {
|
|||||||
add('shadow', project([path: ":", configuration: "namedElements"]))
|
add('shadow', project([path: ":", configuration: "namedElements"]))
|
||||||
neoForge "net.neoforged:neoforge:${rootProject.neoforge_version}"
|
neoForge "net.neoforged:neoforge:${rootProject.neoforge_version}"
|
||||||
|
|
||||||
shadow("ca.spottedleaf:concurrentutil:${rootProject.concurrentutil_version}")
|
shadow("ca.spottedleaf:concurrentutil:${rootProject.concurrentutil_version}") { setTransitive(false) }
|
||||||
|
shadow("ca.spottedleaf:yamlconfig:${rootProject.yamlconfig_version}") { setTransitive(false) }
|
||||||
shadow("org.yaml:snakeyaml:${rootProject.snakeyaml_version}")
|
shadow("org.yaml:snakeyaml:${rootProject.snakeyaml_version}")
|
||||||
forgeExtra("org.yaml:snakeyaml:${rootProject.snakeyaml_version}")
|
forgeExtra("org.yaml:snakeyaml:${rootProject.snakeyaml_version}")
|
||||||
|
|
||||||
@@ -42,6 +43,7 @@ shadowJar {
|
|||||||
destinationDirectory = layout.buildDirectory.dir("libs")
|
destinationDirectory = layout.buildDirectory.dir("libs")
|
||||||
configurations = [project.configurations.shadow]
|
configurations = [project.configurations.shadow]
|
||||||
relocate 'ca.spottedleaf.concurrentutil', 'ca.spottedleaf.moonrise.libs.ca.spottedleaf.concurrentutil'
|
relocate 'ca.spottedleaf.concurrentutil', 'ca.spottedleaf.moonrise.libs.ca.spottedleaf.concurrentutil'
|
||||||
|
relocate 'ca.spottedleaf.yamlconfig', 'ca.spottedleaf.moonrise.libs.ca.spottedleaf.yamlconfig'
|
||||||
relocate 'org.yaml.snakeyaml', 'ca.spottedleaf.moonrise.libs.org.yaml.snakeyaml'
|
relocate 'org.yaml.snakeyaml', 'ca.spottedleaf.moonrise.libs.org.yaml.snakeyaml'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,10 @@ displayURL = "https://github.com/Tuinity/Moonrise"
|
|||||||
authors = "Spottedleaf"
|
authors = "Spottedleaf"
|
||||||
description = "Optimisation mod for the dedicated and integrated server."
|
description = "Optimisation mod for the dedicated and integrated server."
|
||||||
displayTest = "IGNORE_ALL_VERSION"
|
displayTest = "IGNORE_ALL_VERSION"
|
||||||
|
"ferritecore:disabled_options" = [
|
||||||
|
"replaceNeighborLookup",
|
||||||
|
"replacePropertyMap"
|
||||||
|
]
|
||||||
|
|
||||||
[[dependencies.moonrise]]
|
[[dependencies.moonrise]]
|
||||||
modId = "neoforge"
|
modId = "neoforge"
|
||||||
@@ -51,7 +55,7 @@ config = "moonrise.mixins.json"
|
|||||||
[[mixins]]
|
[[mixins]]
|
||||||
config = "moonrise-neoforge.mixins.json"
|
config = "moonrise-neoforge.mixins.json"
|
||||||
|
|
||||||
[mods."lithium:options"]
|
["lithium:options"]
|
||||||
"mixin.ai.poi" = false
|
"mixin.ai.poi" = false
|
||||||
"mixin.alloc.chunk_ticking" = false
|
"mixin.alloc.chunk_ticking" = false
|
||||||
"mixin.alloc.deep_passengers" = false
|
"mixin.alloc.deep_passengers" = false
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ pluginManagement {
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
|
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
|
||||||
id("xyz.jpenilla.quiet-architectury-loom") version "1.7.295" apply false
|
id("xyz.jpenilla.quiet-architectury-loom") version "1.7.300" apply false
|
||||||
id 'com.gradleup.shadow' version '8.3.0' apply false
|
id 'com.gradleup.shadow' version '8.3.0' apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ dependencyResolutionManagement {
|
|||||||
}
|
}
|
||||||
versionCatalogs {
|
versionCatalogs {
|
||||||
create("fabricApiLibs") {
|
create("fabricApiLibs") {
|
||||||
from("net.fabricmc.fabric-api:fabric-api-catalog:0.103.0+1.21.1")
|
from("net.fabricmc.fabric-api:fabric-api-catalog:0.107.0+1.21.1")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -48,3 +48,6 @@ include("fabric")
|
|||||||
findProject(":fabric").name = "Moonrise-Fabric"
|
findProject(":fabric").name = "Moonrise-Fabric"
|
||||||
include("neoforge")
|
include("neoforge")
|
||||||
findProject(":neoforge").name = "Moonrise-NeoForge"
|
findProject(":neoforge").name = "Moonrise-NeoForge"
|
||||||
|
|
||||||
|
// includeBuild("../YamlConfig") // Uncomment to use local YamlConfig
|
||||||
|
// includeBuild("../ConcurrentUtil") // Uncomment to use local ConcurrentUtil
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.common.config;
|
|
||||||
|
|
||||||
public interface InitialiseHook {
|
|
||||||
|
|
||||||
public void initialise();
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.common.config.adapter;
|
|
||||||
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
|
|
||||||
public abstract class TypeAdapter<T, S> {
|
|
||||||
|
|
||||||
public abstract T deserialize(final TypeAdapterRegistry registry, final Object input, final Type type);
|
|
||||||
|
|
||||||
public abstract S serialize(final TypeAdapterRegistry registry, final T value, final Type type);
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,307 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.common.config.adapter;
|
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.config.InitialiseHook;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.collection.CollectionTypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.collection.ListTypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.collection.SortedMapTypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.primitive.BooleanTypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.primitive.ByteTypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.primitive.DoubleTypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.primitive.FloatTypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.primitive.IntegerTypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.primitive.LongTypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.primitive.ShortTypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.primitive.StringTypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.type.BigDecimalTypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.type.BigIntegerTypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.type.DurationTypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.annotation.Adaptable;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.annotation.Serializable;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.type.Duration;
|
|
||||||
import java.lang.annotation.Annotation;
|
|
||||||
import java.lang.reflect.Constructor;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.ParameterizedType;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public final class TypeAdapterRegistry {
|
|
||||||
|
|
||||||
private final Map<Class<?>, TypeAdapter<?, ?>> adapters = new HashMap<>();
|
|
||||||
{
|
|
||||||
this.adapters.put(boolean.class, BooleanTypeAdapter.INSTANCE);
|
|
||||||
this.adapters.put(byte.class, ByteTypeAdapter.INSTANCE);
|
|
||||||
this.adapters.put(short.class, ShortTypeAdapter.INSTANCE);
|
|
||||||
this.adapters.put(int.class, IntegerTypeAdapter.INSTANCE);
|
|
||||||
this.adapters.put(long.class, LongTypeAdapter.INSTANCE);
|
|
||||||
this.adapters.put(float.class, FloatTypeAdapter.INSTANCE);
|
|
||||||
this.adapters.put(double.class, DoubleTypeAdapter.INSTANCE);
|
|
||||||
|
|
||||||
this.adapters.put(Boolean.class, BooleanTypeAdapter.INSTANCE);
|
|
||||||
this.adapters.put(Byte.class, ByteTypeAdapter.INSTANCE);
|
|
||||||
this.adapters.put(Short.class, ShortTypeAdapter.INSTANCE);
|
|
||||||
this.adapters.put(Integer.class, IntegerTypeAdapter.INSTANCE);
|
|
||||||
this.adapters.put(Long.class, LongTypeAdapter.INSTANCE);
|
|
||||||
this.adapters.put(Float.class, FloatTypeAdapter.INSTANCE);
|
|
||||||
this.adapters.put(Double.class, DoubleTypeAdapter.INSTANCE);
|
|
||||||
|
|
||||||
this.adapters.put(String.class, StringTypeAdapter.INSTANCE);
|
|
||||||
|
|
||||||
this.adapters.put(Collection.class, CollectionTypeAdapter.INSTANCE);
|
|
||||||
this.adapters.put(List.class, ListTypeAdapter.INSTANCE);
|
|
||||||
this.adapters.put(Map.class, SortedMapTypeAdapter.SORTED_CASE_INSENSITIVE);
|
|
||||||
this.adapters.put(LinkedHashMap.class, SortedMapTypeAdapter.SORTED_CASE_INSENSITIVE);
|
|
||||||
|
|
||||||
this.adapters.put(BigInteger.class, BigIntegerTypeAdapter.INSTANCE);
|
|
||||||
this.adapters.put(BigDecimal.class, BigDecimalTypeAdapter.INSTANCE);
|
|
||||||
this.adapters.put(Duration.class, DurationTypeAdapter.INSTANCE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TypeAdapter<?, ?> putAdapter(final Class<?> clazz, final TypeAdapter<?, ?> adapter) {
|
|
||||||
return this.adapters.put(clazz, adapter);
|
|
||||||
}
|
|
||||||
|
|
||||||
public TypeAdapter<?, ?> getAdapter(final Class<?> clazz) {
|
|
||||||
return this.adapters.get(clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object deserialize(final Object input, final Type type) {
|
|
||||||
TypeAdapter<?, ?> adapter = null;
|
|
||||||
if (type instanceof Class<?> clazz) {
|
|
||||||
adapter = this.adapters.get(clazz);
|
|
||||||
}
|
|
||||||
if (adapter == null && (type instanceof ParameterizedType parameterizedType)) {
|
|
||||||
adapter = this.adapters.get((Class<?>)parameterizedType.getRawType());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (adapter == null) {
|
|
||||||
throw new IllegalArgumentException("No adapter for " + input.getClass() + " with type " + type);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ((TypeAdapter)adapter).deserialize(this, input, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Object serialize(final Object input, final Type type) {
|
|
||||||
TypeAdapter<?, ?> adapter = null;
|
|
||||||
if (type instanceof Class<?> clazz) {
|
|
||||||
adapter = this.adapters.get(clazz);
|
|
||||||
}
|
|
||||||
if (adapter == null && (type instanceof ParameterizedType parameterizedType)) {
|
|
||||||
adapter = this.adapters.get((Class<?>)parameterizedType.getRawType());
|
|
||||||
}
|
|
||||||
if (adapter == null) {
|
|
||||||
adapter = this.adapters.get(input.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (adapter == null) {
|
|
||||||
throw new IllegalArgumentException("No adapter for " + input.getClass() + " with type " + type);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ((TypeAdapter)adapter).serialize(this, input, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> TypeAdapter<T, Map<Object, Object>> makeAdapter(final Class<? extends T> clazz) throws Exception {
|
|
||||||
final TypeAdapter<T, Map<Object, Object>> ret = new AutoTypeAdapter<>(this, clazz);
|
|
||||||
|
|
||||||
this.putAdapter(clazz, ret);
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public <T> void callInitialisers(final T object) {
|
|
||||||
if (object == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final TypeAdapter<?, ?> adapter = this.getAdapter(object.getClass());
|
|
||||||
|
|
||||||
if (!(adapter instanceof AutoTypeAdapter<?> autoTypeAdapter)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
((AutoTypeAdapter<T>)autoTypeAdapter).callInitialisers(object);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class AutoTypeAdapter<T> extends TypeAdapter<T, Map<Object, Object>> {
|
|
||||||
|
|
||||||
private final TypeAdapterRegistry registry;
|
|
||||||
private final Constructor<? extends T> constructor;
|
|
||||||
private final SerializableField[] fields;
|
|
||||||
|
|
||||||
public AutoTypeAdapter(final TypeAdapterRegistry registry, final Class<? extends T> clazz) throws Exception {
|
|
||||||
this.registry = registry;
|
|
||||||
this.constructor = clazz.getConstructor();
|
|
||||||
this.fields = findSerializableFields(registry, clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static TypeAdapter<?, ?> findOrMakeAdapter(final TypeAdapterRegistry registry, final Class<?> clazz) throws Exception {
|
|
||||||
final TypeAdapter<?, ?> ret = registry.getAdapter(clazz);
|
|
||||||
if (ret != null) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (final Annotation annotation : clazz.getAnnotations()) {
|
|
||||||
if (annotation instanceof Adaptable adaptable) {
|
|
||||||
return registry.makeAdapter(clazz);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("No type adapter for " + clazz + " (Forgot @Adaptable?)");
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String makeSerializedKey(final String input) {
|
|
||||||
final StringBuilder ret = new StringBuilder();
|
|
||||||
|
|
||||||
for (final char c : input.toCharArray()) {
|
|
||||||
if (!Character.isUpperCase(c)) {
|
|
||||||
ret.append(c);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
ret.append('-');
|
|
||||||
ret.append(Character.toLowerCase(c));
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
private static record SerializableField(
|
|
||||||
Field field,
|
|
||||||
boolean required,
|
|
||||||
String comment,
|
|
||||||
TypeAdapter<?, ?> adapter,
|
|
||||||
boolean serialize,
|
|
||||||
String serializedKey
|
|
||||||
) {}
|
|
||||||
|
|
||||||
private static SerializableField[] findSerializableFields(final TypeAdapterRegistry registry, Class<?> clazz) throws Exception {
|
|
||||||
final List<SerializableField> ret = new ArrayList<>();
|
|
||||||
do {
|
|
||||||
for (final Field field : clazz.getDeclaredFields()) {
|
|
||||||
field.setAccessible(true);
|
|
||||||
|
|
||||||
for (final Annotation annotation : field.getAnnotations()) {
|
|
||||||
if (!(annotation instanceof Serializable serializable)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
final TypeAdapter<?, ?> adapter;
|
|
||||||
|
|
||||||
if (serializable.adapter() != TypeAdapter.class) {
|
|
||||||
adapter = serializable.adapter().getConstructor().newInstance();
|
|
||||||
} else {
|
|
||||||
adapter = findOrMakeAdapter(registry, field.getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
String serializedKey = serializable.serializedKey();
|
|
||||||
if (serializedKey.isEmpty()) {
|
|
||||||
serializedKey = makeSerializedKey(field.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
ret.add(new SerializableField(
|
|
||||||
field, serializable.required(), serializable.comment(), adapter,
|
|
||||||
serializable.serialize(), serializedKey
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} while ((clazz = clazz.getSuperclass()) != Object.class);
|
|
||||||
|
|
||||||
ret.sort((final SerializableField c1, final SerializableField c2) -> {
|
|
||||||
return c1.serializedKey.compareTo(c2.serializedKey);
|
|
||||||
});
|
|
||||||
|
|
||||||
return ret.toArray(new SerializableField[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public T deserialize(final TypeAdapterRegistry registry, final Object input, final Type type) {
|
|
||||||
if (!(input instanceof Map<?,?> inputMap)) {
|
|
||||||
throw new IllegalArgumentException("Not a map type: " + input.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
final T ret = this.constructor.newInstance();
|
|
||||||
|
|
||||||
for (final SerializableField field : this.fields) {
|
|
||||||
final Object fieldValue = inputMap.get(field.serializedKey);
|
|
||||||
|
|
||||||
if (fieldValue == null) {
|
|
||||||
if (field.required) {
|
|
||||||
throw new IllegalArgumentException("Missing required field '" + field.serializedKey + "' in " + this.constructor.getDeclaringClass());
|
|
||||||
}
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
field.field.set(ret, field.adapter.deserialize(registry, fieldValue, field.field.getGenericType()));
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
} catch (final Exception ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<Object, Object> serialize(final TypeAdapterRegistry registry, final T value, final Type type) {
|
|
||||||
final LinkedHashMap<Object, Object> ret = new LinkedHashMap<>();
|
|
||||||
|
|
||||||
for (final SerializableField field : this.fields) {
|
|
||||||
if (!field.serialize) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Object fieldValue;
|
|
||||||
try {
|
|
||||||
fieldValue = field.field.get(value);
|
|
||||||
} catch (final Exception ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fieldValue != null) {
|
|
||||||
ret.put(
|
|
||||||
field.comment.isBlank() ? field.serializedKey : new CommentedData(field.comment, field.serializedKey),
|
|
||||||
((TypeAdapter)field.adapter).serialize(
|
|
||||||
registry, fieldValue, field.field.getGenericType()
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void callInitialisers(final T value) {
|
|
||||||
for (final SerializableField field : this.fields) {
|
|
||||||
final Object fieldValue;
|
|
||||||
try {
|
|
||||||
fieldValue = field.field.get(value);
|
|
||||||
} catch (final Exception ex) {
|
|
||||||
throw new RuntimeException(ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fieldValue instanceof InitialiseHook initialiseHook) {
|
|
||||||
initialiseHook.initialise();
|
|
||||||
}
|
|
||||||
|
|
||||||
this.registry.callInitialisers(fieldValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static final class CommentedData {
|
|
||||||
|
|
||||||
public final String comment;
|
|
||||||
public final Object data;
|
|
||||||
|
|
||||||
public CommentedData(final String comment, final Object data) {
|
|
||||||
this.comment = comment;
|
|
||||||
this.data = data;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.common.config.adapter.collection;
|
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapterRegistry;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.primitive.StringTypeAdapter;
|
|
||||||
import java.lang.reflect.ParameterizedType;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public final class CollectionTypeAdapter extends TypeAdapter<Collection<Object>, List<Object>> {
|
|
||||||
|
|
||||||
public static final CollectionTypeAdapter INSTANCE = new CollectionTypeAdapter();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Collection<Object> deserialize(final TypeAdapterRegistry registry, final Object input, final Type type) {
|
|
||||||
if (!(type instanceof ParameterizedType parameterizedType)) {
|
|
||||||
throw new IllegalArgumentException("Collection field must specify generic type");
|
|
||||||
}
|
|
||||||
final Type elementType = parameterizedType.getActualTypeArguments()[0];
|
|
||||||
if (input instanceof Collection<?> collection) {
|
|
||||||
final List<Object> ret = new ArrayList<>(collection.size());
|
|
||||||
|
|
||||||
for (final Object v : collection) {
|
|
||||||
ret.add(registry.deserialize(v, elementType));
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("Not a collection type: " + input.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Object> serialize(final TypeAdapterRegistry registry, final Collection<Object> value, final Type type) {
|
|
||||||
final List<Object> ret = new ArrayList<>(value.size());
|
|
||||||
|
|
||||||
final Type elementType = type instanceof ParameterizedType parameterizedType ? parameterizedType.getActualTypeArguments()[0] : null;
|
|
||||||
|
|
||||||
for (final Object v : value) {
|
|
||||||
ret.add(registry.serialize(v, elementType == null ? v.getClass() : elementType));
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.common.config.adapter.collection;
|
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapterRegistry;
|
|
||||||
import java.lang.reflect.ParameterizedType;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
public final class ListTypeAdapter extends TypeAdapter<List<Object>, List<Object>> {
|
|
||||||
|
|
||||||
public static final ListTypeAdapter INSTANCE = new ListTypeAdapter();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Object> deserialize(final TypeAdapterRegistry registry, final Object input, final Type type) {
|
|
||||||
if (!(type instanceof ParameterizedType parameterizedType)) {
|
|
||||||
throw new IllegalArgumentException("Collection field must specify generic type");
|
|
||||||
}
|
|
||||||
final Type elementType = parameterizedType.getActualTypeArguments()[0];
|
|
||||||
if (input instanceof Collection<?> collection) {
|
|
||||||
final List<Object> ret = new ArrayList<>(collection.size());
|
|
||||||
|
|
||||||
for (final Object v : collection) {
|
|
||||||
ret.add(registry.deserialize(v, elementType));
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("Not a collection type: " + input.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<Object> serialize(final TypeAdapterRegistry registry, final List<Object> value, final Type type) {
|
|
||||||
final List<Object> ret = new ArrayList<>(value.size());
|
|
||||||
|
|
||||||
final Type elementType = type instanceof ParameterizedType parameterizedType ? parameterizedType.getActualTypeArguments()[0] : null;
|
|
||||||
|
|
||||||
for (final Object v : value) {
|
|
||||||
ret.add(registry.serialize(v, elementType));
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.common.config.adapter.collection;
|
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapterRegistry;
|
|
||||||
import java.lang.reflect.ParameterizedType;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
|
|
||||||
public final class SortedMapTypeAdapter extends TypeAdapter<Map<String, Object>, Map<String, Object>> {
|
|
||||||
|
|
||||||
public static final SortedMapTypeAdapter SORTED_CASE_INSENSITIVE = new SortedMapTypeAdapter(String.CASE_INSENSITIVE_ORDER);
|
|
||||||
public static final SortedMapTypeAdapter SORTED_CASE_SENSITIVE = new SortedMapTypeAdapter(null);
|
|
||||||
|
|
||||||
private final Comparator<String> keyComparator;
|
|
||||||
|
|
||||||
public SortedMapTypeAdapter(final Comparator<String> keyComparator) {
|
|
||||||
this.keyComparator = keyComparator;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, Object> deserialize(final TypeAdapterRegistry registry, final Object input, final Type type) {
|
|
||||||
if (!(type instanceof ParameterizedType parameterizedType)) {
|
|
||||||
throw new IllegalArgumentException("Collection field must specify generic type");
|
|
||||||
}
|
|
||||||
final Type valueType = parameterizedType.getActualTypeArguments()[1];
|
|
||||||
if (input instanceof Map<?,?> inputMap) {
|
|
||||||
final Map<String, Object> castedInput = (Map<String, Object>)inputMap;
|
|
||||||
|
|
||||||
final TreeMap<String, Object> ret = new TreeMap<>(this.keyComparator);
|
|
||||||
|
|
||||||
for (final Map.Entry<String, Object> entry : castedInput.entrySet()) {
|
|
||||||
ret.put(entry.getKey(), registry.deserialize(entry.getValue(), valueType));
|
|
||||||
}
|
|
||||||
|
|
||||||
// transform to linked so that get() is O(1)
|
|
||||||
return new LinkedHashMap<>(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("Not a map type: " + input.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, Object> serialize(final TypeAdapterRegistry registry, final Map<String, Object> value, final Type type) {
|
|
||||||
final TreeMap<String, Object> ret = new TreeMap<>(this.keyComparator);
|
|
||||||
|
|
||||||
final Type valueType = type instanceof ParameterizedType parameterizedType ? parameterizedType.getActualTypeArguments()[1] : null;
|
|
||||||
|
|
||||||
for (final Map.Entry<String, Object> entry : value.entrySet()) {
|
|
||||||
ret.put(entry.getKey(), registry.serialize(entry.getValue(), valueType));
|
|
||||||
}
|
|
||||||
|
|
||||||
// transform to linked so that get() is O(1)
|
|
||||||
return new LinkedHashMap<>(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.common.config.adapter.collection;
|
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapterRegistry;
|
|
||||||
import java.lang.reflect.ParameterizedType;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.util.LinkedHashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public final class UnsortedMapTypeAdapter extends TypeAdapter<Map<String, Object>, Map<String, Object>> {
|
|
||||||
|
|
||||||
public static final UnsortedMapTypeAdapter INSTANCE = new UnsortedMapTypeAdapter();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, Object> deserialize(final TypeAdapterRegistry registry, final Object input, final Type type) {
|
|
||||||
if (!(type instanceof ParameterizedType parameterizedType)) {
|
|
||||||
throw new IllegalArgumentException("Collection field must specify generic type");
|
|
||||||
}
|
|
||||||
final Type valueType = parameterizedType.getActualTypeArguments()[1];
|
|
||||||
if (input instanceof Map<?,?> inputMap) {
|
|
||||||
final Map<String, Object> castedInput = (Map<String, Object>)inputMap;
|
|
||||||
|
|
||||||
final LinkedHashMap<String, Object> ret = new LinkedHashMap<>();
|
|
||||||
|
|
||||||
for (final Map.Entry<String, Object> entry : castedInput.entrySet()) {
|
|
||||||
ret.put(entry.getKey(), registry.deserialize(entry.getValue(), valueType));
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("Not a map type: " + input.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Map<String, Object> serialize(final TypeAdapterRegistry registry, final Map<String, Object> value, final Type type) {
|
|
||||||
final LinkedHashMap<String, Object> ret = new LinkedHashMap<>();
|
|
||||||
|
|
||||||
final Type valueType = type instanceof ParameterizedType parameterizedType ? parameterizedType.getActualTypeArguments()[1] : null;
|
|
||||||
|
|
||||||
for (final Map.Entry<String, Object> entry : value.entrySet()) {
|
|
||||||
ret.put(entry.getKey(), registry.serialize(entry.getValue(), valueType));
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.common.config.adapter.primitive;
|
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapterRegistry;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
|
|
||||||
public final class BooleanTypeAdapter extends TypeAdapter<Boolean, Boolean> {
|
|
||||||
|
|
||||||
public static final BooleanTypeAdapter INSTANCE = new BooleanTypeAdapter();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean deserialize(final TypeAdapterRegistry registry, final Object input, final Type type) {
|
|
||||||
if (input instanceof Boolean ret) {
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
if (input instanceof String str) {
|
|
||||||
if (str.equalsIgnoreCase("false")) {
|
|
||||||
return Boolean.FALSE;
|
|
||||||
}
|
|
||||||
if (str.equalsIgnoreCase("true")) {
|
|
||||||
return Boolean.TRUE;
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("Not a boolean: " + str);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("Not a boolean type: " + input.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Boolean serialize(final TypeAdapterRegistry registry, final Boolean value, final Type type) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.common.config.adapter.primitive;
|
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapterRegistry;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
public final class ByteTypeAdapter extends TypeAdapter<Byte, Byte> {
|
|
||||||
|
|
||||||
public static final ByteTypeAdapter INSTANCE = new ByteTypeAdapter();
|
|
||||||
|
|
||||||
private static Byte cast(final Object original, final long value) {
|
|
||||||
if (value < (long)Byte.MIN_VALUE || value > (long)Byte.MAX_VALUE) {
|
|
||||||
throw new IllegalArgumentException("Byte value is out of range: " + original.toString());
|
|
||||||
}
|
|
||||||
return Byte.valueOf((byte)value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Byte deserialize(final TypeAdapterRegistry registry, final Object input, final Type type) {
|
|
||||||
if (input instanceof Number number) {
|
|
||||||
// note: silently discard floating point significand
|
|
||||||
return cast(input, number instanceof BigInteger bigInteger ? bigInteger.longValueExact() : number.longValue());
|
|
||||||
}
|
|
||||||
if (input instanceof String string) {
|
|
||||||
return cast(input, (long)Double.parseDouble(string));
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("Not a byte type: " + input.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Byte serialize(final TypeAdapterRegistry registry, final Byte value, final Type type) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.common.config.adapter.primitive;
|
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapterRegistry;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
|
|
||||||
public final class DoubleTypeAdapter extends TypeAdapter<Double, Double> {
|
|
||||||
|
|
||||||
public static final DoubleTypeAdapter INSTANCE = new DoubleTypeAdapter();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Double deserialize(final TypeAdapterRegistry registry, final Object input, final Type type) {
|
|
||||||
if (input instanceof Number number) {
|
|
||||||
return Double.valueOf(number.doubleValue());
|
|
||||||
}
|
|
||||||
if (input instanceof String string) {
|
|
||||||
return Double.valueOf(Double.parseDouble(string));
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("Not a byte type: " + input.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Double serialize(final TypeAdapterRegistry registry, final Double value, final Type type) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.common.config.adapter.primitive;
|
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapterRegistry;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
|
|
||||||
public final class FloatTypeAdapter extends TypeAdapter<Float, Float> {
|
|
||||||
|
|
||||||
public static final FloatTypeAdapter INSTANCE = new FloatTypeAdapter();
|
|
||||||
|
|
||||||
private static Float cast(final Object original, final double value) {
|
|
||||||
if (value < -(double)Float.MAX_VALUE || value > (double)Float.MAX_VALUE) {
|
|
||||||
throw new IllegalArgumentException("Byte value is out of range: " + original.toString());
|
|
||||||
}
|
|
||||||
// note: silently ignore precision loss
|
|
||||||
return Float.valueOf((float)value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Float deserialize(final TypeAdapterRegistry registry, final Object input, final Type type) {
|
|
||||||
if (input instanceof Number number) {
|
|
||||||
return cast(input, number.doubleValue());
|
|
||||||
}
|
|
||||||
if (input instanceof String string) {
|
|
||||||
return cast(input, Double.parseDouble(string));
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("Not a byte type: " + input.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Float serialize(final TypeAdapterRegistry registry, final Float value, final Type type) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.common.config.adapter.primitive;
|
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapterRegistry;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
public final class IntegerTypeAdapter extends TypeAdapter<Integer, Integer> {
|
|
||||||
|
|
||||||
public static final IntegerTypeAdapter INSTANCE = new IntegerTypeAdapter();
|
|
||||||
|
|
||||||
private static Integer cast(final Object original, final long value) {
|
|
||||||
if (value < (long)Integer.MIN_VALUE || value > (long)Integer.MAX_VALUE) {
|
|
||||||
throw new IllegalArgumentException("Integer value is out of range: " + original.toString());
|
|
||||||
}
|
|
||||||
return Integer.valueOf((int)value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Integer deserialize(final TypeAdapterRegistry registry, final Object input, final Type type) {
|
|
||||||
if (input instanceof Number number) {
|
|
||||||
// note: silently discard floating point significand
|
|
||||||
return cast(input, number instanceof BigInteger bigInteger ? bigInteger.longValueExact() : number.longValue());
|
|
||||||
}
|
|
||||||
if (input instanceof String string) {
|
|
||||||
return cast(input, (long)Double.parseDouble(string));
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("Not an integer type: " + input.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Integer serialize(final TypeAdapterRegistry registry, final Integer value, final Type type) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.common.config.adapter.primitive;
|
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapterRegistry;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
public final class LongTypeAdapter extends TypeAdapter<Long, Long> {
|
|
||||||
|
|
||||||
public static final LongTypeAdapter INSTANCE = new LongTypeAdapter();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Long deserialize(final TypeAdapterRegistry registry, final Object input, final Type type) {
|
|
||||||
if (input instanceof Number number) {
|
|
||||||
// note: silently discard floating point significand
|
|
||||||
return number instanceof BigInteger bigInteger ? bigInteger.longValueExact() : number.longValue();
|
|
||||||
}
|
|
||||||
if (input instanceof String string) {
|
|
||||||
try {
|
|
||||||
return Long.valueOf(Long.parseLong(string));
|
|
||||||
} catch (final NumberFormatException ex) {
|
|
||||||
return Long.valueOf((long)Double.parseDouble(string));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("Not a long type: " + input.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Long serialize(final TypeAdapterRegistry registry, final Long value, final Type type) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.common.config.adapter.primitive;
|
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapterRegistry;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
public final class ShortTypeAdapter extends TypeAdapter<Short, Short> {
|
|
||||||
|
|
||||||
public static final ShortTypeAdapter INSTANCE = new ShortTypeAdapter();
|
|
||||||
|
|
||||||
private static Short cast(final Object original, final long value) {
|
|
||||||
if (value < (long)Short.MIN_VALUE || value > (long)Short.MAX_VALUE) {
|
|
||||||
throw new IllegalArgumentException("Short value is out of range: " + original.toString());
|
|
||||||
}
|
|
||||||
return Short.valueOf((short)value);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Short deserialize(final TypeAdapterRegistry registry, final Object input, final Type type) {
|
|
||||||
if (input instanceof Number number) {
|
|
||||||
// note: silently discard floating point significand
|
|
||||||
return cast(input, number instanceof BigInteger bigInteger ? bigInteger.longValueExact() : number.longValue());
|
|
||||||
}
|
|
||||||
if (input instanceof String string) {
|
|
||||||
return cast(input, (long)Double.parseDouble(string));
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("Not a short type: " + input.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Short serialize(final TypeAdapterRegistry registry, final Short value, final Type type) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.common.config.adapter.primitive;
|
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapterRegistry;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
|
|
||||||
public final class StringTypeAdapter extends TypeAdapter<String, String> {
|
|
||||||
|
|
||||||
public static final StringTypeAdapter INSTANCE = new StringTypeAdapter();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String deserialize(final TypeAdapterRegistry registry, final Object input, final Type type) {
|
|
||||||
if (input instanceof Boolean bool) {
|
|
||||||
return String.valueOf(bool.booleanValue());
|
|
||||||
}
|
|
||||||
if (input instanceof Number number) {
|
|
||||||
return number.toString();
|
|
||||||
}
|
|
||||||
if (input instanceof String string) {
|
|
||||||
return string;
|
|
||||||
}
|
|
||||||
throw new IllegalArgumentException("Not a string type: " + input.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String serialize(final TypeAdapterRegistry registry, final String value, final Type type) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.common.config.adapter.type;
|
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapterRegistry;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
public final class BigDecimalTypeAdapter extends TypeAdapter<BigDecimal, String> {
|
|
||||||
|
|
||||||
public static final BigDecimalTypeAdapter INSTANCE = new BigDecimalTypeAdapter();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BigDecimal deserialize(final TypeAdapterRegistry registry, final Object input, final Type type) {
|
|
||||||
if (input instanceof Number number) {
|
|
||||||
// safest to catch all number impls is to use toString
|
|
||||||
return new BigDecimal(number.toString());
|
|
||||||
}
|
|
||||||
if (input instanceof String string) {
|
|
||||||
return new BigDecimal(string);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("Not an BigDecimal type: " + input.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String serialize(final TypeAdapterRegistry registry, final BigDecimal value, final Type type) {
|
|
||||||
return value.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.common.config.adapter.type;
|
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapterRegistry;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
|
|
||||||
public final class BigIntegerTypeAdapter extends TypeAdapter<BigInteger, String> {
|
|
||||||
|
|
||||||
public static final BigIntegerTypeAdapter INSTANCE = new BigIntegerTypeAdapter();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public BigInteger deserialize(final TypeAdapterRegistry registry, final Object input, final Type type) {
|
|
||||||
if (input instanceof Number number) {
|
|
||||||
if (number instanceof BigInteger bigInteger) {
|
|
||||||
return bigInteger;
|
|
||||||
}
|
|
||||||
// note: silently discard floating point significand
|
|
||||||
if (number instanceof BigDecimal bigDecimal) {
|
|
||||||
return bigDecimal.toBigInteger();
|
|
||||||
}
|
|
||||||
|
|
||||||
return BigInteger.valueOf(number.longValue());
|
|
||||||
}
|
|
||||||
if (input instanceof String string) {
|
|
||||||
return new BigDecimal(string).toBigInteger();
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new IllegalArgumentException("Not an BigInteger type: " + input.getClass());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String serialize(final TypeAdapterRegistry registry, final BigInteger value, final Type type) {
|
|
||||||
return value.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.common.config.adapter.type;
|
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapterRegistry;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.type.Duration;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
|
|
||||||
public final class DurationTypeAdapter extends TypeAdapter<Duration, String> {
|
|
||||||
|
|
||||||
public static final DurationTypeAdapter INSTANCE = new DurationTypeAdapter();
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Duration deserialize(final TypeAdapterRegistry registry, final Object input, final Type type) {
|
|
||||||
if (!(input instanceof String string)) {
|
|
||||||
throw new IllegalArgumentException("Not a string: " + input.getClass());
|
|
||||||
}
|
|
||||||
return Duration.parse(string);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String serialize(final TypeAdapterRegistry registry, final Duration value, final Type type) {
|
|
||||||
return value.toString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.common.config.annotation;
|
|
||||||
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Annotation used on a class to indicate that its type adapter may automatically be generated. The class must have
|
|
||||||
* a public no-args constructor.
|
|
||||||
*/
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Target(ElementType.TYPE)
|
|
||||||
public @interface Adaptable {
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.common.config.annotation;
|
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapter;
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Annotation indicating that a field should be deserialized or serialized from the config.
|
|
||||||
* By default, this annotation is not assumed.
|
|
||||||
*/
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@Target(ElementType.FIELD)
|
|
||||||
public @interface Serializable {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Indicates whether this field is required to be present in the config. If the field is not present,
|
|
||||||
* and {@code required = true}, then an exception will be thrown during deserialization. If {@code required = false}
|
|
||||||
* and the field is not present, then the field value will remain unmodified.
|
|
||||||
*/
|
|
||||||
public boolean required() default false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The comment to apply before the element when serializing.
|
|
||||||
*/
|
|
||||||
public String comment() default "";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adapter override class. The class must have a public no-args constructor.
|
|
||||||
*/
|
|
||||||
public Class<? extends TypeAdapter> adapter() default TypeAdapter.class;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether to serialize the value to the config.
|
|
||||||
*/
|
|
||||||
public boolean serialize() default true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* When not empty, this value overrides the auto generated serialized key in the config.
|
|
||||||
*/
|
|
||||||
public String serializedKey() default "";
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,178 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.common.config.config;
|
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapterRegistry;
|
|
||||||
import org.yaml.snakeyaml.DumperOptions;
|
|
||||||
import org.yaml.snakeyaml.LoaderOptions;
|
|
||||||
import org.yaml.snakeyaml.Yaml;
|
|
||||||
import org.yaml.snakeyaml.comments.CommentLine;
|
|
||||||
import org.yaml.snakeyaml.comments.CommentType;
|
|
||||||
import org.yaml.snakeyaml.constructor.Constructor;
|
|
||||||
import org.yaml.snakeyaml.nodes.Node;
|
|
||||||
import org.yaml.snakeyaml.representer.Represent;
|
|
||||||
import org.yaml.snakeyaml.representer.Representer;
|
|
||||||
import java.io.BufferedInputStream;
|
|
||||||
import java.io.BufferedOutputStream;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.StringReader;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.nio.file.AtomicMoveNotSupportedException;
|
|
||||||
import java.nio.file.Files;
|
|
||||||
import java.nio.file.StandardCopyOption;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.TreeMap;
|
|
||||||
|
|
||||||
public final class YamlConfig<T> {
|
|
||||||
|
|
||||||
public final TypeAdapterRegistry typeAdapters;
|
|
||||||
|
|
||||||
private final Class<? extends T> clazz;
|
|
||||||
|
|
||||||
public volatile T config;
|
|
||||||
|
|
||||||
private final Yaml yaml;
|
|
||||||
private final LoaderOptions loaderOptions;
|
|
||||||
private final DumperOptions dumperOptions;
|
|
||||||
|
|
||||||
public YamlConfig(final Class<? extends T> clazz, final T dfl) throws Exception {
|
|
||||||
this(clazz, dfl, new TypeAdapterRegistry());
|
|
||||||
}
|
|
||||||
|
|
||||||
public YamlConfig(final Class<? extends T> clazz, final T dfl, final TypeAdapterRegistry registry) throws Exception {
|
|
||||||
this.clazz = clazz;
|
|
||||||
this.config = dfl;
|
|
||||||
this.typeAdapters = registry;
|
|
||||||
this.typeAdapters.makeAdapter(clazz);
|
|
||||||
|
|
||||||
final LoaderOptions loaderOptions = new LoaderOptions();
|
|
||||||
loaderOptions.setProcessComments(true);
|
|
||||||
|
|
||||||
final DumperOptions dumperOptions = new DumperOptions();
|
|
||||||
dumperOptions.setProcessComments(true);
|
|
||||||
dumperOptions.setDefaultFlowStyle(DumperOptions.FlowStyle.BLOCK);
|
|
||||||
|
|
||||||
this.loaderOptions = loaderOptions;
|
|
||||||
this.dumperOptions = dumperOptions;
|
|
||||||
this.yaml = new Yaml(new YamlConstructor(loaderOptions), new YamlRepresenter(dumperOptions), dumperOptions, loaderOptions);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void load(final File file) throws IOException {
|
|
||||||
try (final InputStream is = new BufferedInputStream(new FileInputStream(file))) {
|
|
||||||
this.load(is);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void load(final InputStream is) throws IOException {
|
|
||||||
final Object serialized = this.yaml.load(new InputStreamReader(is, StandardCharsets.UTF_8));
|
|
||||||
|
|
||||||
this.config = (T)this.typeAdapters.deserialize(serialized, this.clazz);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void save(final File file) throws IOException {
|
|
||||||
this.save(file, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void save(final File file, final String header) throws IOException {
|
|
||||||
if (file.isDirectory()) {
|
|
||||||
throw new IOException("File is a directory");
|
|
||||||
}
|
|
||||||
|
|
||||||
final File parent = file.getParentFile();
|
|
||||||
if (parent != null) {
|
|
||||||
parent.mkdirs();
|
|
||||||
}
|
|
||||||
|
|
||||||
final File tmp = new File(parent, file.getName() + ".tmp");
|
|
||||||
tmp.delete();
|
|
||||||
tmp.createNewFile();
|
|
||||||
try {
|
|
||||||
try (final OutputStream os = new BufferedOutputStream(new FileOutputStream(tmp))) {
|
|
||||||
this.save(os, header);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
Files.move(tmp.toPath(), file.toPath(), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE);
|
|
||||||
} catch (final AtomicMoveNotSupportedException ex) {
|
|
||||||
Files.move(tmp.toPath(), file.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
tmp.delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void save(final OutputStream os) throws IOException {
|
|
||||||
os.write(this.saveToString().getBytes(StandardCharsets.UTF_8));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void save(final OutputStream os, final String header) throws IOException {
|
|
||||||
os.write(this.saveToString(header).getBytes(StandardCharsets.UTF_8));
|
|
||||||
}
|
|
||||||
|
|
||||||
public String saveToString() {
|
|
||||||
return this.yaml.dump(this.typeAdapters.serialize(this.config, this.clazz));
|
|
||||||
}
|
|
||||||
|
|
||||||
public String saveToString(final String header) {
|
|
||||||
if (header.isBlank()) {
|
|
||||||
return this.saveToString();
|
|
||||||
}
|
|
||||||
|
|
||||||
final StringBuilder ret = new StringBuilder();
|
|
||||||
final String lineBreak = this.dumperOptions.getLineBreak().getString();
|
|
||||||
|
|
||||||
for (final String line : header.split("\n")) {
|
|
||||||
ret.append("# ").append(line.trim()).append(lineBreak);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret.append(lineBreak);
|
|
||||||
|
|
||||||
return ret.append(this.saveToString()).toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void callInitialisers() {
|
|
||||||
this.typeAdapters.callInitialisers(this.config);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class YamlConstructor extends Constructor {
|
|
||||||
|
|
||||||
public YamlConstructor(final LoaderOptions loadingConfig) {
|
|
||||||
super(loadingConfig);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final class YamlRepresenter extends Representer {
|
|
||||||
|
|
||||||
public YamlRepresenter(final DumperOptions options) {
|
|
||||||
super(options);
|
|
||||||
|
|
||||||
this.representers.put(TypeAdapterRegistry.CommentedData.class, new CommentedDataRepresenter());
|
|
||||||
}
|
|
||||||
|
|
||||||
private final class CommentedDataRepresenter implements Represent {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Node representData(final Object data0) {
|
|
||||||
final TypeAdapterRegistry.CommentedData commentedData = (TypeAdapterRegistry.CommentedData)data0;
|
|
||||||
|
|
||||||
final Node node = YamlRepresenter.this.representData(commentedData.data);
|
|
||||||
|
|
||||||
final List<CommentLine> comments = new ArrayList<>();
|
|
||||||
|
|
||||||
for (final String line : commentedData.comment.split("\n")) {
|
|
||||||
comments.add(new CommentLine(null, null, " ".concat(line.trim()), CommentType.BLOCK));
|
|
||||||
}
|
|
||||||
|
|
||||||
node.setBlockComments(comments);
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +1,12 @@
|
|||||||
package ca.spottedleaf.moonrise.common.config.moonrise;
|
package ca.spottedleaf.moonrise.common.config.moonrise;
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.config.InitialiseHook;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.annotation.Adaptable;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.ui.ClothConfig;
|
import ca.spottedleaf.moonrise.common.config.ui.ClothConfig;
|
||||||
import ca.spottedleaf.moonrise.common.config.annotation.Serializable;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.type.Duration;
|
|
||||||
import ca.spottedleaf.moonrise.common.util.MoonriseCommon;
|
import ca.spottedleaf.moonrise.common.util.MoonriseCommon;
|
||||||
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.annotation.Adaptable;
|
||||||
|
import ca.spottedleaf.yamlconfig.annotation.Serializable;
|
||||||
|
import ca.spottedleaf.yamlconfig.type.Duration;
|
||||||
|
|
||||||
@Adaptable
|
@Adaptable
|
||||||
public final class MoonriseConfig {
|
public final class MoonriseConfig {
|
||||||
@@ -251,4 +251,21 @@ public final class MoonriseConfig {
|
|||||||
)
|
)
|
||||||
public boolean fixMC159283 = false;
|
public boolean fixMC159283 = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
public Misc misc = new Misc();
|
||||||
|
|
||||||
|
@Adaptable
|
||||||
|
public static final class Misc {
|
||||||
|
|
||||||
|
@Serializable(
|
||||||
|
serializedKey = "immediately-close-loading-screen",
|
||||||
|
comment = """
|
||||||
|
Whether the loading screen should be closed immediately when joining servers/SP worlds.
|
||||||
|
This will let you in game faster, but may result in getting in game before enough chunks are
|
||||||
|
loaded for rendering.
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
public boolean immediatelyCloseLoadingScreen = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,38 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.common.config.moonrise.adapter;
|
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapter;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapterRegistry;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.moonrise.type.DefaultedValue;
|
|
||||||
import java.lang.reflect.ParameterizedType;
|
|
||||||
import java.lang.reflect.Type;
|
|
||||||
|
|
||||||
public final class DefaultedTypeAdapter extends TypeAdapter<DefaultedValue<?>, Object> {
|
|
||||||
|
|
||||||
private static final String DEFAULT_STRING = "default";
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DefaultedValue<?> deserialize(final TypeAdapterRegistry registry, final Object input, final Type type) {
|
|
||||||
if (input instanceof String string && string.equalsIgnoreCase(DEFAULT_STRING)) {
|
|
||||||
return new DefaultedValue<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(type instanceof ParameterizedType parameterizedType)) {
|
|
||||||
throw new IllegalArgumentException("DefaultedValue field must specify generic type");
|
|
||||||
}
|
|
||||||
final Type valueType = parameterizedType.getActualTypeArguments()[0];
|
|
||||||
|
|
||||||
return new DefaultedValue<>(registry.deserialize(input, valueType));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Object serialize(final TypeAdapterRegistry registry, final DefaultedValue<?> value, final Type type) {
|
|
||||||
final Object raw = value.getValueRaw();
|
|
||||||
if (raw == null) {
|
|
||||||
return DEFAULT_STRING;
|
|
||||||
}
|
|
||||||
|
|
||||||
final Type valueType = type instanceof ParameterizedType parameterizedType ? parameterizedType.getActualTypeArguments()[0] : null;
|
|
||||||
|
|
||||||
return registry.serialize(raw, valueType);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,22 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.common.config.moonrise.type;
|
|
||||||
|
|
||||||
public final class DefaultedValue<T> {
|
|
||||||
|
|
||||||
private final T value;
|
|
||||||
|
|
||||||
public DefaultedValue() {
|
|
||||||
this(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DefaultedValue(final T value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T getValueRaw() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
public T getOrDefault(final T dfl) {
|
|
||||||
return this.value != null ? this.value : dfl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,76 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.common.config.type;
|
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
|
||||||
|
|
||||||
public final class Duration {
|
|
||||||
|
|
||||||
private final String string;
|
|
||||||
private final long timeNS;
|
|
||||||
|
|
||||||
private Duration(final String string, final long timeNS) {
|
|
||||||
this.string = string;
|
|
||||||
this.timeNS = timeNS;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Duration parse(final String value) {
|
|
||||||
if (value.length() < 2) {
|
|
||||||
throw new IllegalArgumentException("Invalid duration: " + value);
|
|
||||||
}
|
|
||||||
|
|
||||||
final char last = value.charAt(value.length() - 1);
|
|
||||||
|
|
||||||
final long multiplier;
|
|
||||||
|
|
||||||
switch (last) {
|
|
||||||
case 's': {
|
|
||||||
multiplier = (1000L * 1000L * 1000L) * 1L;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 't': {
|
|
||||||
multiplier = (1000L * 1000L * 1000L) / 20L;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'm': {
|
|
||||||
multiplier = (1000L * 1000L * 1000L) * 60L;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'h': {
|
|
||||||
multiplier = (1000L * 1000L * 1000L) * 60L * 60L;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'd': {
|
|
||||||
multiplier = (1000L * 1000L * 1000L) * 24L * 60L * 60L;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
throw new IllegalArgumentException("Duration must end with one of: [s, t, m, h, d]");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final BigDecimal parsed = new BigDecimal(value.substring(0, value.length() - 1))
|
|
||||||
.multiply(new BigDecimal(multiplier));
|
|
||||||
|
|
||||||
return new Duration(value, parsed.toBigInteger().longValueExact());
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTimeNS() {
|
|
||||||
return this.timeNS;
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTimeMS() {
|
|
||||||
return this.timeNS / (1000L * 1000L);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTimeS() {
|
|
||||||
return this.timeNS / (1000L * 1000L * 1000L);
|
|
||||||
}
|
|
||||||
|
|
||||||
public long getTimeTicks() {
|
|
||||||
return this.timeNS / ((1000L * 1000L * 1000L) / (20L));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return this.string;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -122,7 +122,7 @@ public final class NearbyPlayers {
|
|||||||
players[NearbyMapType.GENERAL_SMALL.ordinal()].update(chunk.x, chunk.z, GENERAL_SMALL_VIEW_DISTANCE);
|
players[NearbyMapType.GENERAL_SMALL.ordinal()].update(chunk.x, chunk.z, GENERAL_SMALL_VIEW_DISTANCE);
|
||||||
players[NearbyMapType.GENERAL_REALLY_SMALL.ordinal()].update(chunk.x, chunk.z, GENERAL_REALLY_SMALL_VIEW_DISTANCE);
|
players[NearbyMapType.GENERAL_REALLY_SMALL.ordinal()].update(chunk.x, chunk.z, GENERAL_REALLY_SMALL_VIEW_DISTANCE);
|
||||||
players[NearbyMapType.TICK_VIEW_DISTANCE.ordinal()].update(chunk.x, chunk.z, ChunkSystem.getTickViewDistance(player));
|
players[NearbyMapType.TICK_VIEW_DISTANCE.ordinal()].update(chunk.x, chunk.z, ChunkSystem.getTickViewDistance(player));
|
||||||
players[NearbyMapType.VIEW_DISTANCE.ordinal()].update(chunk.x, chunk.z, ChunkSystem.getLoadViewDistance(player));
|
players[NearbyMapType.VIEW_DISTANCE.ordinal()].update(chunk.x, chunk.z, ChunkSystem.getViewDistance(player));
|
||||||
players[NearbyMapType.SPAWN_RANGE.ordinal()].update(chunk.x, chunk.z, ChunkTickConstants.PLAYER_SPAWN_TRACK_RANGE); // Moonrise - chunk tick iteration
|
players[NearbyMapType.SPAWN_RANGE.ordinal()].update(chunk.x, chunk.z, ChunkTickConstants.PLAYER_SPAWN_TRACK_RANGE); // Moonrise - chunk tick iteration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -152,8 +152,8 @@ public final class ChunkSystem {
|
|||||||
return RegionizedPlayerChunkLoader.getAPISendViewDistance(player);
|
return RegionizedPlayerChunkLoader.getAPISendViewDistance(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getLoadViewDistance(final ServerPlayer player) {
|
public static int getViewDistance(final ServerPlayer player) {
|
||||||
return RegionizedPlayerChunkLoader.getLoadViewDistance(player);
|
return RegionizedPlayerChunkLoader.getAPIViewDistance(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getTickViewDistance(final ServerPlayer player) {
|
public static int getTickViewDistance(final ServerPlayer player) {
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
package ca.spottedleaf.moonrise.common.util;
|
package ca.spottedleaf.moonrise.common.util;
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.config.adapter.TypeAdapterRegistry;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.config.YamlConfig;
|
|
||||||
import ca.spottedleaf.moonrise.common.config.moonrise.MoonriseConfig;
|
import ca.spottedleaf.moonrise.common.config.moonrise.MoonriseConfig;
|
||||||
import ca.spottedleaf.moonrise.common.config.moonrise.adapter.DefaultedTypeAdapter;
|
import ca.spottedleaf.yamlconfig.adapter.TypeAdapterRegistry;
|
||||||
import ca.spottedleaf.moonrise.common.config.moonrise.type.DefaultedValue;
|
import ca.spottedleaf.yamlconfig.config.YamlConfig;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -17,8 +15,6 @@ public final class ConfigHolder {
|
|||||||
private static final TypeAdapterRegistry CONFIG_ADAPTERS = new TypeAdapterRegistry();
|
private static final TypeAdapterRegistry CONFIG_ADAPTERS = new TypeAdapterRegistry();
|
||||||
private static final YamlConfig<MoonriseConfig> CONFIG;
|
private static final YamlConfig<MoonriseConfig> CONFIG;
|
||||||
static {
|
static {
|
||||||
CONFIG_ADAPTERS.putAdapter(DefaultedValue.class, new DefaultedTypeAdapter());
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
CONFIG = new YamlConfig<>(MoonriseConfig.class, new MoonriseConfig(), CONFIG_ADAPTERS);
|
CONFIG = new YamlConfig<>(MoonriseConfig.class, new MoonriseConfig(), CONFIG_ADAPTERS);
|
||||||
} catch (final Exception ex) {
|
} catch (final Exception ex) {
|
||||||
@@ -51,14 +47,6 @@ public final class ConfigHolder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static boolean reloadConfig() {
|
public static boolean reloadConfig() {
|
||||||
final boolean ret = reloadConfig0();
|
|
||||||
|
|
||||||
CONFIG.callInitialisers();
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static boolean reloadConfig0() {
|
|
||||||
synchronized (CONFIG) {
|
synchronized (CONFIG) {
|
||||||
if (CONFIG_FILE.exists()) {
|
if (CONFIG_FILE.exists()) {
|
||||||
try {
|
try {
|
||||||
@@ -69,6 +57,8 @@ public final class ConfigHolder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CONFIG.callInitialisers();
|
||||||
|
|
||||||
// write back any changes, or create if needed
|
// write back any changes, or create if needed
|
||||||
return saveConfig();
|
return saveConfig();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package ca.spottedleaf.moonrise.mixin.chunk_system;
|
package ca.spottedleaf.moonrise.mixin.chunk_system;
|
||||||
|
|
||||||
|
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;
|
||||||
@@ -13,6 +14,7 @@ import net.minecraft.server.level.DistanceManager;
|
|||||||
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 net.minecraft.server.level.TickingTracker;
|
import net.minecraft.server.level.TickingTracker;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
import net.minecraft.util.SortedArraySet;
|
import net.minecraft.util.SortedArraySet;
|
||||||
import net.minecraft.util.thread.ProcessorHandle;
|
import net.minecraft.util.thread.ProcessorHandle;
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
@@ -296,7 +298,10 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
|
|||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public void updateSimulationDistance(final int simulationDistance) {
|
public void updateSimulationDistance(final int simulationDistance) {
|
||||||
((ChunkSystemServerLevel)this.moonrise$getChunkMap().level).moonrise$getPlayerChunkLoader().setTickDistance(simulationDistance);
|
// note: vanilla does not clamp to 0, but we do simply because we need a min of 0
|
||||||
|
final int clamped = Mth.clamp(simulationDistance, 0, MoonriseConstants.MAX_VIEW_DISTANCE);
|
||||||
|
|
||||||
|
((ChunkSystemServerLevel)this.moonrise$getChunkMap().level).moonrise$getPlayerChunkLoader().setTickDistance(clamped);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -43,4 +43,17 @@ abstract class PlayerListMixin {
|
|||||||
)
|
)
|
||||||
private void doNotAdjustVD(final PlayerList instance, final Packet<?> packet) {}
|
private void doNotAdjustVD(final PlayerList instance, final Packet<?> packet) {}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason The RegionizedPlayerChunkLoader will handle the SD packet
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Redirect(
|
||||||
|
method = "setSimulationDistance",
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "Lnet/minecraft/server/players/PlayerList;broadcastAll(Lnet/minecraft/network/protocol/Packet;)V"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private void doNotAdjustSD(final PlayerList instance, final Packet<?> packet) {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,6 +81,13 @@ abstract class ServerChunkCacheMixin extends ChunkSource implements ChunkSystemS
|
|||||||
completable::complete
|
completable::complete
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!completable.isDone() && chunkTaskScheduler.hasShutdown()) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Chunk system has shut down, cannot process chunk requests in world '" + ca.spottedleaf.moonrise.common.util.WorldUtil.getWorldName(this.level) + "' at "
|
||||||
|
+ "(" + chunkX + "," + chunkZ + ") status: " + toStatus
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (TickThread.isTickThreadFor(this.level, chunkX, chunkZ)) {
|
if (TickThread.isTickThreadFor(this.level, chunkX, chunkZ)) {
|
||||||
ChunkTaskScheduler.pushChunkWait(this.level, chunkX, chunkZ);
|
ChunkTaskScheduler.pushChunkWait(this.level, chunkX, chunkZ);
|
||||||
this.mainThreadProcessor.managedBlock(completable::isDone);
|
this.mainThreadProcessor.managedBlock(completable::isDone);
|
||||||
|
|||||||
@@ -5,16 +5,12 @@ import ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape;
|
|||||||
import com.mojang.serialization.MapCodec;
|
import com.mojang.serialization.MapCodec;
|
||||||
import it.unimi.dsi.fastutil.HashCommon;
|
import it.unimi.dsi.fastutil.HashCommon;
|
||||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap;
|
import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap;
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.world.level.BlockGetter;
|
|
||||||
import net.minecraft.world.level.block.Block;
|
import net.minecraft.world.level.block.Block;
|
||||||
import net.minecraft.world.level.block.state.BlockBehaviour;
|
import net.minecraft.world.level.block.state.BlockBehaviour;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.block.state.StateHolder;
|
import net.minecraft.world.level.block.state.StateHolder;
|
||||||
import net.minecraft.world.level.block.state.properties.Property;
|
import net.minecraft.world.level.block.state.properties.Property;
|
||||||
import net.minecraft.world.phys.AABB;
|
|
||||||
import net.minecraft.world.phys.shapes.CollisionContext;
|
|
||||||
import net.minecraft.world.phys.shapes.Shapes;
|
import net.minecraft.world.phys.shapes.Shapes;
|
||||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
@@ -32,7 +28,7 @@ abstract class BlockStateBaseMixin extends StateHolder<Block, BlockState> implem
|
|||||||
protected BlockBehaviour.BlockStateBase.Cache cache;
|
protected BlockBehaviour.BlockStateBase.Cache cache;
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
public abstract VoxelShape getCollisionShape(BlockGetter blockGetter, BlockPos blockPos, CollisionContext collisionContext);
|
public abstract boolean isAir();
|
||||||
|
|
||||||
protected BlockStateBaseMixin(Block object, Reference2ObjectArrayMap<Property<?>, Comparable<?>> reference2ObjectArrayMap, MapCodec<BlockState> mapCodec) {
|
protected BlockStateBaseMixin(Block object, Reference2ObjectArrayMap<Property<?>, Comparable<?>> reference2ObjectArrayMap, MapCodec<BlockState> mapCodec) {
|
||||||
super(object, reference2ObjectArrayMap, mapCodec);
|
super(object, reference2ObjectArrayMap, mapCodec);
|
||||||
@@ -93,10 +89,9 @@ abstract class BlockStateBaseMixin extends StateHolder<Block, BlockState> implem
|
|||||||
private void initCollisionState(final CallbackInfo ci) {
|
private void initCollisionState(final CallbackInfo ci) {
|
||||||
if (this.cache != null) {
|
if (this.cache != null) {
|
||||||
final VoxelShape collisionShape = this.cache.collisionShape;
|
final VoxelShape collisionShape = this.cache.collisionShape;
|
||||||
try {
|
if (this.isAir()) {
|
||||||
this.constantCollisionShape = this.getCollisionShape(null, null, null);
|
this.constantCollisionShape = Shapes.empty();
|
||||||
} catch (final Throwable throwable) {
|
} else {
|
||||||
// :(
|
|
||||||
this.constantCollisionShape = null;
|
this.constantCollisionShape = null;
|
||||||
}
|
}
|
||||||
this.occludesFullBlock = ((CollisionVoxelShape)collisionShape).moonrise$occludesFullBlock();
|
this.occludesFullBlock = ((CollisionVoxelShape)collisionShape).moonrise$occludesFullBlock();
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package ca.spottedleaf.moonrise.mixin.loading_screen;
|
package ca.spottedleaf.moonrise.mixin.loading_screen;
|
||||||
|
|
||||||
|
import ca.spottedleaf.moonrise.common.util.ConfigHolder;
|
||||||
import net.minecraft.client.multiplayer.LevelLoadStatusManager;
|
import net.minecraft.client.multiplayer.LevelLoadStatusManager;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
@@ -25,6 +26,9 @@ abstract class LevelLoadStatusManagerMixin {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
private void immediatelyClose(final CallbackInfo ci) {
|
private void immediatelyClose(final CallbackInfo ci) {
|
||||||
|
if (!ConfigHolder.getConfig().misc.immediatelyCloseLoadingScreen) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (this.status == LevelLoadStatusManager.Status.WAITING_FOR_SERVER) {
|
if (this.status == LevelLoadStatusManager.Status.WAITING_FOR_SERVER) {
|
||||||
this.status = LevelLoadStatusManager.Status.LEVEL_READY;
|
this.status = LevelLoadStatusManager.Status.LEVEL_READY;
|
||||||
ci.cancel();
|
ci.cancel();
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import it.unimi.dsi.fastutil.objects.AbstractReference2ObjectMap;
|
|||||||
import it.unimi.dsi.fastutil.objects.ObjectIterator;
|
import it.unimi.dsi.fastutil.objects.ObjectIterator;
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectSet;
|
import it.unimi.dsi.fastutil.objects.ObjectSet;
|
||||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectMap;
|
import it.unimi.dsi.fastutil.objects.Reference2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
|
import it.unimi.dsi.fastutil.objects.ReferenceArrayList;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -27,7 +27,7 @@ public final class ZeroCollidingReferenceStateTable<O, S> {
|
|||||||
|
|
||||||
public ZeroCollidingReferenceStateTable(final Collection<Property<?>> properties) {
|
public ZeroCollidingReferenceStateTable(final Collection<Property<?>> properties) {
|
||||||
this.propertyToIndexer = new Int2ObjectOpenHashMap<>(properties.size());
|
this.propertyToIndexer = new Int2ObjectOpenHashMap<>(properties.size());
|
||||||
this.properties = new ReferenceOpenHashSet<>(properties);
|
this.properties = new ReferenceArrayList<>(properties);
|
||||||
|
|
||||||
final List<Property<?>> sortedProperties = new ArrayList<>(properties);
|
final List<Property<?>> sortedProperties = new ArrayList<>(properties);
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import ca.spottedleaf.moonrise.common.PlatformHooks;
|
|||||||
import ca.spottedleaf.moonrise.common.misc.AllocatingRateLimiter;
|
import ca.spottedleaf.moonrise.common.misc.AllocatingRateLimiter;
|
||||||
import ca.spottedleaf.moonrise.common.misc.SingleUserAreaMap;
|
import ca.spottedleaf.moonrise.common.misc.SingleUserAreaMap;
|
||||||
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
||||||
import ca.spottedleaf.moonrise.common.util.MoonriseCommon;
|
import ca.spottedleaf.moonrise.common.util.MoonriseConstants;
|
||||||
import ca.spottedleaf.moonrise.common.util.TickThread;
|
import ca.spottedleaf.moonrise.common.util.TickThread;
|
||||||
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;
|
||||||
@@ -16,13 +16,10 @@ import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManage
|
|||||||
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.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.HashCommon;
|
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2ByteOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
import it.unimi.dsi.fastutil.longs.LongArrayList;
|
||||||
import it.unimi.dsi.fastutil.longs.LongComparator;
|
import it.unimi.dsi.fastutil.longs.LongComparator;
|
||||||
import it.unimi.dsi.fastutil.longs.LongHeapPriorityQueue;
|
import it.unimi.dsi.fastutil.longs.LongHeapPriorityQueue;
|
||||||
import it.unimi.dsi.fastutil.longs.LongIterator;
|
|
||||||
import it.unimi.dsi.fastutil.longs.LongLinkedOpenHashSet;
|
|
||||||
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
import it.unimi.dsi.fastutil.longs.LongOpenHashSet;
|
||||||
import net.minecraft.network.protocol.Packet;
|
import net.minecraft.network.protocol.Packet;
|
||||||
import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket;
|
import net.minecraft.network.protocol.game.ClientboundForgetLevelChunkPacket;
|
||||||
@@ -42,8 +39,6 @@ import net.minecraft.world.level.chunk.status.ChunkStatus;
|
|||||||
import net.minecraft.world.level.levelgen.BelowZeroRetrogen;
|
import net.minecraft.world.level.levelgen.BelowZeroRetrogen;
|
||||||
import java.lang.invoke.VarHandle;
|
import java.lang.invoke.VarHandle;
|
||||||
import java.util.ArrayDeque;
|
import java.util.ArrayDeque;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
@@ -120,14 +115,25 @@ public final class RegionizedPlayerChunkLoader {
|
|||||||
int sendViewDistance
|
int sendViewDistance
|
||||||
) {
|
) {
|
||||||
public ViewDistances setTickViewDistance(final int distance) {
|
public ViewDistances setTickViewDistance(final int distance) {
|
||||||
|
if (distance != -1 && (distance < (0) || distance > (MoonriseConstants.MAX_VIEW_DISTANCE))) {
|
||||||
|
throw new IllegalArgumentException(Integer.toString(distance));
|
||||||
|
}
|
||||||
return new ViewDistances(distance, this.loadViewDistance, this.sendViewDistance);
|
return new ViewDistances(distance, this.loadViewDistance, this.sendViewDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ViewDistances setLoadViewDistance(final int distance) {
|
public ViewDistances setLoadViewDistance(final int distance) {
|
||||||
|
// note: load view distance = api view distance + 1
|
||||||
|
if (distance != -1 && (distance < (2 + 1) || distance > (MoonriseConstants.MAX_VIEW_DISTANCE + 1))) {
|
||||||
|
throw new IllegalArgumentException(Integer.toString(distance));
|
||||||
|
}
|
||||||
return new ViewDistances(this.tickViewDistance, distance, this.sendViewDistance);
|
return new ViewDistances(this.tickViewDistance, distance, this.sendViewDistance);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ViewDistances setSendViewDistance(final int distance) {
|
public ViewDistances setSendViewDistance(final int distance) {
|
||||||
|
// note: send view distance <= load view distance - 1
|
||||||
|
if (distance != -1 && (distance < (0) || distance > (MoonriseConstants.MAX_VIEW_DISTANCE))) {
|
||||||
|
throw new IllegalArgumentException(Integer.toString(distance));
|
||||||
|
}
|
||||||
return new ViewDistances(this.tickViewDistance, this.loadViewDistance, distance);
|
return new ViewDistances(this.tickViewDistance, this.loadViewDistance, distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,16 +167,6 @@ public final class RegionizedPlayerChunkLoader {
|
|||||||
return data.lastLoadDistance - 1;
|
return data.lastLoadDistance - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getLoadViewDistance(final ServerPlayer player) {
|
|
||||||
final ServerLevel level = player.serverLevel();
|
|
||||||
final PlayerChunkLoaderData data = ((ChunkSystemServerPlayer)player).moonrise$getChunkLoader();
|
|
||||||
if (data == null) {
|
|
||||||
return ((ChunkSystemServerLevel)level).moonrise$getPlayerChunkLoader().getAPIViewDistance();
|
|
||||||
}
|
|
||||||
// view distance = load distance + 1
|
|
||||||
return data.lastLoadDistance - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getAPISendViewDistance(final ServerPlayer player) {
|
public static int getAPISendViewDistance(final ServerPlayer player) {
|
||||||
final ServerLevel level = player.serverLevel();
|
final ServerLevel level = player.serverLevel();
|
||||||
final PlayerChunkLoaderData data = ((ChunkSystemServerPlayer)player).moonrise$getChunkLoader();
|
final PlayerChunkLoaderData data = ((ChunkSystemServerPlayer)player).moonrise$getChunkLoader();
|
||||||
@@ -522,7 +518,7 @@ public final class RegionizedPlayerChunkLoader {
|
|||||||
final int playerLoadViewDistance, final int worldLoadViewDistance) {
|
final int playerLoadViewDistance, final int worldLoadViewDistance) {
|
||||||
return Math.min(
|
return Math.min(
|
||||||
playerTickViewDistance < 0 ? worldTickViewDistance : playerTickViewDistance,
|
playerTickViewDistance < 0 ? worldTickViewDistance : playerTickViewDistance,
|
||||||
playerLoadViewDistance < 0 ? worldLoadViewDistance : playerLoadViewDistance
|
playerLoadViewDistance < 0 ? (worldLoadViewDistance - 1) : (playerLoadViewDistance - 1)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -219,6 +219,8 @@ public final class ChunkHolderManager {
|
|||||||
LOGGER.error("Failed to close '" + type.name() + "' regionfile cache for world '" + WorldUtil.getWorldName(this.world) + "'", ex);
|
LOGGER.error("Failed to close '" + type.name() + "' regionfile cache for world '" + WorldUtil.getWorldName(this.world) + "'", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.taskScheduler.setShutdown(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ensureInAutosave(final NewChunkHolder holder) {
|
void ensureInAutosave(final NewChunkHolder holder) {
|
||||||
|
|||||||
@@ -271,6 +271,16 @@ public final class ChunkTaskScheduler {
|
|||||||
return this.lockShift;
|
return this.lockShift;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private volatile boolean shutdown;
|
||||||
|
|
||||||
|
public boolean hasShutdown() {
|
||||||
|
return this.shutdown;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setShutdown(final boolean shutdown) {
|
||||||
|
this.shutdown = shutdown;
|
||||||
|
}
|
||||||
|
|
||||||
public ChunkTaskScheduler(final ServerLevel world) {
|
public ChunkTaskScheduler(final ServerLevel world) {
|
||||||
this.world = world;
|
this.world = world;
|
||||||
// must be >= region shift (in paper, doesn't exist) and must be >= ticket propagator section shift
|
// must be >= region shift (in paper, doesn't exist) and must be >= ticket propagator section shift
|
||||||
@@ -524,6 +534,13 @@ public final class ChunkTaskScheduler {
|
|||||||
return loaded;
|
return loaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.hasShutdown()) {
|
||||||
|
throw new IllegalStateException(
|
||||||
|
"Chunk system has shut down, cannot process chunk requests in world '" + ca.spottedleaf.moonrise.common.util.WorldUtil.getWorldName(this.world) + "' at "
|
||||||
|
+ "(" + chunkX + "," + chunkZ + ") status: " + status
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
final Long ticketId = getNextNonFullLoadId();
|
final Long ticketId = getNextNonFullLoadId();
|
||||||
final int ticketLevel = getTicketLevel(status);
|
final int ticketLevel = getTicketLevel(status);
|
||||||
this.chunkHolderManager.addTicketAtLevel(NON_FULL_CHUNK_LOAD, chunkX, chunkZ, ticketLevel, ticketId);
|
this.chunkHolderManager.addTicketAtLevel(NON_FULL_CHUNK_LOAD, chunkX, chunkZ, ticketLevel, ticketId);
|
||||||
|
|||||||
@@ -2162,10 +2162,16 @@ public final class CollisionUtil {
|
|||||||
|
|
||||||
public CollisionContext getDelegate() {
|
public CollisionContext getDelegate() {
|
||||||
this.delegated = true;
|
this.delegated = true;
|
||||||
final Entity entity = this.getEntity();
|
final Entity entity = super.getEntity();
|
||||||
return this.delegate == null ? this.delegate = (entity == null ? CollisionContext.empty() : CollisionContext.of(entity)) : this.delegate;
|
return this.delegate == null ? this.delegate = (entity == null ? CollisionContext.empty() : CollisionContext.of(entity)) : this.delegate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Entity getEntity() {
|
||||||
|
this.getDelegate();
|
||||||
|
return super.getEntity();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isDescending() {
|
public boolean isDescending() {
|
||||||
return this.getDelegate().isDescending();
|
return this.getDelegate().isDescending();
|
||||||
|
|||||||
@@ -237,7 +237,7 @@ public final class MoonriseCommand {
|
|||||||
return Command.SINGLE_SUCCESS;
|
return Command.SINGLE_SUCCESS;
|
||||||
} else {
|
} else {
|
||||||
ctx.getSource().sendFailure(
|
ctx.getSource().sendFailure(
|
||||||
Component.literal("Reloaded Moonrise config.")
|
Component.literal("Failed to reload Moonrise config, see logs.")
|
||||||
.withStyle(ChatFormatting.RED)
|
.withStyle(ChatFormatting.RED)
|
||||||
);
|
);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -30,6 +30,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",
|
||||||
|
|||||||
Reference in New Issue
Block a user