Compare commits

...

48 Commits

Author SHA1 Message Date
Spottedleaf
a6cf977c5f Set version to 0.2.0-beta.5 2024-12-01 16:00:29 -08:00
Spottedleaf
8ed23bc8f3 Fix several off-by-one errors in view distance calculations
1. For NearbyPlayers, we need to be using the view distance, and
   not the load distance (which is +1 of the view distance).
2. Correctly clamp tick distance to view distance. Since
   load distance is +1 of view distance, we need to subtract
   one from the load distance when clamping.

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

Fixes https://github.com/PaperMC/Paper/issues/11697
2024-12-01 12:00:31 -08:00
Spottedleaf
1a077389c2 Force LazyEntityCollisionContext#getEntity() to delegate
By delegating when the entity is retrieved, we can correctly catch
cases where the collision method is inspecting some entity state.
2024-12-01 12:00:18 -08:00
Spottedleaf
49bcc60cf5 Only call config initialisers if reload succeeded 2024-12-01 11:31:16 -08:00
Spottedleaf
8b1f31ade8 Drop RegionFileStorage.RegionFileSizeException diff in MoonriseRegionFileIO
This diff should be implemented in Paper. Previously, the diff was
in the chunk system patch in Paper - but it should be in its own
separate patch.
2024-11-28 17:53:36 -08:00
Spottedleaf
4d88e04e3c Do not call modifyEntityTrackingRange on own range
The range is already modified, so this call will not do anything.
2024-11-27 12:20:50 -08:00
Spottedleaf
33889c3850 Replace Level/Entity randoms with ThreadUnsafeRandom
This avoids the expensive CAS logic at the expense of losing the
thread check.
2024-11-27 05:56:34 -08:00
Spottedleaf
37ac3003cb Replace SimpleRandom with (Simple)ThreadUnsafeRandom
ThreadUnsafeRandom is a random implementation that is
identical to LegacyRandomSource behaviourally, but
without the thread checks.

SimpleThreadUnsafeRandom is ThreadUnsafeRandom except with
its nextInt(int) function replaced with a faster
but more biased implementation when bound is very large.
2024-11-27 05:56:34 -08:00
Jason Penilla
28128d06c1 Disable immediate loading screen closure by default 2024-11-26 15:51:35 -07:00
Spottedleaf
6f9620787b Use https for YamlConfig repo
SSH isn't setup in actions so it cannot clone via SSH.
2024-11-25 09:30:49 -08:00
Spottedleaf
cbf6c118dc Mark install_deps.sh as executable 2024-11-25 09:25:32 -08:00
Spottedleaf
d44fa1f8aa Move YamlConfig to own project 2024-11-25 09:17:11 -08:00
Spottedleaf
3d9ae3f018 Fix non block ticking chunks not sending block/light updates
Needed to redirect the getTickingChunk call in
broadcastChangedChunks to use the chunk to send method.
2024-11-18 13:24:24 -08:00
Spottedleaf
d24f6c2874 Do not create unneccessary callback in ChunkTaskScheduler#scheduleChunkLoad
If the parameter has addTicket = false and onComplete = null,
then the loadCallback would do no work and as a result does
not need to be created.
2024-11-17 14:09:00 -08:00
Jason Penilla
f190cdd8cb Back to 0.2.0-SNAPSHOT 2024-11-17 11:31:37 -07:00
Jason Penilla
e7510eda16 0.2.0-beta.4 2024-11-17 10:49:05 -07:00
Jason Penilla
d9442c1492 Update lithium overrides 2024-11-17 10:28:38 -07:00
Jason Penilla
93eb2786f2 Update ServerExplosionMixin for NeoForge changes 2024-11-17 10:27:31 -07:00
Jason Penilla
1bef6823c5 Update lithium, NeoForge, loom 2024-11-16 17:35:27 -07:00
Jason Penilla
01152eec95 Update NeoForge lithium overrides 2024-11-16 17:34:44 -07:00
Spottedleaf
1e39f5370a Fix experimental minecart collisions on sloped rails
We are supposed to ignore some collisions on the sloped
rail.
2024-11-14 13:31:22 -08:00
Jason Penilla
ea50ba38ea Apply FerriteCore config overrides automatically
New versions of FC added this mechanism

closes #66
2024-11-05 16:12:37 -07:00
Spottedleaf
c00b9fcd7b Move back to 0.2.0-SNAPSHOT 2024-11-02 16:54:15 -07:00
Spottedleaf
bad5cae4d8 0.2.0-beta.3 2024-11-02 16:50:24 -07:00
Spottedleaf
e3b1502bb6 0.2.0-beta.9 2024-11-02 16:48:24 -07:00
Spottedleaf
54fc964987 Handle corrupt light data gracefully
First, if the light data is not marked as correct, we should not be
parsing it in the first place. This will eliminate errors from
parsing possibly different versioned light data.

Secondly, if parsing the light data throws an exception (from
the SWMRNibbleArray constructor), then we can simply mark
the returned chunk as having incorrect light data - rather than
propagating the exception and causing the chunk to be re-generated.
2024-11-02 16:14:05 -07:00
Spottedleaf
0cbc9aa1a1 Update README to reflect official nature of the patches 2024-10-31 12:05:59 -07:00
Jason Penilla
19e2136ae1 Use declaration order for state holder property iteration
Mostly an aesthetic change for serialization, should not have any impact on performance or correctness.
2024-10-27 18:32:04 -07:00
Jason Penilla
126cc03747 Back to 0.2.0-SNAPSHOT 2024-10-26 11:02:43 -07:00
Jason Penilla
ceb4936d9d 0.2.0-beta.2 2024-10-26 10:58:58 -07:00
Jason Penilla
3cb888e894 Update Fabric API and call ServerChunkEvents.CHUNK_GENERATE 2024-10-26 09:51:34 -07:00
Jason Penilla
7bedc1a7de Back to 0.2.0-SNAPSHOT 2024-10-24 11:54:52 -07:00
Jason Penilla
718f6e1369 0.2.0-beta.1 2024-10-24 11:48:32 -07:00
Spottedleaf
da9ab708a6 Import diff
The ChunkTaskScheduler one is actually needed in Paper to compile.
2024-10-24 11:39:02 -07:00
Spottedleaf
f22335f0b6 Move logic in anyPlayerCloseEnoughForSpawning overwrite to correct place
The internal function is responsible for the actual player iteration.
2024-10-24 10:00:23 -07:00
Spottedleaf
a3f2328000 Redirect chunk holder retrieval in ChunkMap#forEachSpawnCandidateChunk
The old chunk holder field is not maintained so this would
NPE.
2024-10-24 09:50:35 -07:00
Spottedleaf
529b9a44bb Add missing overwrite for DistanceManager#getTickingChunks 2024-10-24 09:37:16 -07:00
Spottedleaf
1e9a6504a1 Add world parameter to configAutoSaveInterval/configMaxAutoSavePerTick
Paper needs the world parameter to access the config values,
but in Moonrise we do not.
2024-10-24 08:29:57 -07:00
Spottedleaf
9c46dcbb94 Remove unused read/write methods on ChunkSystemSectionStorage
As with the last commit, these were only used in the legacy
region file I/O code and as such there is no reason to maintain
them.
2024-10-24 07:10:48 -07:00
Spottedleaf
9a1e04389a Adjust SectionStorageMixin to destroy hooks
In the legacy implementation of the region file I/O (before
the chunk system), these hooks were actually used. Now, they are not
and so there is no point in maintaining them.
2024-10-24 07:01:46 -07:00
Spottedleaf
29084d8e3f Properly sync on dimension data during ServerChunkCache#close
Note that this data was still saved, but we did not block until
it was finished.
2024-10-23 22:57:27 -07:00
Spottedleaf
41790ecf1a Implement overwrite for DistanceManager#getSpawnCandidateChunks 2024-10-23 22:53:34 -07:00
Spottedleaf
8af7bccdfd Adjust PlatformHooks#convertNBT to take TypeReference
DataFixTypes has a limited number of types, which will limit its
usage on Paper.
2024-10-23 22:10:41 -07:00
Spottedleaf
5f9b3571f8 Fix compile
Did not implement the other half of changes required in the last
commit...
2024-10-23 21:36:36 -07:00
Spottedleaf
9adfb2514d Change PlatformHooks#onChunkHolderTicketChange to take ChunkHolder
This makes compatibility on Paper easier to implement
as NewChunkHolder is not always available.
2024-10-23 21:33:54 -07:00
Jason Penilla
bf2cd1c571 fabric: fix crash when fabric-lifecycle-events-v1 not present 2024-10-23 18:23:42 -07:00
76 changed files with 725 additions and 1635 deletions

View File

@@ -31,8 +31,8 @@ jobs:
key: ${{ runner.os }}-project-local-gradle-caches-${{ hashFiles('**/libs.versions.toml', '**/*.gradle*', '**/gradle-wrapper.properties') }}
restore-keys: |
${{ runner.os }}-project-local-gradle-caches-
- name: "setup concurrentutil"
run: ./installConcurrentUtil.sh
- name: "setup dependencies"
run: ./install_deps.sh
- name: "execute gradle build"
run: ./gradlew build
- name: Determine Snapshot Status

3
.gitmodules vendored
View File

@@ -1,3 +1,6 @@
[submodule "ConcurrentUtil"]
path = ConcurrentUtil
url = https://github.com/Spottedleaf/ConcurrentUtil.git
[submodule "YamlConfig"]
path = YamlConfig
url = https://github.com/Spottedleaf/YamlConfig.git

View File

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

1
YamlConfig Submodule

Submodule YamlConfig added at 67552e7707

View File

@@ -23,6 +23,7 @@ dependencies {
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
api("ca.spottedleaf:concurrentutil:${rootProject.concurrentutil_version}")
api("ca.spottedleaf:yamlconfig:${rootProject.yamlconfig_version}")
api("org.yaml:snakeyaml:${rootProject.snakeyaml_version}")
modImplementation "me.shedaniel.cloth:cloth-config:${rootProject.cloth_version}"
@@ -48,6 +49,7 @@ allprojects {
mavenLocal {
mavenContent {
includeModule("ca.spottedleaf", "concurrentutil")
includeModule("ca.spottedleaf", "yamlconfig")
}
}
maven {

View File

@@ -18,13 +18,15 @@ dependencies {
modImplementation "net.fabricmc:fabric-loader:${project.loader_version}"
libs("ca.spottedleaf:concurrentutil:${rootProject.concurrentutil_version}")
libs("ca.spottedleaf:yamlconfig:${rootProject.yamlconfig_version}")
libs("org.yaml:snakeyaml:${rootProject.snakeyaml_version}")
modImplementation "me.shedaniel.cloth:cloth-config-fabric:${rootProject.cloth_version}"
include "me.shedaniel.cloth:cloth-config-fabric:${rootProject.cloth_version}"
modImplementation "com.terraformersmc:modmenu:${rootProject.modmenu_version}"
modImplementation fabricApiLibs.fabric.api
modImplementation fabricApiLibs.command.api.v2
modImplementation fabricApiLibs.lifecycle.events.v1
include fabricApiLibs.command.api.v2
include fabricApiLibs.base
}
@@ -42,6 +44,7 @@ shadowJar {
destinationDirectory = layout.buildDirectory.dir("libs")
configurations = [project.configurations.shadow]
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'
}
@@ -59,7 +62,7 @@ publishMods {
incompatible(
"not-enough-crashes",
"starlight",
"c2me-fabric"
"c2me"
)
}
}

View File

@@ -2,21 +2,25 @@ package ca.spottedleaf.moonrise.fabric;
import ca.spottedleaf.moonrise.common.PlatformHooks;
import ca.spottedleaf.moonrise.common.util.ConfigHolder;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder;
import com.mojang.datafixers.DSL;
import com.mojang.datafixers.DataFixer;
import com.mojang.serialization.Dynamic;
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents;
import net.fabricmc.loader.api.FabricLoader;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.GenerationChunkHolder;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.datafix.DataFixTypes;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.ChunkAccess;
import net.minecraft.world.level.chunk.ImposterProtoChunk;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.ProtoChunk;
import net.minecraft.world.level.chunk.status.ChunkStatusTasks;
@@ -28,6 +32,8 @@ import java.util.function.Predicate;
public final class FabricHooks implements PlatformHooks {
private static final boolean HAS_FABRIC_LIFECYCLE_EVENTS = FabricLoader.getInstance().isModLoaded("fabric-lifecycle-events-v1");
@Override
public String getBrand() {
return "Moonrise";
@@ -62,7 +68,12 @@ public final class FabricHooks implements PlatformHooks {
@Override
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
@@ -71,13 +82,15 @@ public final class FabricHooks implements PlatformHooks {
}
@Override
public void onChunkHolderTicketChange(final ServerLevel world, final NewChunkHolder holder, final int oldLevel, final int newLevel) {
public void onChunkHolderTicketChange(final ServerLevel world, final ChunkHolder holder, final int oldLevel, final int newLevel) {
}
@Override
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
@@ -153,12 +166,12 @@ public final class FabricHooks implements PlatformHooks {
}
@Override
public long configAutoSaveInterval() {
public long configAutoSaveInterval(final ServerLevel world) {
return ConfigHolder.getConfig().chunkSaving.autoSaveInterval.getTimeTicks();
}
@Override
public int configMaxAutoSavePerTick() {
public int configMaxAutoSavePerTick(final ServerLevel world) {
return ConfigHolder.getConfig().chunkSaving.maxAutoSaveChunksPerTick;
}
@@ -173,9 +186,11 @@ public final class FabricHooks implements PlatformHooks {
}
@Override
public CompoundTag convertNBT(final DataFixTypes type, final DataFixer dataFixer, final CompoundTag nbt,
public CompoundTag convertNBT(final DSL.TypeReference type, final DataFixer dataFixer, final CompoundTag nbt,
final int fromVersion, final int toVersion) {
return type.update(dataFixer, nbt, fromVersion, toVersion);
return (CompoundTag)dataFixer.update(
type, new Dynamic<>(NbtOps.INSTANCE, nbt), fromVersion, toVersion
).getValue();
}
@Override

View File

@@ -42,7 +42,6 @@
"custom": {
"lithium:options": {
"mixin.ai.poi": false,
"mixin.alloc.chunk_ticking": false,
"mixin.alloc.deep_passengers": false,
"mixin.alloc.entity_tracker": false,
"mixin.block.flatten_states": false,
@@ -66,9 +65,12 @@
"mixin.world.block_entity_ticking": false,
"mixin.world.chunk_access": false,
"mixin.world.explosions.block_raycast": false,
"mixin.world.explosions.cache_exposure": false,
"mixin.world.temperature_cache": false,
"mixin.world.tick_scheduler": false
}
},
"ferritecore:disabled_options": [
"replaceNeighborLookup",
"replacePropertyMap"
]
}
}

View File

@@ -6,16 +6,17 @@ org.gradle.daemon=false
minecraft_version=1.21.3
loader_version=0.16.7
supported_minecraft_versions=1.21.3
neoforge_version=21.3.0-beta
fabric_api_version=0.106.1+1.21.3
snakeyaml_version=2.2
neoforge_version=21.3.31-beta
fabric_api_version=0.107.0+1.21.3
snakeyaml_version=2.3
concurrentutil_version=0.0.2-SNAPSHOT
yamlconfig_version=1.0.2-SNAPSHOT
cloth_version=16.0.141
modmenu_version=12.0.0-beta.1
# version ids from modrinth
fabric_lithium_version=mc1.21.1-0.14.0-beta.1
neo_lithium_version=BrMIoIMv
fabric_lithium_version=QhCwdt4l
neo_lithium_version=wDD955sb
# Mod Properties
mod_version=0.2.0-SNAPSHOT
mod_version=0.2.0-beta.5
maven_group=ca.spottedleaf.moonrise
archives_base_name=moonrise

View File

@@ -2,5 +2,11 @@
set -eou pipefail
git submodule update --init --recursive
cd ConcurrentUtil
mvn install
cd ..
cd YamlConfig
mvn install

View File

@@ -22,6 +22,7 @@ dependencies {
neoForge "net.neoforged:neoforge:${rootProject.neoforge_version}"
shadow("ca.spottedleaf:concurrentutil:${rootProject.concurrentutil_version}")
shadow("ca.spottedleaf:yamlconfig:${rootProject.yamlconfig_version}")
shadow("org.yaml:snakeyaml:${rootProject.snakeyaml_version}")
forgeExtra("org.yaml:snakeyaml:${rootProject.snakeyaml_version}")
@@ -42,6 +43,7 @@ shadowJar {
destinationDirectory = layout.buildDirectory.dir("libs")
configurations = [project.configurations.shadow]
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'
}

View File

@@ -3,14 +3,16 @@ package ca.spottedleaf.moonrise.neoforge;
import ca.spottedleaf.moonrise.common.PlatformHooks;
import ca.spottedleaf.moonrise.common.util.ConfigHolder;
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder;
import com.mojang.datafixers.DSL;
import com.mojang.datafixers.DataFixer;
import com.mojang.serialization.Dynamic;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.NbtOps;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.GenerationChunkHolder;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.util.datafix.DataFixTypes;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.ChunkPos;
@@ -80,10 +82,12 @@ public final class NeoForgeHooks implements PlatformHooks {
}
@Override
public void onChunkHolderTicketChange(final ServerLevel world, final NewChunkHolder holder, final int oldLevel, final int newLevel) {
public void onChunkHolderTicketChange(final ServerLevel world, final ChunkHolder holder, final int oldLevel, final int newLevel) {
final ChunkPos pos = holder.getPos();
EventHooks.fireChunkTicketLevelUpdated(
world, CoordinateUtils.getChunkKey(holder.chunkX, holder.chunkZ),
oldLevel, newLevel, holder.vanillaChunkHolder
world, CoordinateUtils.getChunkKey(pos.x, pos.z),
oldLevel, newLevel, holder
);
}
@@ -185,12 +189,12 @@ public final class NeoForgeHooks implements PlatformHooks {
}
@Override
public long configAutoSaveInterval() {
public long configAutoSaveInterval(final ServerLevel world) {
return ConfigHolder.getConfig().chunkSaving.autoSaveInterval.getTimeTicks();
}
@Override
public int configMaxAutoSavePerTick() {
public int configMaxAutoSavePerTick(final ServerLevel world) {
return ConfigHolder.getConfig().chunkSaving.maxAutoSaveChunksPerTick;
}
@@ -205,9 +209,11 @@ public final class NeoForgeHooks implements PlatformHooks {
}
@Override
public CompoundTag convertNBT(final DataFixTypes type, final DataFixer dataFixer, final CompoundTag nbt,
public CompoundTag convertNBT(final DSL.TypeReference type, final DataFixer dataFixer, final CompoundTag nbt,
final int fromVersion, final int toVersion) {
return type.update(dataFixer, nbt, fromVersion, toVersion);
return (CompoundTag)dataFixer.update(
type, new Dynamic<>(NbtOps.INSTANCE, nbt), fromVersion, toVersion
).getValue();
}
@Override

View File

@@ -13,6 +13,10 @@ displayURL = "https://github.com/Tuinity/Moonrise"
authors = "Spottedleaf"
description = "Optimisation mod for the dedicated and integrated server."
displayTest = "IGNORE_ALL_VERSION"
"ferritecore:disabled_options" = [
"replaceNeighborLookup",
"replacePropertyMap"
]
[[dependencies.moonrise]]
modId = "neoforge"
@@ -51,9 +55,8 @@ config = "moonrise.mixins.json"
[[mixins]]
config = "moonrise-neoforge.mixins.json"
[mods."lithium:options"]
["lithium:options"]
"mixin.ai.poi" = false
"mixin.alloc.chunk_ticking" = false
"mixin.alloc.deep_passengers" = false
"mixin.alloc.entity_tracker" = false
"mixin.block.flatten_states" = false
@@ -77,6 +80,5 @@ config = "moonrise-neoforge.mixins.json"
"mixin.world.block_entity_ticking" = false
"mixin.world.chunk_access" = false
"mixin.world.explosions.block_raycast" = false
"mixin.world.explosions.cache_exposure" = false
"mixin.world.temperature_cache" = false
"mixin.world.tick_scheduler" = false

View File

@@ -24,7 +24,7 @@ pluginManagement {
plugins {
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
id("xyz.jpenilla.quiet-architectury-loom") version "1.7.297" apply false
id("xyz.jpenilla.quiet-architectury-loom") version "1.7.300" apply false
id 'com.gradleup.shadow' version '8.3.0' apply false
}

View File

@@ -1,9 +1,10 @@
package ca.spottedleaf.moonrise.common;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder;
import com.mojang.datafixers.DSL;
import com.mojang.datafixers.DataFixer;
import net.minecraft.core.BlockPos;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ChunkHolder;
import net.minecraft.server.level.GenerationChunkHolder;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.server.level.ServerPlayer;
@@ -44,7 +45,7 @@ public interface PlatformHooks {
public boolean allowAsyncTicketUpdates();
public void onChunkHolderTicketChange(final ServerLevel world, final NewChunkHolder holder, final int oldLevel, final int newLevel);
public void onChunkHolderTicketChange(final ServerLevel world, final ChunkHolder holder, final int oldLevel, final int newLevel);
public void chunkUnloadFromWorld(final LevelChunk chunk);
@@ -79,16 +80,16 @@ public interface PlatformHooks {
public int configPlayerMaxConcurrentGens();
public long configAutoSaveInterval();
public long configAutoSaveInterval(final ServerLevel world);
public int configMaxAutoSavePerTick();
public int configMaxAutoSavePerTick(final ServerLevel world);
public boolean configFixMC159283();
// support for CB chunk mustNotSave
public boolean forceNoSave(final ChunkAccess chunk);
public CompoundTag convertNBT(final DataFixTypes type, final DataFixer dataFixer, final CompoundTag nbt,
public CompoundTag convertNBT(final DSL.TypeReference type, final DataFixer dataFixer, final CompoundTag nbt,
final int fromVersion, final int toVersion);
public boolean hasMainChunkLoadHook();

View File

@@ -1,7 +0,0 @@
package ca.spottedleaf.moonrise.common.config;
public interface InitialiseHook {
public void initialise();
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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 {
}

View File

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

View File

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

View File

@@ -1,12 +1,12 @@
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.annotation.Serializable;
import ca.spottedleaf.moonrise.common.config.type.Duration;
import ca.spottedleaf.moonrise.common.util.MoonriseCommon;
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
public final class MoonriseConfig {
@@ -251,4 +251,21 @@ public final class MoonriseConfig {
)
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;
}
}

View File

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

View File

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

View File

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

View File

@@ -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_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.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
}

View File

@@ -2,6 +2,7 @@ package ca.spottedleaf.moonrise.common.misc;
import ca.spottedleaf.concurrentutil.util.IntPairUtil;
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
import it.unimi.dsi.fastutil.longs.LongSet;
import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap;
import it.unimi.dsi.fastutil.objects.ReferenceSet;
@@ -14,6 +15,10 @@ public final class PositionCountingAreaMap<T> {
return this.counters.keySet();
}
public LongSet getPositions() {
return this.positions.keySet();
}
public int getTotalPositions() {
return this.positions.size();
}

View File

@@ -152,8 +152,8 @@ public final class ChunkSystem {
return RegionizedPlayerChunkLoader.getAPISendViewDistance(player);
}
public static int getLoadViewDistance(final ServerPlayer player) {
return RegionizedPlayerChunkLoader.getLoadViewDistance(player);
public static int getViewDistance(final ServerPlayer player) {
return RegionizedPlayerChunkLoader.getAPIViewDistance(player);
}
public static int getTickViewDistance(final ServerPlayer player) {

View File

@@ -1,11 +1,9 @@
package ca.spottedleaf.moonrise.common.util;
import ca.spottedleaf.moonrise.common.PlatformHooks;
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.adapter.DefaultedTypeAdapter;
import ca.spottedleaf.moonrise.common.config.moonrise.type.DefaultedValue;
import ca.spottedleaf.yamlconfig.adapter.TypeAdapterRegistry;
import ca.spottedleaf.yamlconfig.config.YamlConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
@@ -18,8 +16,6 @@ public final class ConfigHolder {
private static final TypeAdapterRegistry CONFIG_ADAPTERS = new TypeAdapterRegistry();
private static final YamlConfig<MoonriseConfig> CONFIG;
static {
CONFIG_ADAPTERS.putAdapter(DefaultedValue.class, new DefaultedTypeAdapter());
try {
CONFIG = new YamlConfig<>(MoonriseConfig.class, new MoonriseConfig(), CONFIG_ADAPTERS);
} catch (final Exception ex) {
@@ -52,14 +48,6 @@ public final class ConfigHolder {
}
public static boolean reloadConfig() {
final boolean ret = reloadConfig0();
CONFIG.callInitialisers();
return ret;
}
private static boolean reloadConfig0() {
synchronized (CONFIG) {
if (CONFIG_FILE.exists()) {
try {
@@ -70,6 +58,8 @@ public final class ConfigHolder {
}
}
CONFIG.callInitialisers();
// write back any changes, or create if needed
return saveConfig();
}

View File

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

View File

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

View File

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

View File

@@ -538,6 +538,21 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
throw new UnsupportedOperationException();
}
/**
* @reason Route to new chunk system
* @author Spottedleaf
*/
@Redirect(
method = "forEachSpawnCandidateChunk",
at = @At(
value = "INVOKE",
target = "Lit/unimi/dsi/fastutil/longs/Long2ObjectLinkedOpenHashMap;get(J)Ljava/lang/Object;"
)
)
private <V> V redirectChunkHolderGet(final Long2ObjectLinkedOpenHashMap<V> instance, final long key) {
return (V)this.getVisibleChunkIfPresent(key);
}
@Override
public CompletableFuture<Optional<CompoundTag>> read(final ChunkPos pos) {
final CompletableFuture<Optional<CompoundTag>> ret = new CompletableFuture<>();

View File

@@ -1,5 +1,6 @@
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.chunk.ChunkSystemDistanceManager;
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager;
@@ -13,6 +14,7 @@ import net.minecraft.server.level.ThrottlingChunkTaskDispatcher;
import net.minecraft.server.level.Ticket;
import net.minecraft.server.level.TicketType;
import net.minecraft.server.level.TickingTracker;
import net.minecraft.util.Mth;
import net.minecraft.util.SortedArraySet;
import net.minecraft.world.level.ChunkPos;
import org.spongepowered.asm.mixin.Mixin;
@@ -285,7 +287,10 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
*/
@Overwrite
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);
}
/**
@@ -315,6 +320,15 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
throw new UnsupportedOperationException();
}
/**
* @reason Remove old chunk system hooks
* @author Spottedleaf
*/
@Overwrite
public LongSet getTickingChunks() {
throw new UnsupportedOperationException();
}
/**
* @reason This hack is not required anymore, see {@link MinecraftServerMixin}
* @author Spottedleaf

View File

@@ -43,4 +43,17 @@ abstract class PlayerListMixin {
)
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) {}
}

View File

@@ -266,20 +266,4 @@ public abstract class PoiManagerMixin extends SectionStorage<Object, Object> imp
private <T> Stream<T> skipLoadedSet(final Stream<T> instance, final Predicate<? super T> predicate) {
return instance;
}
@Override
public final void moonrise$close() throws IOException {}
@Override
public final CompoundTag moonrise$read(final int chunkX, final int chunkZ) throws IOException {
return MoonriseRegionFileIO.loadData(
this.world, chunkX, chunkZ, MoonriseRegionFileIO.RegionFileType.POI_DATA,
MoonriseRegionFileIO.getIOBlockingPriorityForCurrentThread()
);
}
@Override
public final void moonrise$write(final int chunkX, final int chunkZ, final CompoundTag data) throws IOException {
MoonriseRegionFileIO.scheduleSave(this.world, chunkX, chunkZ, data, MoonriseRegionFileIO.RegionFileType.POI_DATA);
}
}

View File

@@ -26,10 +26,6 @@ abstract class SectionStorageMixin<R, P> implements ChunkSystemSectionStorage, A
@Shadow
private SimpleRegionStorage simpleRegionStorage;
@Shadow
@Final
static Logger LOGGER;
@Unique
private RegionFileStorage storage;
@@ -39,6 +35,9 @@ abstract class SectionStorageMixin<R, P> implements ChunkSystemSectionStorage, A
return this.storage;
}
@Override
public void moonrise$close() throws IOException {}
/**
* @reason Retrieve storage from IOWorker, and then nuke it
* @author Spottedleaf
@@ -59,12 +58,8 @@ abstract class SectionStorageMixin<R, P> implements ChunkSystemSectionStorage, A
* @author Spottedleaf
*/
@Overwrite
public final CompletableFuture<Optional<CompoundTag>> tryRead(final ChunkPos pos) {
try {
return CompletableFuture.completedFuture(Optional.ofNullable(this.moonrise$read(pos.x, pos.z)));
} catch (final Throwable thr) {
return CompletableFuture.failedFuture(thr);
}
public final CompletableFuture<Optional<SectionStorage.PackedChunk<P>>> tryRead(final ChunkPos pos) {
throw new IllegalStateException("Only chunk system can write state, offending class:" + this.getClass().getName());
}
/**
@@ -77,24 +72,12 @@ abstract class SectionStorageMixin<R, P> implements ChunkSystemSectionStorage, A
}
/**
* @reason Route to new chunk system hook
* @reason Destroy old chunk system hook
* @author Spottedleaf
*/
@Redirect(
method = "writeChunk(Lnet/minecraft/world/level/ChunkPos;)V",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/level/chunk/storage/SimpleRegionStorage;write(Lnet/minecraft/world/level/ChunkPos;Lnet/minecraft/nbt/CompoundTag;)Ljava/util/concurrent/CompletableFuture;"
)
)
private CompletableFuture<Void> redirectWrite(final SimpleRegionStorage instance, final ChunkPos pos,
final CompoundTag tag) {
try {
this.moonrise$write(pos.x, pos.z, tag);
} catch (final IOException ex) {
LOGGER.error("Error writing poi chunk data to disk for chunk " + pos, ex);
}
return null;
@Overwrite
private void writeChunk(final ChunkPos chunkPos) {
throw new IllegalStateException("Only chunk system can write state, offending class:" + this.getClass().getName());
}
/**

View File

@@ -24,6 +24,7 @@ import net.minecraft.world.level.chunk.ChunkSource;
import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LightChunk;
import net.minecraft.world.level.chunk.status.ChunkStatus;
import net.minecraft.world.level.storage.DimensionDataStorage;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Overwrite;
@@ -51,6 +52,10 @@ abstract class ServerChunkCacheMixin extends ChunkSource implements ChunkSystemS
@Final
public ServerLevel level;
@Shadow
@Final
private DimensionDataStorage dataStorage;
@Unique
private final ConcurrentLong2ReferenceChainedHashTable<LevelChunk> fullChunks = new ConcurrentLong2ReferenceChainedHashTable<>();
@@ -261,6 +266,7 @@ abstract class ServerChunkCacheMixin extends ChunkSource implements ChunkSystemS
@Override
@Overwrite
public void close() throws IOException {
this.dataStorage.close();
((ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.close(true, true);
}
@@ -309,6 +315,22 @@ abstract class ServerChunkCacheMixin extends ChunkSource implements ChunkSystemS
return false;
}
/**
* @reason We need to use {@link ChunkHolder#getChunkToSend()} as the new chunk system will not bring every chunk
* sent to players up to block ticking.
* @author Spottedleaf
*/
@Redirect(
method = "broadcastChangedChunks",
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/server/level/ChunkHolder;getTickingChunk()Lnet/minecraft/world/level/chunk/LevelChunk;")
)
private LevelChunk redirectTickingChunk(final ChunkHolder instance) {
return instance.getChunkToSend();
}
/**
* @reason Perform mid-tick chunk task processing during chunk tick
* @author Spottedleaf

View File

@@ -85,11 +85,20 @@ abstract class ChunkMapMixin {
}
/**
* @reason Use nearby players to avoid iterating over all online players
* @reason Avoid checking first if there are nearby players, as we make internal perform this implicitly.
* @author Spottedleaf
*/
@Overwrite
public boolean anyPlayerCloseEnoughForSpawning(final ChunkPos pos) {
return this.anyPlayerCloseEnoughForSpawningInternal(pos);
}
/**
* @reason Use nearby players to avoid iterating over all online players
* @author Spottedleaf
*/
@Overwrite
public boolean anyPlayerCloseEnoughForSpawningInternal(final ChunkPos pos) {
final ReferenceList<ServerPlayer> players = ((ChunkSystemServerLevel)this.level).moonrise$getNearbyPlayers().getPlayers(
pos, NearbyPlayers.NearbyMapType.SPAWN_RANGE
);

View File

@@ -4,6 +4,7 @@ import ca.spottedleaf.moonrise.common.misc.PositionCountingAreaMap;
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickConstants;
import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickDistanceManager;
import it.unimi.dsi.fastutil.longs.LongIterator;
import net.minecraft.core.SectionPos;
import net.minecraft.server.level.DistanceManager;
import net.minecraft.server.level.ServerPlayer;
@@ -106,4 +107,13 @@ abstract class DistanceManagerMixin implements ChunkTickDistanceManager {
public boolean hasPlayersNearby(final long pos) {
return this.spawnChunkTracker.hasObjectsNear(CoordinateUtils.getChunkX(pos), CoordinateUtils.getChunkZ(pos));
}
/**
* @reason Use spawnChunkTracker instead
* @author Spottedleaf
*/
@Overwrite
public LongIterator getSpawnCandidateChunks() {
return this.spawnChunkTracker.getPositions().iterator();
}
}

View File

@@ -2,7 +2,7 @@ package ca.spottedleaf.moonrise.mixin.chunk_tick_iteration;
import ca.spottedleaf.moonrise.common.list.ReferenceList;
import ca.spottedleaf.moonrise.common.misc.NearbyPlayers;
import ca.spottedleaf.moonrise.common.util.SimpleRandom;
import ca.spottedleaf.moonrise.common.util.SimpleThreadUnsafeRandom;
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkData;
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunkHolder;
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk;
@@ -39,7 +39,7 @@ abstract class ServerChunkCacheMixin extends ChunkSource {
@Unique
private final SimpleRandom shuffleRandom = new SimpleRandom(0L);
private final SimpleThreadUnsafeRandom shuffleRandom = new SimpleThreadUnsafeRandom(0L);
@Unique
private boolean isChunkNearPlayer(final ChunkMap chunkMap, final ChunkPos chunkPos, final LevelChunk levelChunk) {

View File

@@ -5,16 +5,12 @@ import ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape;
import com.mojang.serialization.MapCodec;
import it.unimi.dsi.fastutil.HashCommon;
import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap;
import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.world.level.BlockGetter;
import net.minecraft.world.level.block.Block;
import net.minecraft.world.level.block.state.BlockBehaviour;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.block.state.StateHolder;
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.VoxelShape;
import org.spongepowered.asm.mixin.Mixin;
@@ -32,7 +28,7 @@ abstract class BlockStateBaseMixin extends StateHolder<Block, BlockState> implem
protected BlockBehaviour.BlockStateBase.Cache cache;
@Shadow
public abstract VoxelShape getCollisionShape(BlockGetter blockGetter, BlockPos blockPos, CollisionContext collisionContext);
public abstract boolean isAir();
@Shadow
public VoxelShape[] occlusionShapesByFace;
@@ -99,10 +95,9 @@ abstract class BlockStateBaseMixin extends StateHolder<Block, BlockState> implem
private void initCollisionState(final CallbackInfo ci) {
if (this.cache != null) {
final VoxelShape collisionShape = this.cache.collisionShape;
try {
this.constantCollisionShape = this.getCollisionShape(null, null, null);
} catch (final Throwable throwable) {
// :(
if (this.isAir()) {
this.constantCollisionShape = Shapes.empty();
} else {
this.constantCollisionShape = null;
}
this.occludesFullBlock = ((CollisionVoxelShape)collisionShape).moonrise$occludesFullBlock();

View File

@@ -15,7 +15,6 @@ import net.minecraft.world.entity.Entity;
import net.minecraft.world.level.ChunkPos;
import net.minecraft.world.level.Explosion;
import net.minecraft.world.level.ExplosionDamageCalculator;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.ServerExplosion;
import net.minecraft.world.level.block.state.BlockState;
import net.minecraft.world.level.chunk.LevelChunk;
@@ -440,7 +439,10 @@ abstract class ServerExplosionMixin {
* @author Spottedleaf
*/
@Redirect(
method = "hurtEntities",
method = {
"hurtEntities()V",
"hurtEntities(Ljava/util/List;)V" // Neo moves logic into this new method
},
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/level/ServerExplosion;getSeenPercent(Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/entity/Entity;)F"

View File

@@ -146,7 +146,7 @@ abstract class TrackedEntityMixin implements EntityTrackerTrackedEntity {
@Overwrite
public int getEffectiveRange() {
final Entity entity = this.entity;
int range = PlatformHooks.get().modifyEntityTrackingRange(entity, this.range);
int range = this.range;
if (entity.getPassengers() == ImmutableList.<Entity>of()) {
return this.scaledRange(range);

View File

@@ -1,5 +1,6 @@
package ca.spottedleaf.moonrise.mixin.loading_screen;
import ca.spottedleaf.moonrise.common.util.ConfigHolder;
import net.minecraft.client.multiplayer.LevelLoadStatusManager;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -25,6 +26,9 @@ abstract class LevelLoadStatusManagerMixin {
)
)
private void immediatelyClose(final CallbackInfo ci) {
if (!ConfigHolder.getConfig().misc.immediatelyCloseLoadingScreen) {
return;
}
if (this.status == LevelLoadStatusManager.Status.WAITING_FOR_SERVER) {
this.status = LevelLoadStatusManager.Status.LEVEL_READY;
ci.cancel();

View File

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

View File

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

View File

@@ -2,7 +2,7 @@ package ca.spottedleaf.moonrise.mixin.random_ticking;
import ca.spottedleaf.moonrise.common.PlatformHooks;
import ca.spottedleaf.moonrise.common.list.ShortList;
import ca.spottedleaf.moonrise.common.util.SimpleRandom;
import ca.spottedleaf.moonrise.common.util.SimpleThreadUnsafeRandom;
import ca.spottedleaf.moonrise.common.util.WorldUtil;
import ca.spottedleaf.moonrise.patches.block_counting.BlockCountingChunkSection;
import com.llamalad7.mixinextras.sugar.Local;
@@ -20,6 +20,7 @@ import net.minecraft.world.level.chunk.LevelChunk;
import net.minecraft.world.level.chunk.LevelChunkSection;
import net.minecraft.world.level.chunk.PalettedContainer;
import net.minecraft.world.level.dimension.DimensionType;
import net.minecraft.world.level.levelgen.RandomSupport;
import net.minecraft.world.level.material.FluidState;
import net.minecraft.world.level.storage.WritableLevelData;
import org.spongepowered.asm.mixin.Mixin;
@@ -38,7 +39,7 @@ abstract class ServerLevelMixin extends Level implements WorldGenLevel {
private static final LevelChunkSection[] EMPTY_SECTION_ARRAY = new LevelChunkSection[0];
@Unique
private final SimpleRandom simpleRandom = new SimpleRandom(0L);
private final SimpleThreadUnsafeRandom simpleRandom = new SimpleThreadUnsafeRandom(RandomSupport.generateUniqueSeed());
/**
* @reason Use faster random
@@ -72,7 +73,7 @@ abstract class ServerLevelMixin extends Level implements WorldGenLevel {
@Local(ordinal = 0, argsOnly = true) final int tickSpeed) {
final LevelChunkSection[] sections = chunk.getSections();
final int minSection = WorldUtil.getMinSection((ServerLevel)(Object)this);
final SimpleRandom simpleRandom = this.simpleRandom;
final SimpleThreadUnsafeRandom simpleRandom = this.simpleRandom;
final boolean doubleTickFluids = !PlatformHooks.get().configFixMC224294();
final ChunkPos cpos = chunk.getPos();

View File

@@ -21,6 +21,7 @@ import net.minecraft.world.level.chunk.status.ChunkStatus;
import net.minecraft.world.level.chunk.storage.RegionStorageInfo;
import net.minecraft.world.level.chunk.storage.SerializableChunkData;
import net.minecraft.world.level.lighting.LevelLightEngine;
import org.slf4j.Logger;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
@@ -46,6 +47,10 @@ abstract class SerializableChunkDataMixin {
@Final
private List<SerializableChunkData.SectionData> sectionData;
@Shadow
@Final
private static Logger LOGGER;
/**
* @reason Replace light correctness check with our own
* Our light check is versioned in case we change the light format OR fix a bug
@@ -116,33 +121,45 @@ abstract class SerializableChunkDataMixin {
final SWMRNibbleArray[] blockNibbles = StarLightEngine.getFilledEmptyLight(world);
final SWMRNibbleArray[] skyNibbles = StarLightEngine.getFilledEmptyLight(world);
for (final SerializableChunkData.SectionData sectionData : this.sectionData) {
final int y = sectionData.y();
final DataLayer blockLight = sectionData.blockLight();
final DataLayer skyLight = sectionData.skyLight();
final int blockState = ((StarlightSectionData)(Object)sectionData).starlight$getBlockLightState();
final int skyState = ((StarlightSectionData)(Object)sectionData).starlight$getSkyLightState();
if (blockState >= 0) {
if (blockLight != null) {
blockNibbles[y - minSection] = new SWMRNibbleArray(MixinWorkarounds.clone(blockLight.getData()), blockState); // clone for data safety
} else {
blockNibbles[y - minSection] = new SWMRNibbleArray(null, blockState);
}
}
if (skyState >= 0 && hasSkyLight) {
if (skyLight != null) {
skyNibbles[y - minSection] = new SWMRNibbleArray(MixinWorkarounds.clone(skyLight.getData()), skyState); // clone for data safety
} else {
skyNibbles[y - minSection] = new SWMRNibbleArray(null, skyState);
}
}
if (!this.lightCorrect) {
((StarlightChunk)ret).starlight$setBlockNibbles(blockNibbles);
((StarlightChunk)ret).starlight$setSkyNibbles(skyNibbles);
return;
}
((StarlightChunk)ret).starlight$setBlockNibbles(blockNibbles);
((StarlightChunk)ret).starlight$setSkyNibbles(skyNibbles);
try {
for (final SerializableChunkData.SectionData sectionData : this.sectionData) {
final int y = sectionData.y();
final DataLayer blockLight = sectionData.blockLight();
final DataLayer skyLight = sectionData.skyLight();
final int blockState = ((StarlightSectionData)(Object)sectionData).starlight$getBlockLightState();
final int skyState = ((StarlightSectionData)(Object)sectionData).starlight$getSkyLightState();
if (blockState >= 0) {
if (blockLight != null) {
blockNibbles[y - minSection] = new SWMRNibbleArray(MixinWorkarounds.clone(blockLight.getData()), blockState); // clone for data safety
} else {
blockNibbles[y - minSection] = new SWMRNibbleArray(null, blockState);
}
}
if (skyState >= 0 && hasSkyLight) {
if (skyLight != null) {
skyNibbles[y - minSection] = new SWMRNibbleArray(MixinWorkarounds.clone(skyLight.getData()), skyState); // clone for data safety
} else {
skyNibbles[y - minSection] = new SWMRNibbleArray(null, skyState);
}
}
}
((StarlightChunk)ret).starlight$setBlockNibbles(blockNibbles);
((StarlightChunk)ret).starlight$setSkyNibbles(skyNibbles);
} catch (final Throwable thr) {
ret.setLightCorrect(false);
LOGGER.error("Failed to parse light data for chunk " + ret.getPos() + " in world '" + WorldUtil.getWorldName(world) + "'", thr);
}
}
/**

View File

@@ -9,7 +9,7 @@ import it.unimi.dsi.fastutil.objects.AbstractReference2ObjectMap;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
import it.unimi.dsi.fastutil.objects.ObjectSet;
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.Collection;
import java.util.Collections;
@@ -27,7 +27,7 @@ public final class ZeroCollidingReferenceStateTable<O, S> {
public ZeroCollidingReferenceStateTable(final Collection<Property<?>> properties) {
this.propertyToIndexer = new Int2ObjectOpenHashMap<>(properties.size());
this.properties = new ReferenceOpenHashSet<>(properties);
this.properties = new ReferenceArrayList<>(properties);
final List<Property<?>> sortedProperties = new ArrayList<>(properties);

View File

@@ -5,7 +5,7 @@ import net.minecraft.SharedConstants;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.util.datafix.DataFixTypes;
import net.minecraft.util.datafix.fixes.References;
public final class ChunkSystemConverters {
@@ -26,13 +26,13 @@ public final class ChunkSystemConverters {
public static CompoundTag convertPoiCompoundTag(final CompoundTag data, final ServerLevel world) {
final int dataVersion = getDataVersion(data, DEFAULT_POI_DATA_VERSION);
return PlatformHooks.get().convertNBT(DataFixTypes.POI_CHUNK, world.getServer().getFixerUpper(), data, dataVersion, getCurrentVersion());
return PlatformHooks.get().convertNBT(References.POI_CHUNK, world.getServer().getFixerUpper(), data, dataVersion, getCurrentVersion());
}
public static CompoundTag convertEntityChunkCompoundTag(final CompoundTag data, final ServerLevel world) {
final int dataVersion = getDataVersion(data, DEFAULT_ENTITY_CHUNK_DATA_VERSION);
return PlatformHooks.get().convertNBT(DataFixTypes.ENTITY_CHUNK, world.getServer().getFixerUpper(), data, dataVersion, getCurrentVersion());
return PlatformHooks.get().convertNBT(References.ENTITY_CHUNK, world.getServer().getFixerUpper(), data, dataVersion, getCurrentVersion());
}
private ChunkSystemConverters() {}

View File

@@ -1214,15 +1214,8 @@ public final class MoonriseRegionFileIO {
try {
writeData = this.regionDataController.startWrite(this.chunkX, this.chunkZ, write);
} catch (final Throwable thr) {
// TODO implement this?
/*if (thr instanceof RegionFileStorage.RegionFileSizeException) {
final int maxSize = RegionFile.MAX_CHUNK_SIZE / (1024 * 1024);
LOGGER.error("Chunk at (" + this.chunkX + "," + this.chunkZ + ") in '" + WorldUtil.getWorldName(this.world) + "' exceeds max size of " + maxSize + "MiB, it has been deleted from disk.");
} else */
{
failedWrite = thr instanceof IOException;
LOGGER.error("Failed to write chunk data for task: " + this.toString(), thr);
}
failedWrite = thr instanceof IOException;
LOGGER.error("Failed to write chunk data for task: " + this.toString(), thr);
}
if (writeData == null) {

View File

@@ -165,7 +165,7 @@ public final class ChunkEntitySlices {
return this.entities.size() != 0;
}
private List<Entity> getAllEntities() {
public List<Entity> getAllEntities() {
final int len = this.entities.size();
if (len == 0) {
return new ArrayList<>();

View File

@@ -1,15 +1,10 @@
package ca.spottedleaf.moonrise.patches.chunk_system.level.storage;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.level.chunk.storage.RegionFileStorage;
import java.io.IOException;
public interface ChunkSystemSectionStorage {
public CompoundTag moonrise$read(final int chunkX, final int chunkZ) throws IOException;
public void moonrise$write(final int chunkX, final int chunkZ, final CompoundTag data) throws IOException;
public RegionFileStorage moonrise$getRegionStorage();
public void moonrise$close() throws IOException;

View File

@@ -6,6 +6,7 @@ import ca.spottedleaf.moonrise.common.PlatformHooks;
import ca.spottedleaf.moonrise.common.misc.AllocatingRateLimiter;
import ca.spottedleaf.moonrise.common.misc.SingleUserAreaMap;
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
import ca.spottedleaf.moonrise.common.util.MoonriseConstants;
import ca.spottedleaf.moonrise.common.util.TickThread;
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel;
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
@@ -114,14 +115,25 @@ public final class RegionizedPlayerChunkLoader {
int sendViewDistance
) {
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);
}
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);
}
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);
}
@@ -155,16 +167,6 @@ public final class RegionizedPlayerChunkLoader {
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) {
final ServerLevel level = player.serverLevel();
final PlayerChunkLoaderData data = ((ChunkSystemServerPlayer)player).moonrise$getChunkLoader();
@@ -516,7 +518,7 @@ public final class RegionizedPlayerChunkLoader {
final int playerLoadViewDistance, final int worldLoadViewDistance) {
return Math.min(
playerTickViewDistance < 0 ? worldTickViewDistance : playerTickViewDistance,
playerLoadViewDistance < 0 ? worldLoadViewDistance : playerLoadViewDistance
playerLoadViewDistance < 0 ? (worldLoadViewDistance - 1) : (playerLoadViewDistance - 1)
);
}

View File

@@ -231,8 +231,8 @@ public final class ChunkHolderManager {
public void autoSave() {
final List<NewChunkHolder> reschedule = new ArrayList<>();
final long currentTick = this.currentTick;
final long maxSaveTime = currentTick - Math.max(1L, PlatformHooks.get().configAutoSaveInterval());
final int maxToSave = PlatformHooks.get().configMaxAutoSavePerTick();
final long maxSaveTime = currentTick - Math.max(1L, PlatformHooks.get().configAutoSaveInterval(this.world));
final int maxToSave = PlatformHooks.get().configMaxAutoSavePerTick(this.world);
for (int autoSaved = 0; autoSaved < maxToSave && !this.autoSaveQueue.isEmpty();) {
final NewChunkHolder holder = this.autoSaveQueue.first();

View File

@@ -6,7 +6,6 @@ import ca.spottedleaf.concurrentutil.executor.thread.PrioritisedThreadPool;
import ca.spottedleaf.concurrentutil.lock.ReentrantAreaLock;
import ca.spottedleaf.concurrentutil.util.ConcurrentUtil;
import ca.spottedleaf.concurrentutil.util.Priority;
import ca.spottedleaf.moonrise.common.config.moonrise.MoonriseConfig;
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
import ca.spottedleaf.moonrise.common.util.JsonUtil;
import ca.spottedleaf.moonrise.common.util.MoonriseCommon;
@@ -580,7 +579,7 @@ public final class ChunkTaskScheduler {
this.chunkHolderManager.processTicketUpdates();
}
final Consumer<ChunkAccess> loadCallback = (final ChunkAccess chunk) -> {
final Consumer<ChunkAccess> loadCallback = onComplete == null && !addTicket ? null : (final ChunkAccess chunk) -> {
try {
if (onComplete != null) {
onComplete.accept(chunk);
@@ -617,7 +616,9 @@ public final class ChunkTaskScheduler {
if (!chunkHolder.upgradeGenTarget(toStatus)) {
this.schedule(chunkX, chunkZ, toStatus, chunkHolder, tasks);
}
chunkHolder.addStatusConsumer(toStatus, loadCallback);
if (loadCallback != null) {
chunkHolder.addStatusConsumer(toStatus, loadCallback);
}
}
}
} finally {
@@ -631,7 +632,7 @@ public final class ChunkTaskScheduler {
tasks.get(i).schedule();
}
if (!scheduled) {
if (loadCallback != null && !scheduled) {
// couldn't schedule
try {
loadCallback.accept(chunk);

View File

@@ -1078,7 +1078,7 @@ public final class NewChunkHolder {
}
// Don't really have a choice but to place this hook here
PlatformHooks.get().onChunkHolderTicketChange(this.world, this, oldLevel, newLevel);
PlatformHooks.get().onChunkHolderTicketChange(this.world, this.vanillaChunkHolder, oldLevel, newLevel);
}
static final int NEIGHBOUR_RADIUS = 2;

View File

@@ -14,7 +14,9 @@ import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.vehicle.AbstractMinecart;
import net.minecraft.world.item.Item;
import net.minecraft.world.level.CollisionGetter;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.block.state.BlockState;
@@ -1943,6 +1945,7 @@ public final class CollisionUtil {
final BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos();
final CollisionContext collisionShape = new LazyEntityCollisionContext(entity);
final boolean useEntityCollisionShape = LazyEntityCollisionContext.useEntityCollisionShape(world, entity);
// special cases:
if (minBlockY > maxBlockY) {
@@ -2028,7 +2031,10 @@ public final class CollisionUtil {
VoxelShape blockCollision = ((CollisionBlockState)blockData).moonrise$getConstantContextCollisionShape();
if (edgeCount == 0 || ((edgeCount != 1 || blockData.hasLargeCollisionShape()) && (edgeCount != 2 || blockData.getBlock() == Blocks.MOVING_PISTON))) {
if (blockCollision == null) {
if (useEntityCollisionShape) {
mutablePos.set(blockX, blockY, blockZ);
blockCollision = collisionShape.getCollisionShape(blockData, world, mutablePos);
} else if (blockCollision == null) {
mutablePos.set(blockX, blockY, blockZ);
blockCollision = blockData.getCollisionShape(world, mutablePos, collisionShape);
}
@@ -2150,6 +2156,10 @@ public final class CollisionUtil {
super(false, 0.0, null, null, entity);
}
public static boolean useEntityCollisionShape(final Level world, final Entity entity) {
return entity instanceof AbstractMinecart && AbstractMinecart.useExperimentalMovement(world);
}
public boolean isDelegated() {
final boolean delegated = this.delegated;
this.delegated = false;
@@ -2158,10 +2168,16 @@ public final class CollisionUtil {
public CollisionContext getDelegate() {
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;
}
@Override
public Entity getEntity() {
this.getDelegate();
return super.getEntity();
}
@Override
public boolean isDescending() {
return this.getDelegate().isDescending();
@@ -2181,6 +2197,11 @@ public final class CollisionUtil {
public boolean canStandOnFluid(final FluidState state, final FluidState fluidState) {
return this.getDelegate().canStandOnFluid(state, fluidState);
}
@Override
public VoxelShape getCollisionShape(final BlockState blockState, final CollisionGetter collisionGetter, final BlockPos blockPos) {
return this.getDelegate().getCollisionShape(blockState, collisionGetter, blockPos);
}
}
private CollisionUtil() {

View File

@@ -237,7 +237,7 @@ public final class MoonriseCommand {
return Command.SINGLE_SUCCESS;
} else {
ctx.getSource().sendFailure(
Component.literal("Reloaded Moonrise config.")
Component.literal("Failed to reload Moonrise config, see logs.")
.withStyle(ChatFormatting.RED)
);
return 0;

View File

@@ -1,143 +1,145 @@
{
"required": true,
"minVersion": "0.8",
"package": "ca.spottedleaf.moonrise.mixin",
"compatibilityLevel": "JAVA_21",
"mixins": [
"bitstorage.SimpleBitStorageMixin",
"bitstorage.ZeroBitStorageMixin",
"block_counting.BitStorageMixin",
"block_counting.LevelChunkSectionMixin",
"block_counting.SimpleBitStorageMixin",
"block_counting.ZeroBitStorageMixin",
"block_entity_remove.LevelMixin",
"blockstate_propertyaccess.BooleanPropertyMixin",
"blockstate_propertyaccess.EnumPropertyMixin",
"blockstate_propertyaccess.IntegerPropertyMixin",
"blockstate_propertyaccess.PropertyMixin",
"blockstate_propertyaccess.StateHolderMixin",
"chunk_system.ChunkBufferMixin",
"chunk_system.ChunkGeneratorMixin",
"chunk_system.ChunkHolderMixin",
"chunk_system.ChunkMap$DistanceManagerMixin",
"chunk_system.ChunkMapMixin",
"chunk_system.ChunkPyramidMixin",
"chunk_system.ChunkStatusMixin",
"chunk_system.ChunkStepMixin",
"chunk_system.ChunkStorageMixin",
"chunk_system.DistanceManagerMixin",
"chunk_system.EntityGetterMixin",
"chunk_system.EntityMixin",
"chunk_system.EntityTickListMixin",
"chunk_system.GenerationChunkHolderMixin",
"chunk_system.LevelChunkMixin",
"chunk_system.LevelChunkTicksMixin",
"chunk_system.LevelMixin",
"chunk_system.LevelReaderMixin",
"chunk_system.MinecraftServerMixin",
"chunk_system.NoiseBasedChunkGeneratorMixin",
"chunk_system.PlayerListMixin",
"chunk_system.PoiManagerMixin",
"chunk_system.PoiSectionMixin",
"chunk_system.RegionFileMixin",
"chunk_system.RegionFileStorageMixin",
"chunk_system.SectionStorageMixin",
"chunk_system.SerializableChunkDataMixin",
"chunk_system.ServerChunkCache$MainThreadExecutorMixin",
"chunk_system.ServerChunkCacheMixin",
"chunk_system.ServerLevelMixin",
"chunk_system.ServerPlayerMixin",
"chunk_system.SortedArraySetMixin",
"chunk_system.StructureCheckMixin",
"chunk_system.StructureTemplate$PaletteMixin",
"chunk_system.TicketMixin",
"chunk_tick_iteration.ChunkMapMixin",
"chunk_tick_iteration.DistanceManagerMixin",
"chunk_tick_iteration.ServerChunkCacheMixin",
"chunk_tick_iteration.ServerLevelMixin",
"collisions.ArmorStandMixin",
"collisions.ArrayVoxelShapeMixin",
"collisions.BitSetDiscreteVoxelShapeMixin",
"collisions.BlockMixin",
"collisions.BlockPosMixin",
"collisions.BlockStateBaseMixin",
"collisions.CubeVoxelShapeMixin",
"collisions.DirectionMixin",
"collisions.DiscreteVoxelShapeMixin",
"collisions.EntityGetterMixin",
"collisions.EntityMixin",
"collisions.LevelMixin",
"collisions.ServerEntityMixin",
"collisions.ServerExplosionMixin",
"collisions.ShapesMixin",
"collisions.SliceShapeMixin",
"collisions.VoxelShapeMixin",
"command.CommandsMixin",
"config.MinecraftServerMixin",
"end_island.DensityFunctions$EndIslandDensityFunctionMixin",
"entity_tracker.ChunkMapMixin",
"entity_tracker.EntityMixin",
"entity_tracker.TrackedEntityMixin",
"fast_palette.CrudeIncrementalIntIdentityHashBiMapMixin",
"fast_palette.HashMapPaletteMixin",
"fast_palette.LinearPaletteMixin",
"fast_palette.PalettedContainer$DataMixin",
"fast_palette.PalettedContainerMixin",
"fast_palette.PaletteMixin",
"fast_palette.SingleValuePaletteMixin",
"fluid.FlowingFluidMixin",
"fluid.FluidStateMixin",
"fluid.MappedRegistryMixin",
"getblock.ChunkAccessMixin",
"getblock.LevelChunkMixin",
"getblock.LevelMixin",
"keep_alive_client.ServerGamePacketListenerImplMixin",
"mob_spawning.EntityTypeMixin",
"mob_spawning.LocalMobCapCalculator$MobCountsMixin",
"mob_spawning.MobSpawnSettingsMixin",
"mob_spawning.NaturalSpawnerMixin",
"poi_lookup.AcquirePoiMixin",
"poi_lookup.PoiManagerMixin",
"poi_lookup.PortalForcerMixin",
"random_ticking.BiomeManagerMixin",
"random_ticking.BiomeMixin",
"random_ticking.LevelMixin",
"random_ticking.ServerLevelMixin",
"serverlist.ConnectionMixin",
"starlight.blockstate.BlockStateBaseMixin",
"starlight.chunk.ChunkAccessMixin",
"starlight.chunk.EmptyLevelChunkMixin",
"starlight.chunk.ImposterProtoChunkMixin",
"starlight.chunk.LevelChunkMixin",
"starlight.chunk.ProtoChunkMixin",
"starlight.lightengine.LevelLightEngineMixin",
"starlight.lightengine.ThreadedLevelLightEngineMixin",
"starlight.world.SerializableChunkData$SectionData",
"starlight.world.SerializableChunkDataMixin",
"starlight.world.WorldGenRegionMixin",
"util_thread_counts.UtilMixin",
"util_threading_detector.PalettedContainerMixin",
"util_threading_detector.ThreadingDetectorMixin",
"util_time_source.UtilMixin"
],
"client": [
"chunk_system.ClientLevelMixin",
"chunk_system.OptionsMixin",
"collisions.LiquidBlockRendererMixin",
"collisions.ParticleMixin",
"config.MinecraftMixin",
"loading_screen.LevelLoadStatusManagerMixin",
"profiler.MinecraftMixin",
"render.SectionRenderDispatcherMixin",
"serverlist.ClientConnectionMixin",
"serverlist.ServerAddressResolverMixin",
"serverlist.ServerSelectionListMixin",
"starlight.multiplayer.ClientPacketListenerMixin"
],
"injectors": {
"defaultRequire": 1
},
"overwrites": {
"conformVisibility": true
"required": true,
"minVersion": "0.8",
"package": "ca.spottedleaf.moonrise.mixin",
"compatibilityLevel": "JAVA_21",
"mixins": [
"bitstorage.SimpleBitStorageMixin",
"bitstorage.ZeroBitStorageMixin",
"block_counting.BitStorageMixin",
"block_counting.LevelChunkSectionMixin",
"block_counting.SimpleBitStorageMixin",
"block_counting.ZeroBitStorageMixin",
"block_entity_remove.LevelMixin",
"blockstate_propertyaccess.BooleanPropertyMixin",
"blockstate_propertyaccess.EnumPropertyMixin",
"blockstate_propertyaccess.IntegerPropertyMixin",
"blockstate_propertyaccess.PropertyMixin",
"blockstate_propertyaccess.StateHolderMixin",
"chunk_system.ChunkBufferMixin",
"chunk_system.ChunkGeneratorMixin",
"chunk_system.ChunkHolderMixin",
"chunk_system.ChunkMap$DistanceManagerMixin",
"chunk_system.ChunkMapMixin",
"chunk_system.ChunkPyramidMixin",
"chunk_system.ChunkStatusMixin",
"chunk_system.ChunkStepMixin",
"chunk_system.ChunkStorageMixin",
"chunk_system.DistanceManagerMixin",
"chunk_system.EntityGetterMixin",
"chunk_system.EntityMixin",
"chunk_system.EntityTickListMixin",
"chunk_system.GenerationChunkHolderMixin",
"chunk_system.LevelChunkMixin",
"chunk_system.LevelChunkTicksMixin",
"chunk_system.LevelMixin",
"chunk_system.LevelReaderMixin",
"chunk_system.MinecraftServerMixin",
"chunk_system.NoiseBasedChunkGeneratorMixin",
"chunk_system.PlayerListMixin",
"chunk_system.PoiManagerMixin",
"chunk_system.PoiSectionMixin",
"chunk_system.RegionFileMixin",
"chunk_system.RegionFileStorageMixin",
"chunk_system.SectionStorageMixin",
"chunk_system.SerializableChunkDataMixin",
"chunk_system.ServerChunkCache$MainThreadExecutorMixin",
"chunk_system.ServerChunkCacheMixin",
"chunk_system.ServerLevelMixin",
"chunk_system.ServerPlayerMixin",
"chunk_system.SortedArraySetMixin",
"chunk_system.StructureCheckMixin",
"chunk_system.StructureTemplate$PaletteMixin",
"chunk_system.TicketMixin",
"chunk_tick_iteration.ChunkMapMixin",
"chunk_tick_iteration.DistanceManagerMixin",
"chunk_tick_iteration.ServerChunkCacheMixin",
"chunk_tick_iteration.ServerLevelMixin",
"collisions.ArmorStandMixin",
"collisions.ArrayVoxelShapeMixin",
"collisions.BitSetDiscreteVoxelShapeMixin",
"collisions.BlockMixin",
"collisions.BlockPosMixin",
"collisions.BlockStateBaseMixin",
"collisions.CubeVoxelShapeMixin",
"collisions.DirectionMixin",
"collisions.DiscreteVoxelShapeMixin",
"collisions.EntityGetterMixin",
"collisions.EntityMixin",
"collisions.LevelMixin",
"collisions.ServerEntityMixin",
"collisions.ServerExplosionMixin",
"collisions.ShapesMixin",
"collisions.SliceShapeMixin",
"collisions.VoxelShapeMixin",
"command.CommandsMixin",
"config.MinecraftServerMixin",
"end_island.DensityFunctions$EndIslandDensityFunctionMixin",
"entity_tracker.ChunkMapMixin",
"entity_tracker.EntityMixin",
"entity_tracker.TrackedEntityMixin",
"fast_palette.CrudeIncrementalIntIdentityHashBiMapMixin",
"fast_palette.HashMapPaletteMixin",
"fast_palette.LinearPaletteMixin",
"fast_palette.PalettedContainer$DataMixin",
"fast_palette.PalettedContainerMixin",
"fast_palette.PaletteMixin",
"fast_palette.SingleValuePaletteMixin",
"fluid.FlowingFluidMixin",
"fluid.FluidStateMixin",
"fluid.MappedRegistryMixin",
"getblock.ChunkAccessMixin",
"getblock.LevelChunkMixin",
"getblock.LevelMixin",
"keep_alive_client.ServerGamePacketListenerImplMixin",
"mob_spawning.EntityTypeMixin",
"mob_spawning.LocalMobCapCalculator$MobCountsMixin",
"mob_spawning.MobSpawnSettingsMixin",
"mob_spawning.NaturalSpawnerMixin",
"poi_lookup.AcquirePoiMixin",
"poi_lookup.PoiManagerMixin",
"poi_lookup.PortalForcerMixin",
"random.EntityMixin",
"random.LevelMixin",
"random_ticking.BiomeManagerMixin",
"random_ticking.BiomeMixin",
"random_ticking.LevelMixin",
"random_ticking.ServerLevelMixin",
"serverlist.ConnectionMixin",
"starlight.blockstate.BlockStateBaseMixin",
"starlight.chunk.ChunkAccessMixin",
"starlight.chunk.EmptyLevelChunkMixin",
"starlight.chunk.ImposterProtoChunkMixin",
"starlight.chunk.LevelChunkMixin",
"starlight.chunk.ProtoChunkMixin",
"starlight.lightengine.LevelLightEngineMixin",
"starlight.lightengine.ThreadedLevelLightEngineMixin",
"starlight.world.SerializableChunkData$SectionData",
"starlight.world.SerializableChunkDataMixin",
"starlight.world.WorldGenRegionMixin",
"util_thread_counts.UtilMixin",
"util_threading_detector.PalettedContainerMixin",
"util_threading_detector.ThreadingDetectorMixin",
"util_time_source.UtilMixin"
],
"client": [
"chunk_system.ClientLevelMixin",
"chunk_system.OptionsMixin",
"collisions.LiquidBlockRendererMixin",
"collisions.ParticleMixin",
"config.MinecraftMixin",
"loading_screen.LevelLoadStatusManagerMixin",
"profiler.MinecraftMixin",
"render.SectionRenderDispatcherMixin",
"serverlist.ClientConnectionMixin",
"serverlist.ServerAddressResolverMixin",
"serverlist.ServerSelectionListMixin",
"starlight.multiplayer.ClientPacketListenerMixin"
],
"injectors": {
"defaultRequire": 1
},
"overwrites": {
"conformVisibility": true
}
}