Compare commits
93 Commits
v0.1.0-bet
...
v0.2.0-bet
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bad5cae4d8 | ||
|
|
e3b1502bb6 | ||
|
|
54fc964987 | ||
|
|
0cbc9aa1a1 | ||
|
|
19e2136ae1 | ||
|
|
126cc03747 | ||
|
|
ceb4936d9d | ||
|
|
3cb888e894 | ||
|
|
7bedc1a7de | ||
|
|
718f6e1369 | ||
|
|
da9ab708a6 | ||
|
|
f22335f0b6 | ||
|
|
a3f2328000 | ||
|
|
529b9a44bb | ||
|
|
1e9a6504a1 | ||
|
|
9c46dcbb94 | ||
|
|
9a1e04389a | ||
|
|
29084d8e3f | ||
|
|
41790ecf1a | ||
|
|
8af7bccdfd | ||
|
|
5f9b3571f8 | ||
|
|
9adfb2514d | ||
|
|
bf2cd1c571 | ||
|
|
dad9a5c2eb | ||
|
|
a3acd46ee1 | ||
|
|
3e8cb80336 | ||
|
|
5c3e713be7 | ||
|
|
284631c321 | ||
|
|
666c4cb1a3 | ||
|
|
19b523eecd | ||
|
|
4a748778dc | ||
|
|
a70073ae3e | ||
|
|
6724814c02 | ||
|
|
f32a08738e | ||
|
|
56e48ed069 | ||
|
|
9da99576a6 | ||
|
|
dfbe1bcf8b | ||
|
|
ae29196221 | ||
|
|
f1eb61cc51 | ||
|
|
58c933938f | ||
|
|
1dc3cb5f14 | ||
|
|
2acfc6a68e | ||
|
|
c22538c364 | ||
|
|
e244c60375 | ||
|
|
65253d5199 | ||
|
|
6e82b034b7 | ||
|
|
a7cd78e63b | ||
|
|
05ba7066d9 | ||
|
|
340ac4e8f5 | ||
|
|
a4770aca2b | ||
|
|
a8d4ce526b | ||
|
|
2acd5cc213 | ||
|
|
07dce0ffe6 | ||
|
|
c2e2f0b9f2 | ||
|
|
1374ea34ee | ||
|
|
fef4872a3a | ||
|
|
a9678c76eb | ||
|
|
bafa195546 | ||
|
|
04c6e6c01a | ||
|
|
7351872730 | ||
|
|
77b977ac17 | ||
|
|
f0d122f358 | ||
|
|
aa240eb16d | ||
|
|
f9c99d1e32 | ||
|
|
3fa0ff67a7 | ||
|
|
f7d9e5b422 | ||
|
|
5d1975154b | ||
|
|
d21fa9f48c | ||
|
|
1c150afe83 | ||
|
|
d9988c86f4 | ||
|
|
0958439e54 | ||
|
|
8d9d6488e8 | ||
|
|
8ba83bc9c2 | ||
|
|
0c60a6ac08 | ||
|
|
d404dbc6c5 | ||
|
|
8d456890f1 | ||
|
|
23eddfe918 | ||
|
|
55ff406372 | ||
|
|
3e25a2f4aa | ||
|
|
cfa80c4488 | ||
|
|
453b635ef2 | ||
|
|
e07e4fdcc4 | ||
|
|
81bb9701da | ||
|
|
d0a7f9af62 | ||
|
|
fe7bcfc56a | ||
|
|
44f8058b09 | ||
|
|
d1f8e81913 | ||
|
|
dcef1320b2 | ||
|
|
179b45cac5 | ||
|
|
89e9cd52e4 | ||
|
|
38c3f5fd80 | ||
|
|
98e8a08e85 | ||
|
|
caf2960b6b |
53
.github/ISSUE_TEMPLATE/a_incompatibility.yml
vendored
Normal file
53
.github/ISSUE_TEMPLATE/a_incompatibility.yml
vendored
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
name: Mod Incompatibility
|
||||||
|
description: Report an incompatibility with another mod.
|
||||||
|
title: '[Incompatibility: <NeoForge/Fabric/NeoForge & Fabric>]: Mod Name'
|
||||||
|
labels:
|
||||||
|
- mod-incompatibility
|
||||||
|
- needs-triage
|
||||||
|
body:
|
||||||
|
- type: input
|
||||||
|
id: mc_ver
|
||||||
|
attributes:
|
||||||
|
label: Minecraft Version
|
||||||
|
placeholder: e.g. 1.21.1 or 1.21.2
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: moonrise_ver
|
||||||
|
attributes:
|
||||||
|
label: Moonrise Version
|
||||||
|
placeholder: e.g. 0.1.0-beta.6 or Git commit hash
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
id: mod_loader
|
||||||
|
attributes:
|
||||||
|
label: Mod Loader
|
||||||
|
description: >-
|
||||||
|
The mod loader(s) this conflict happens with. When selecting 'Both' it
|
||||||
|
is expected you will submit logs for both as well. Be sure to update the
|
||||||
|
issue title.
|
||||||
|
options:
|
||||||
|
- NeoForge
|
||||||
|
- Fabric
|
||||||
|
- Both (NeoForge and Fabric)
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: logs_crashes
|
||||||
|
attributes:
|
||||||
|
label: Logs and Crash Reports
|
||||||
|
description: >-
|
||||||
|
Include links to all relevant logs and crash reports (prefer using
|
||||||
|
https://gist.github.com/ or https://mclo.gs/). In case this is not
|
||||||
|
applicable fill in 'N/A' (it is expected you will provide context
|
||||||
|
below).
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: context
|
||||||
|
attributes:
|
||||||
|
label: Additional Context
|
||||||
|
description: Provide any relevant context, including version of the conflicting mod.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
55
.github/ISSUE_TEMPLATE/b_bug.yml
vendored
Normal file
55
.github/ISSUE_TEMPLATE/b_bug.yml
vendored
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
name: Bug Report
|
||||||
|
description: Report a bug or Vanilla behavior parity issue.
|
||||||
|
title: '[Bug: <NeoForge/Fabric/NeoForge & Fabric>]: Short description'
|
||||||
|
labels:
|
||||||
|
- bug
|
||||||
|
- needs-triage
|
||||||
|
body:
|
||||||
|
- type: input
|
||||||
|
id: mc_ver
|
||||||
|
attributes:
|
||||||
|
label: Minecraft Version
|
||||||
|
placeholder: e.g. 1.21.1 or 1.21.2
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: moonrise_ver
|
||||||
|
attributes:
|
||||||
|
label: Moonrise Version
|
||||||
|
placeholder: e.g. 0.1.0-beta.6 or Git commit hash
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
id: mod_loader
|
||||||
|
attributes:
|
||||||
|
label: Mod Loader
|
||||||
|
description: >-
|
||||||
|
The mod loader(s) this bug happens with. When selecting 'Both' it
|
||||||
|
is expected you will submit logs for both as well. Be sure to update the
|
||||||
|
issue title.
|
||||||
|
options:
|
||||||
|
- NeoForge
|
||||||
|
- Fabric
|
||||||
|
- Both (NeoForge and Fabric)
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: logs_crashes
|
||||||
|
attributes:
|
||||||
|
label: Logs and Crash Reports
|
||||||
|
description: >-
|
||||||
|
Include links to all relevant logs and crash reports (prefer using
|
||||||
|
https://gist.github.com/ or https://mclo.gs/). In case this is not
|
||||||
|
applicable fill in 'N/A' (it is expected you will provide context
|
||||||
|
below).
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: context
|
||||||
|
attributes:
|
||||||
|
label: Additional Context
|
||||||
|
description: >-
|
||||||
|
Provide any relevant context, including expected vs. actual behavior,
|
||||||
|
and reproduction steps.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
65
.github/ISSUE_TEMPLATE/c_performance.yml
vendored
Normal file
65
.github/ISSUE_TEMPLATE/c_performance.yml
vendored
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
name: Performance Problem
|
||||||
|
description: Report a performance problem that doesn't fall under the bug category.
|
||||||
|
title: '[Performance: <NeoForge/Fabric/NeoForge & Fabric>]: Short description'
|
||||||
|
labels:
|
||||||
|
- performance
|
||||||
|
- needs-triage
|
||||||
|
body:
|
||||||
|
- type: input
|
||||||
|
id: mc_ver
|
||||||
|
attributes:
|
||||||
|
label: Minecraft Version
|
||||||
|
placeholder: e.g. 1.21.1, 1.21.2
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: moonrise_ver
|
||||||
|
attributes:
|
||||||
|
label: Moonrise Version
|
||||||
|
placeholder: e.g. 0.1.0-beta.6 or Git commit hash
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
id: mod_loader
|
||||||
|
attributes:
|
||||||
|
label: Mod Loader
|
||||||
|
description: >-
|
||||||
|
The mod loader(s) this bug happens with. When selecting 'Both' it is
|
||||||
|
expected you have tested both as well. Be sure to update the issue
|
||||||
|
title.
|
||||||
|
options:
|
||||||
|
- NeoForge
|
||||||
|
- Fabric
|
||||||
|
- Both (NeoForge and Fabric)
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: logs_crashes
|
||||||
|
attributes:
|
||||||
|
label: Logs and Crash Reports
|
||||||
|
description: >-
|
||||||
|
Include links to all relevant logs and crash reports (prefer using
|
||||||
|
https://gist.github.com/ or https://mclo.gs/). In case this is not
|
||||||
|
applicable fill in 'N/A' (it is expected you will provide context
|
||||||
|
below).
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: profiler
|
||||||
|
attributes:
|
||||||
|
label: Profiler Data
|
||||||
|
description: >-
|
||||||
|
Provide profiler data showing the problem, from Spark or other tools. In
|
||||||
|
case this is not applicable fill in 'N/A' (it is expected you will
|
||||||
|
provide context below).
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: context
|
||||||
|
attributes:
|
||||||
|
label: Additional Context
|
||||||
|
description: >-
|
||||||
|
Provide any relevant context, including reproduction steps, world data,
|
||||||
|
videos, etc.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
5
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: Discord
|
||||||
|
url: https://discord.gg/tuinity
|
||||||
|
about: If you are unsure about something or have general questions, ask in our Discord before opening an issue.
|
||||||
34
.github/ISSUE_TEMPLATE/d_feature.yml
vendored
Normal file
34
.github/ISSUE_TEMPLATE/d_feature.yml
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
name: Feature Request
|
||||||
|
description: Request a new feature.
|
||||||
|
title: '[Feature Request: <NeoForge/Fabric/NeoForge & Fabric>]: Short description'
|
||||||
|
labels:
|
||||||
|
- enhancement
|
||||||
|
- needs-triage
|
||||||
|
body:
|
||||||
|
- type: input
|
||||||
|
id: mc_ver
|
||||||
|
attributes:
|
||||||
|
label: Minecraft Version
|
||||||
|
placeholder: e.g. 1.21.1, 1.21.2
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
id: mod_loader
|
||||||
|
attributes:
|
||||||
|
label: Mod Loader
|
||||||
|
description: The mod loader(s) this feature request is relevant for.
|
||||||
|
options:
|
||||||
|
- NeoForge
|
||||||
|
- Fabric
|
||||||
|
- Both (NeoForge and Fabric)
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: context
|
||||||
|
attributes:
|
||||||
|
label: Description
|
||||||
|
description: >-
|
||||||
|
Describe the feature request in detail, including alternatives
|
||||||
|
considered.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
9
.github/workflows/build.yml
vendored
9
.github/workflows/build.yml
vendored
@@ -35,7 +35,14 @@ jobs:
|
|||||||
run: ./installConcurrentUtil.sh
|
run: ./installConcurrentUtil.sh
|
||||||
- name: "execute gradle build"
|
- name: "execute gradle build"
|
||||||
run: ./gradlew build
|
run: ./gradlew build
|
||||||
- name: Publish (Pre-)Release to Modrinth
|
- name: Determine Snapshot Status
|
||||||
|
run: |
|
||||||
|
if [ "$(./gradlew properties | awk '/^version:/ { print $2; }' | grep '\-SNAPSHOT')" ]; then
|
||||||
|
echo "STATUS=snapshot" >> $GITHUB_ENV
|
||||||
|
else
|
||||||
|
echo "STATUS=release" >> $GITHUB_ENV
|
||||||
|
fi
|
||||||
|
- name: Publish (Pre-)Release to Modrinth & CurseForge
|
||||||
if: "${{ env.STATUS == 'release' && github.event_name == 'release' }}"
|
if: "${{ env.STATUS == 'release' && github.event_name == 'release' }}"
|
||||||
run: ./gradlew :moonrise-fabric:publishMods :moonrise-neoforge:publishMods
|
run: ./gradlew :moonrise-fabric:publishMods :moonrise-neoforge:publishMods
|
||||||
env:
|
env:
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
Moonrise
|
Moonrise
|
||||||
==
|
==
|
||||||
|
[](https://modrinth.com/mod/moonrise-opt)
|
||||||
|
[](https://www.curseforge.com/minecraft/mc-mods/moonrise)
|
||||||
|
[](https://github.com/Tuinity/Moonrise/releases)
|
||||||
|
[](LICENSE.md)
|
||||||
|
|
||||||
Fabric/NeoForge mod for optimising performance of the integrated (singleplayer/LAN) and dedicated server.
|
Fabric/NeoForge mod for optimising performance of the integrated (singleplayer/LAN) and dedicated server.
|
||||||
|
|
||||||
|
|
||||||
@@ -7,13 +12,13 @@ Fabric/NeoForge mod for optimising performance of the integrated (singleplayer/L
|
|||||||
Moonrise aims to optimise the game *without changing Vanilla behavior*. If you find that there are changes to Vanilla behavior,
|
Moonrise aims to optimise the game *without changing Vanilla behavior*. If you find that there are changes to Vanilla behavior,
|
||||||
please open an issue.
|
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:
|
patches. Listed below are notable patches:
|
||||||
|
- [Starlight](https://github.com/PaperMC/Starlight/)
|
||||||
- Chunk system rewrite
|
- Chunk system rewrite
|
||||||
- Collision optimisations
|
- Collision optimisations
|
||||||
- Entity tracker optimisations
|
- Entity tracker optimisations
|
||||||
- Random ticking optimisations
|
- Random ticking optimisations
|
||||||
- [Starlight](https://github.com/PaperMC/Starlight/)
|
|
||||||
|
|
||||||
## Known Compatibility Issues
|
## Known Compatibility Issues
|
||||||
| Mod | Status |
|
| Mod | Status |
|
||||||
|
|||||||
34
build.gradle
34
build.gradle
@@ -98,7 +98,8 @@ subprojects {
|
|||||||
}
|
}
|
||||||
loom.runs.all {
|
loom.runs.all {
|
||||||
ideConfigGenerated true
|
ideConfigGenerated true
|
||||||
// property "mixin.debug", "true"
|
property "mixin.debug", "true"
|
||||||
|
property "Moonrise.MaxViewDistance", "128"
|
||||||
}
|
}
|
||||||
|
|
||||||
plugins.apply("me.modmuss50.mod-publish-plugin")
|
plugins.apply("me.modmuss50.mod-publish-plugin")
|
||||||
@@ -112,18 +113,45 @@ subprojects {
|
|||||||
}
|
}
|
||||||
changelog = providers.environmentVariable("RELEASE_NOTES")
|
changelog = providers.environmentVariable("RELEASE_NOTES")
|
||||||
|
|
||||||
|
List<String> supportedMcVersions = rootProject.supported_minecraft_versions.split(',')
|
||||||
|
|
||||||
modrinth {
|
modrinth {
|
||||||
projectId = "KOHu7RCS"
|
projectId = "KOHu7RCS"
|
||||||
accessToken = providers.environmentVariable("MODRINTH_TOKEN")
|
accessToken = providers.environmentVariable("MODRINTH_TOKEN")
|
||||||
minecraftVersions = [rootProject.minecraft_version]
|
minecraftVersions = supportedMcVersions
|
||||||
}
|
}
|
||||||
|
|
||||||
curseforge {
|
curseforge {
|
||||||
projectId = "1096335"
|
projectId = "1096335"
|
||||||
accessToken = providers.environmentVariable("CURSEFORGE_TOKEN")
|
accessToken = providers.environmentVariable("CURSEFORGE_TOKEN")
|
||||||
minecraftVersions = [rootProject.minecraft_version]
|
minecraftVersions = supportedMcVersions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Setup a run with lithium for compatibility testing
|
||||||
|
sourceSets.create("lithium")
|
||||||
|
configurations.create("lithium")
|
||||||
|
loom {
|
||||||
|
createRemapConfigurations(sourceSets.lithium)
|
||||||
|
runs {
|
||||||
|
register("lithiumClient") {
|
||||||
|
client()
|
||||||
|
property "mixin.debug", "true"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tasks.named("runLithiumClient", net.fabricmc.loom.task.RunGameTask.class) {
|
||||||
|
getClasspath().from(configurations.modRuntimeClasspathLithiumMapped)
|
||||||
|
}
|
||||||
|
dependencies {
|
||||||
|
String coordinates = "maven.modrinth:lithium:"
|
||||||
|
if (getProject().name == "Moonrise-NeoForge") {
|
||||||
|
coordinates += rootProject.neo_lithium_version
|
||||||
|
} else {
|
||||||
|
coordinates += rootProject.fabric_lithium_version
|
||||||
|
}
|
||||||
|
modLithiumRuntimeOnly coordinates
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loom.runs.all {
|
loom.runs.all {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("xyz.jpenilla.quiet-architectury-loom")
|
id("xyz.jpenilla.quiet-architectury-loom")
|
||||||
id 'maven-publish'
|
id 'maven-publish'
|
||||||
id 'io.github.goooler.shadow'
|
id 'com.gradleup.shadow'
|
||||||
}
|
}
|
||||||
|
|
||||||
configurations.create("libs")
|
configurations.create("libs")
|
||||||
@@ -22,9 +22,10 @@ dependencies {
|
|||||||
|
|
||||||
modImplementation "me.shedaniel.cloth:cloth-config-fabric:${rootProject.cloth_version}"
|
modImplementation "me.shedaniel.cloth:cloth-config-fabric:${rootProject.cloth_version}"
|
||||||
include "me.shedaniel.cloth:cloth-config-fabric:${rootProject.cloth_version}"
|
include "me.shedaniel.cloth:cloth-config-fabric:${rootProject.cloth_version}"
|
||||||
modImplementation "com.terraformersmc:modmenu:11.0.1"
|
modImplementation "com.terraformersmc:modmenu:${rootProject.modmenu_version}"
|
||||||
|
|
||||||
modImplementation fabricApiLibs.command.api.v2
|
modImplementation fabricApiLibs.command.api.v2
|
||||||
|
modImplementation fabricApiLibs.lifecycle.events.v1
|
||||||
include fabricApiLibs.command.api.v2
|
include fabricApiLibs.command.api.v2
|
||||||
include fabricApiLibs.base
|
include fabricApiLibs.base
|
||||||
}
|
}
|
||||||
@@ -63,22 +64,3 @@ publishMods {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setup a run with lithium for compatibility testing
|
|
||||||
sourceSets.create("lithium")
|
|
||||||
configurations.create("lithium")
|
|
||||||
loom {
|
|
||||||
createRemapConfigurations(sourceSets.lithium)
|
|
||||||
runs {
|
|
||||||
register("lithiumClient") {
|
|
||||||
client()
|
|
||||||
property "mixin.debug", "true"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
tasks.named("runLithiumClient", net.fabricmc.loom.task.RunGameTask.class) {
|
|
||||||
getClasspath().from(configurations.modRuntimeClasspathLithiumMapped)
|
|
||||||
}
|
|
||||||
dependencies {
|
|
||||||
modLithiumRuntimeOnly "maven.modrinth:lithium:${rootProject.lithium_version}"
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -2,29 +2,38 @@ package ca.spottedleaf.moonrise.fabric;
|
|||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.PlatformHooks;
|
import ca.spottedleaf.moonrise.common.PlatformHooks;
|
||||||
import ca.spottedleaf.moonrise.common.util.ConfigHolder;
|
import ca.spottedleaf.moonrise.common.util.ConfigHolder;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.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.core.BlockPos;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
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.GenerationChunkHolder;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.level.BlockGetter;
|
import net.minecraft.world.level.BlockGetter;
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
import net.minecraft.world.level.Explosion;
|
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
|
import net.minecraft.world.level.chunk.ImposterProtoChunk;
|
||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||||
|
import net.minecraft.world.level.chunk.status.ChunkStatusTasks;
|
||||||
|
import net.minecraft.world.level.chunk.storage.SerializableChunkData;
|
||||||
import net.minecraft.world.level.entity.EntityTypeTest;
|
import net.minecraft.world.level.entity.EntityTypeTest;
|
||||||
import net.minecraft.world.phys.AABB;
|
import net.minecraft.world.phys.AABB;
|
||||||
import net.minecraft.world.phys.Vec3;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
public final class FabricHooks implements PlatformHooks {
|
public final class FabricHooks implements PlatformHooks {
|
||||||
|
|
||||||
|
private static final boolean HAS_FABRIC_LIFECYCLE_EVENTS = FabricLoader.getInstance().isModLoaded("fabric-lifecycle-events-v1");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getBrand() {
|
public String getBrand() {
|
||||||
return "Moonrise";
|
return "Moonrise";
|
||||||
@@ -42,16 +51,6 @@ public final class FabricHooks implements PlatformHooks {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onExplosion(final Level world, final Explosion explosion, final List<Entity> possiblyAffecting, final double diameter) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Vec3 modifyExplosionKnockback(final Level world, final Explosion explosion, final Entity entity, final Vec3 original) {
|
|
||||||
return original;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasCurrentlyLoadingChunk() {
|
public boolean hasCurrentlyLoadingChunk() {
|
||||||
return false;
|
return false;
|
||||||
@@ -69,7 +68,12 @@ public final class FabricHooks implements PlatformHooks {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void chunkFullStatusComplete(final LevelChunk newChunk, final ProtoChunk original) {
|
public void chunkFullStatusComplete(final LevelChunk newChunk, final ProtoChunk original) {
|
||||||
|
if (HAS_FABRIC_LIFECYCLE_EVENTS) {
|
||||||
|
ServerChunkEvents.CHUNK_LOAD.invoker().onChunkLoad((ServerLevel)newChunk.getLevel(), newChunk);
|
||||||
|
if (!(original instanceof ImposterProtoChunk)) {
|
||||||
|
ServerChunkEvents.CHUNK_GENERATE.invoker().onChunkGenerate((ServerLevel)newChunk.getLevel(), newChunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -78,17 +82,19 @@ public final class FabricHooks implements PlatformHooks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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
|
@Override
|
||||||
public void chunkUnloadFromWorld(final LevelChunk chunk) {
|
public void chunkUnloadFromWorld(final LevelChunk chunk) {
|
||||||
|
if (HAS_FABRIC_LIFECYCLE_EVENTS) {
|
||||||
|
ServerChunkEvents.CHUNK_UNLOAD.invoker().onChunkUnload((ServerLevel)chunk.getLevel(), chunk);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void chunkSyncSave(final ServerLevel world, final ChunkAccess chunk, final CompoundTag data) {
|
public void chunkSyncSave(final ServerLevel world, final ChunkAccess chunk, final SerializableChunkData data) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -160,12 +166,12 @@ public final class FabricHooks implements PlatformHooks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long configAutoSaveInterval() {
|
public long configAutoSaveInterval(final ServerLevel world) {
|
||||||
return ConfigHolder.getConfig().chunkSaving.autoSaveInterval.getTimeTicks();
|
return ConfigHolder.getConfig().chunkSaving.autoSaveInterval.getTimeTicks();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int configMaxAutoSavePerTick() {
|
public int configMaxAutoSavePerTick(final ServerLevel world) {
|
||||||
return ConfigHolder.getConfig().chunkSaving.maxAutoSaveChunksPerTick;
|
return ConfigHolder.getConfig().chunkSaving.maxAutoSaveChunksPerTick;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,4 +179,47 @@ public final class FabricHooks implements PlatformHooks {
|
|||||||
public boolean configFixMC159283() {
|
public boolean configFixMC159283() {
|
||||||
return ConfigHolder.getConfig().bugFixes.fixMC159283;
|
return ConfigHolder.getConfig().bugFixes.fixMC159283;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean forceNoSave(final ChunkAccess chunk) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompoundTag convertNBT(final DSL.TypeReference type, final DataFixer dataFixer, final CompoundTag nbt,
|
||||||
|
final int fromVersion, final int toVersion) {
|
||||||
|
return (CompoundTag)dataFixer.update(
|
||||||
|
type, new Dynamic<>(NbtOps.INSTANCE, nbt), fromVersion, toVersion
|
||||||
|
).getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasMainChunkLoadHook() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mainChunkLoad(final ChunkAccess chunk, final SerializableChunkData chunkData) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Entity> modifySavedEntities(final ServerLevel world, final int chunkX, final int chunkZ, final List<Entity> entities) {
|
||||||
|
return entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unloadEntity(final Entity entity) {
|
||||||
|
entity.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postLoadProtoChunk(final ServerLevel world, final ProtoChunk chunk) {
|
||||||
|
ChunkStatusTasks.postLoadProtoChunk(world, chunk.getEntities());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int modifyEntityTrackingRange(final Entity entity, final int currentRange) {
|
||||||
|
return currentRange;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,183 @@
|
|||||||
|
package ca.spottedleaf.moonrise.fabric.mixin.collisions;
|
||||||
|
|
||||||
|
import ca.spottedleaf.moonrise.common.util.WorldUtil;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2DoubleMap;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.tags.TagKey;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.chunk.ChunkSource;
|
||||||
|
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||||
|
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||||
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
|
import net.minecraft.world.level.material.Fluid;
|
||||||
|
import net.minecraft.world.level.material.FluidState;
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
|
||||||
|
@Mixin(Entity.class)
|
||||||
|
abstract class EntityMixin {
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
public abstract boolean touchingUnloadedChunk();
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
public abstract AABB getBoundingBox();
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Deprecated
|
||||||
|
public abstract boolean isPushedByFluid();
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
private Level level;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Deprecated
|
||||||
|
protected Object2DoubleMap<TagKey<Fluid>> fluidHeight;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
public abstract Vec3 getDeltaMovement();
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
public abstract void setDeltaMovement(final Vec3 arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Optimise the block reading in this function
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Overwrite
|
||||||
|
public boolean updateFluidHeightAndDoFluidPushing(final TagKey<Fluid> fluid, final double flowScale) {
|
||||||
|
if (this.touchingUnloadedChunk()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
final AABB boundingBox = this.getBoundingBox().deflate(1.0E-3);
|
||||||
|
|
||||||
|
final Level world = this.level;
|
||||||
|
final int minSection = WorldUtil.getMinSection(world);
|
||||||
|
|
||||||
|
final int minBlockX = Mth.floor(boundingBox.minX);
|
||||||
|
final int minBlockY = Math.max((minSection << 4), Mth.floor(boundingBox.minY));
|
||||||
|
final int minBlockZ = Mth.floor(boundingBox.minZ);
|
||||||
|
|
||||||
|
// note: bounds are exclusive in Vanilla, so we subtract 1 - our loop expects bounds to be inclusive
|
||||||
|
final int maxBlockX = Mth.ceil(boundingBox.maxX) - 1;
|
||||||
|
final int maxBlockY = Math.min((WorldUtil.getMaxSection(world) << 4) | 15, Mth.ceil(boundingBox.maxY) - 1);
|
||||||
|
final int maxBlockZ = Mth.ceil(boundingBox.maxZ) - 1;
|
||||||
|
|
||||||
|
final boolean isPushable = this.isPushedByFluid();
|
||||||
|
final BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos();
|
||||||
|
|
||||||
|
Vec3 pushVector = Vec3.ZERO;
|
||||||
|
double totalPushes = 0.0;
|
||||||
|
double maxHeightDiff = 0.0;
|
||||||
|
boolean inFluid = false;
|
||||||
|
|
||||||
|
final int minChunkX = minBlockX >> 4;
|
||||||
|
final int maxChunkX = maxBlockX >> 4;
|
||||||
|
|
||||||
|
final int minChunkY = minBlockY >> 4;
|
||||||
|
final int maxChunkY = maxBlockY >> 4;
|
||||||
|
|
||||||
|
final int minChunkZ = minBlockZ >> 4;
|
||||||
|
final int maxChunkZ = maxBlockZ >> 4;
|
||||||
|
|
||||||
|
final ChunkSource chunkSource = world.getChunkSource();
|
||||||
|
|
||||||
|
for (int currChunkZ = minChunkZ; currChunkZ <= maxChunkZ; ++currChunkZ) {
|
||||||
|
for (int currChunkX = minChunkX; currChunkX <= maxChunkX; ++currChunkX) {
|
||||||
|
final LevelChunkSection[] sections = chunkSource.getChunk(currChunkX, currChunkZ, ChunkStatus.FULL, false).getSections();
|
||||||
|
|
||||||
|
// bound y
|
||||||
|
for (int currChunkY = minChunkY; currChunkY <= maxChunkY; ++currChunkY) {
|
||||||
|
final int sectionIdx = currChunkY - minSection;
|
||||||
|
if (sectionIdx < 0 || sectionIdx >= sections.length) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final LevelChunkSection section = sections[sectionIdx];
|
||||||
|
if (section.hasOnlyAir()) {
|
||||||
|
// empty
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final PalettedContainer<BlockState> blocks = section.states;
|
||||||
|
|
||||||
|
final int minXIterate = currChunkX == minChunkX ? (minBlockX & 15) : 0;
|
||||||
|
final int maxXIterate = currChunkX == maxChunkX ? (maxBlockX & 15) : 15;
|
||||||
|
final int minZIterate = currChunkZ == minChunkZ ? (minBlockZ & 15) : 0;
|
||||||
|
final int maxZIterate = currChunkZ == maxChunkZ ? (maxBlockZ & 15) : 15;
|
||||||
|
final int minYIterate = currChunkY == minChunkY ? (minBlockY & 15) : 0;
|
||||||
|
final int maxYIterate = currChunkY == maxChunkY ? (maxBlockY & 15) : 15;
|
||||||
|
|
||||||
|
for (int currY = minYIterate; currY <= maxYIterate; ++currY) {
|
||||||
|
for (int currZ = minZIterate; currZ <= maxZIterate; ++currZ) {
|
||||||
|
for (int currX = minXIterate; currX <= maxXIterate; ++currX) {
|
||||||
|
final FluidState fluidState = blocks.get((currX) | (currZ << 4) | ((currY) << 8)).getFluidState();
|
||||||
|
|
||||||
|
if (fluidState.isEmpty() || !fluidState.is(fluid)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutablePos.set(currX | (currChunkX << 4), currY | (currChunkY << 4), currZ | (currChunkZ << 4));
|
||||||
|
|
||||||
|
final double height = (double)((float)mutablePos.getY() + fluidState.getHeight(world, mutablePos));
|
||||||
|
final double diff = height - boundingBox.minY;
|
||||||
|
|
||||||
|
if (diff < 0.0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
inFluid = true;
|
||||||
|
maxHeightDiff = Math.max(maxHeightDiff, diff);
|
||||||
|
|
||||||
|
if (!isPushable) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
++totalPushes;
|
||||||
|
|
||||||
|
final Vec3 flow = fluidState.getFlow(world, mutablePos);
|
||||||
|
|
||||||
|
if (diff < 0.4) {
|
||||||
|
pushVector = pushVector.add(flow.scale(diff));
|
||||||
|
} else {
|
||||||
|
pushVector = pushVector.add(flow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.fluidHeight.put(fluid, maxHeightDiff);
|
||||||
|
|
||||||
|
if (pushVector.lengthSqr() == 0.0) {
|
||||||
|
return inFluid;
|
||||||
|
}
|
||||||
|
|
||||||
|
// note: totalPushes != 0 as pushVector != 0
|
||||||
|
pushVector = pushVector.scale(1.0 / totalPushes);
|
||||||
|
final Vec3 currMovement = this.getDeltaMovement();
|
||||||
|
|
||||||
|
if (!((Entity)(Object)this instanceof Player)) {
|
||||||
|
pushVector = pushVector.normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
pushVector = pushVector.scale(flowScale);
|
||||||
|
if (Math.abs(currMovement.x) < 0.003 && Math.abs(currMovement.z) < 0.003 && pushVector.length() < 0.0045000000000000005) {
|
||||||
|
pushVector = pushVector.normalize().scale(0.0045000000000000005);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setDeltaMovement(currMovement.add(pushVector));
|
||||||
|
|
||||||
|
// note: inFluid = true here as pushVector != 0
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,35 +36,39 @@
|
|||||||
"accessWidener": "moonrise.accesswidener",
|
"accessWidener": "moonrise.accesswidener",
|
||||||
"depends": {
|
"depends": {
|
||||||
"fabricloader": ">=${loader_version}",
|
"fabricloader": ">=${loader_version}",
|
||||||
"minecraft": ">=1.21 <=1.21.1",
|
"minecraft": ">1.21.1 <1.21.4",
|
||||||
"fabric-command-api-v2": "*"
|
"fabric-command-api-v2": "*"
|
||||||
},
|
},
|
||||||
"custom": {
|
"custom": {
|
||||||
"lithium:options": {
|
"lithium:options": {
|
||||||
"mixin.collections.chunk_tickets": false,
|
|
||||||
"mixin.world.temperature_cache": false,
|
|
||||||
"mixin.block.flatten_states": false,
|
|
||||||
"mixin.math.fast_util": false,
|
|
||||||
"mixin.minimal_nonvanilla.collisions.empty_space": false,
|
|
||||||
"mixin.alloc.deep_passengers": false,
|
|
||||||
"mixin.math.fast_blockpos": false,
|
|
||||||
"mixin.shapes.blockstate_cache": false,
|
|
||||||
"mixin.world.block_entity_ticking": false,
|
|
||||||
"mixin.collections.entity_ticking": false,
|
|
||||||
"mixin.world.chunk_access": false,
|
|
||||||
"mixin.ai.poi": false,
|
"mixin.ai.poi": false,
|
||||||
"mixin.chunk.no_validation": false,
|
|
||||||
"mixin.minimal_nonvanilla.world.expiring_chunk_tickets": false,
|
|
||||||
"mixin.world.tick_scheduler": false,
|
|
||||||
"mixin.alloc.chunk_ticking": false,
|
"mixin.alloc.chunk_ticking": false,
|
||||||
"mixin.entity.replace_entitytype_predicates": false,
|
"mixin.alloc.deep_passengers": false,
|
||||||
"mixin.util.block_tracking": false,
|
"mixin.alloc.entity_tracker": false,
|
||||||
"mixin.shapes.specialized_shapes": false,
|
"mixin.block.flatten_states": false,
|
||||||
"mixin.shapes.optimized_matching": false,
|
"mixin.chunk.entity_class_groups": false,
|
||||||
|
"mixin.chunk.no_validation": false,
|
||||||
|
"mixin.collections.chunk_tickets": false,
|
||||||
|
"mixin.collections.entity_ticking": false,
|
||||||
"mixin.entity.collisions.intersection": false,
|
"mixin.entity.collisions.intersection": false,
|
||||||
"mixin.entity.collisions.movement": false,
|
"mixin.entity.collisions.movement": false,
|
||||||
"mixin.entity.collisions.unpushable_cramming": false,
|
"mixin.entity.collisions.unpushable_cramming": false,
|
||||||
"mixin.chunk.entity_class_groups": false
|
"mixin.entity.replace_entitytype_predicates": false,
|
||||||
|
"mixin.math.fast_blockpos": false,
|
||||||
|
"mixin.math.fast_util": false,
|
||||||
|
"mixin.minimal_nonvanilla.collisions.empty_space": false,
|
||||||
|
"mixin.minimal_nonvanilla.world.expiring_chunk_tickets": false,
|
||||||
|
"mixin.shapes.blockstate_cache": false,
|
||||||
|
"mixin.shapes.optimized_matching": false,
|
||||||
|
"mixin.shapes.specialized_shapes": false,
|
||||||
|
"mixin.util.block_tracking": false,
|
||||||
|
"mixin.util.entity_movement_tracking": false,
|
||||||
|
"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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
"mixins": [
|
"mixins": [
|
||||||
"chunk_system.FabricDistanceManagerMixin",
|
"chunk_system.FabricDistanceManagerMixin",
|
||||||
"chunk_system.FabricMinecraftServerMixin",
|
"chunk_system.FabricMinecraftServerMixin",
|
||||||
"chunk_system.FabricServerLevelMixin"
|
"chunk_system.FabricServerLevelMixin",
|
||||||
|
"collisions.EntityMixin"
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"command.ClientSuggestionProviderMixin"
|
"command.ClientSuggestionProviderMixin"
|
||||||
|
|||||||
@@ -3,14 +3,19 @@ org.gradle.jvmargs=-Xmx2G
|
|||||||
org.gradle.daemon=false
|
org.gradle.daemon=false
|
||||||
# Fabric Properties
|
# Fabric Properties
|
||||||
# check these on https://modmuss50.me/fabric.html
|
# check these on https://modmuss50.me/fabric.html
|
||||||
minecraft_version=1.21.1
|
minecraft_version=1.21.3
|
||||||
loader_version=0.15.11
|
loader_version=0.16.7
|
||||||
neoforge_version=21.1.20
|
supported_minecraft_versions=1.21.3
|
||||||
|
neoforge_version=21.3.0-beta
|
||||||
|
fabric_api_version=0.107.0+1.21.3
|
||||||
snakeyaml_version=2.2
|
snakeyaml_version=2.2
|
||||||
concurrentutil_version=0.0.2-SNAPSHOT
|
concurrentutil_version=0.0.2-SNAPSHOT
|
||||||
cloth_version=15.0.128
|
cloth_version=16.0.141
|
||||||
lithium_version=mc1.21.1-0.13.0
|
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
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
mod_version=0.1.0-beta.0
|
mod_version=0.2.0-beta.3
|
||||||
maven_group=ca.spottedleaf.moonrise
|
maven_group=ca.spottedleaf.moonrise
|
||||||
archives_base_name=moonrise
|
archives_base_name=moonrise
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import net.fabricmc.loom.util.aw2at.Aw2At
|
|||||||
plugins {
|
plugins {
|
||||||
id("xyz.jpenilla.quiet-architectury-loom")
|
id("xyz.jpenilla.quiet-architectury-loom")
|
||||||
id 'maven-publish'
|
id 'maven-publish'
|
||||||
id 'io.github.goooler.shadow'
|
id 'com.gradleup.shadow'
|
||||||
}
|
}
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
@@ -53,17 +53,15 @@ publishMods {
|
|||||||
modrinth {
|
modrinth {
|
||||||
incompatible(
|
incompatible(
|
||||||
"notenoughcrashes",
|
"notenoughcrashes",
|
||||||
"starlight-forge",
|
"starlight-neoforge",
|
||||||
"canary",
|
"canary"
|
||||||
"radium"
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
curseforge {
|
curseforge {
|
||||||
incompatible(
|
incompatible(
|
||||||
"not-enough-crashes-forge",
|
"not-enough-crashes-forge",
|
||||||
"starlight-forge",
|
"starlight-neoforge",
|
||||||
"canary",
|
"canary"
|
||||||
"radium-reforged"
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,13 @@ package ca.spottedleaf.moonrise.neoforge;
|
|||||||
import ca.spottedleaf.moonrise.common.PlatformHooks;
|
import ca.spottedleaf.moonrise.common.PlatformHooks;
|
||||||
import ca.spottedleaf.moonrise.common.util.ConfigHolder;
|
import ca.spottedleaf.moonrise.common.util.ConfigHolder;
|
||||||
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.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.core.BlockPos;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
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.GenerationChunkHolder;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
@@ -13,16 +17,16 @@ import net.minecraft.world.entity.Entity;
|
|||||||
import net.minecraft.world.level.BlockGetter;
|
import net.minecraft.world.level.BlockGetter;
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
import net.minecraft.world.level.EmptyBlockGetter;
|
import net.minecraft.world.level.EmptyBlockGetter;
|
||||||
import net.minecraft.world.level.Explosion;
|
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.ImposterProtoChunk;
|
import net.minecraft.world.level.chunk.ImposterProtoChunk;
|
||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||||
|
import net.minecraft.world.level.chunk.status.ChunkStatusTasks;
|
||||||
|
import net.minecraft.world.level.chunk.storage.SerializableChunkData;
|
||||||
import net.minecraft.world.level.entity.EntityTypeTest;
|
import net.minecraft.world.level.entity.EntityTypeTest;
|
||||||
import net.minecraft.world.phys.AABB;
|
import net.minecraft.world.phys.AABB;
|
||||||
import net.minecraft.world.phys.Vec3;
|
|
||||||
import net.neoforged.neoforge.common.CommonHooks;
|
import net.neoforged.neoforge.common.CommonHooks;
|
||||||
import net.neoforged.neoforge.common.NeoForge;
|
import net.neoforged.neoforge.common.NeoForge;
|
||||||
import net.neoforged.neoforge.entity.PartEntity;
|
import net.neoforged.neoforge.entity.PartEntity;
|
||||||
@@ -52,16 +56,6 @@ public final class NeoForgeHooks implements PlatformHooks {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onExplosion(final Level world, final Explosion explosion, final List<Entity> possiblyAffecting, final double diameter) {
|
|
||||||
EventHooks.onExplosionDetonate(world, explosion, possiblyAffecting, diameter);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Vec3 modifyExplosionKnockback(final Level world, final Explosion explosion, final Entity entity, final Vec3 original) {
|
|
||||||
return EventHooks.getExplosionKnockback(world, explosion, entity, original);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasCurrentlyLoadingChunk() {
|
public boolean hasCurrentlyLoadingChunk() {
|
||||||
return true;
|
return true;
|
||||||
@@ -88,10 +82,12 @@ public final class NeoForgeHooks implements PlatformHooks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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(
|
EventHooks.fireChunkTicketLevelUpdated(
|
||||||
world, CoordinateUtils.getChunkKey(holder.chunkX, holder.chunkZ),
|
world, CoordinateUtils.getChunkKey(pos.x, pos.z),
|
||||||
oldLevel, newLevel, holder.vanillaChunkHolder
|
oldLevel, newLevel, holder
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +97,7 @@ public final class NeoForgeHooks implements PlatformHooks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void chunkSyncSave(final ServerLevel world, final ChunkAccess chunk, final CompoundTag data) {
|
public void chunkSyncSave(final ServerLevel world, final ChunkAccess chunk, final SerializableChunkData data) {
|
||||||
NeoForge.EVENT_BUS.post(new ChunkDataEvent.Save(chunk, world, data));
|
NeoForge.EVENT_BUS.post(new ChunkDataEvent.Save(chunk, world, data));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,12 +189,12 @@ public final class NeoForgeHooks implements PlatformHooks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public long configAutoSaveInterval() {
|
public long configAutoSaveInterval(final ServerLevel world) {
|
||||||
return ConfigHolder.getConfig().chunkSaving.autoSaveInterval.getTimeTicks();
|
return ConfigHolder.getConfig().chunkSaving.autoSaveInterval.getTimeTicks();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int configMaxAutoSavePerTick() {
|
public int configMaxAutoSavePerTick(final ServerLevel world) {
|
||||||
return ConfigHolder.getConfig().chunkSaving.maxAutoSaveChunksPerTick;
|
return ConfigHolder.getConfig().chunkSaving.maxAutoSaveChunksPerTick;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,4 +202,47 @@ public final class NeoForgeHooks implements PlatformHooks {
|
|||||||
public boolean configFixMC159283() {
|
public boolean configFixMC159283() {
|
||||||
return ConfigHolder.getConfig().bugFixes.fixMC159283;
|
return ConfigHolder.getConfig().bugFixes.fixMC159283;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean forceNoSave(final ChunkAccess chunk) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompoundTag convertNBT(final DSL.TypeReference type, final DataFixer dataFixer, final CompoundTag nbt,
|
||||||
|
final int fromVersion, final int toVersion) {
|
||||||
|
return (CompoundTag)dataFixer.update(
|
||||||
|
type, new Dynamic<>(NbtOps.INSTANCE, nbt), fromVersion, toVersion
|
||||||
|
).getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasMainChunkLoadHook() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mainChunkLoad(final ChunkAccess chunk, final SerializableChunkData chunkData) {
|
||||||
|
NeoForge.EVENT_BUS.post(new ChunkDataEvent.Load(chunk, chunkData));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Entity> modifySavedEntities(final ServerLevel world, final int chunkX, final int chunkZ, final List<Entity> entities) {
|
||||||
|
return entities;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void unloadEntity(final Entity entity) {
|
||||||
|
entity.setRemoved(Entity.RemovalReason.UNLOADED_TO_CHUNK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void postLoadProtoChunk(final ServerLevel world, final ProtoChunk chunk) {
|
||||||
|
ChunkStatusTasks.postLoadProtoChunk(world, chunk.getEntities());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int modifyEntityTrackingRange(final Entity entity, final int currentRange) {
|
||||||
|
return currentRange;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
package ca.spottedleaf.moonrise.neoforge.mixin.chunk_system;
|
package ca.spottedleaf.moonrise.neoforge.mixin.chunk_system;
|
||||||
|
|
||||||
import ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable;
|
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemDistanceManager;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemDistanceManager;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectFunction;
|
import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickServerLevel;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||||
import net.minecraft.server.level.ChunkLevel;
|
import net.minecraft.server.level.ChunkLevel;
|
||||||
import net.minecraft.server.level.DistanceManager;
|
import net.minecraft.server.level.DistanceManager;
|
||||||
@@ -15,13 +15,13 @@ import org.spongepowered.asm.mixin.Final;
|
|||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
|
||||||
|
|
||||||
@Mixin(DistanceManager.class)
|
@Mixin(DistanceManager.class)
|
||||||
abstract class NeoForgeDistanceManagerMixin implements ChunkSystemDistanceManager {
|
abstract class NeoForgeDistanceManagerMixin implements ChunkSystemDistanceManager {
|
||||||
|
|
||||||
@Unique
|
@Shadow
|
||||||
private final ConcurrentLong2ReferenceChainedHashTable<SortedArraySet<Ticket<?>>> mtSafeForcedTickets = new ConcurrentLong2ReferenceChainedHashTable<>();
|
@Final
|
||||||
|
private Long2ObjectOpenHashMap<SortedArraySet<Ticket<?>>> forcedTickets;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Route to new chunk system
|
* @reason Route to new chunk system
|
||||||
@@ -34,7 +34,7 @@ abstract class NeoForgeDistanceManagerMixin implements ChunkSystemDistanceManage
|
|||||||
if (forceTicks) {
|
if (forceTicks) {
|
||||||
final Ticket<T> forceTicket = new Ticket<>(type, level, identifier, forceTicks);
|
final Ticket<T> forceTicket = new Ticket<>(type, level, identifier, forceTicks);
|
||||||
|
|
||||||
this.mtSafeForcedTickets.compute(pos.toLong(), (final long keyInMap, final SortedArraySet<Ticket<?>> valueInMap) -> {
|
this.forcedTickets.compute(pos.toLong(), (final Long keyInMap, final SortedArraySet<Ticket<?>> valueInMap) -> {
|
||||||
final SortedArraySet<Ticket<?>> ret;
|
final SortedArraySet<Ticket<?>> ret;
|
||||||
if (valueInMap != null) {
|
if (valueInMap != null) {
|
||||||
ret = valueInMap;
|
ret = valueInMap;
|
||||||
@@ -42,7 +42,11 @@ abstract class NeoForgeDistanceManagerMixin implements ChunkSystemDistanceManage
|
|||||||
ret = SortedArraySet.create(4);
|
ret = SortedArraySet.create(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
ret.add(forceTicket);
|
if (ret.add(forceTicket)) {
|
||||||
|
((ChunkTickServerLevel)NeoForgeDistanceManagerMixin.this.moonrise$getChunkMap().level).moonrise$addPlayerTickingRequest(
|
||||||
|
CoordinateUtils.getChunkX(keyInMap.longValue()), CoordinateUtils.getChunkZ(keyInMap.longValue())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
});
|
});
|
||||||
@@ -60,8 +64,12 @@ abstract class NeoForgeDistanceManagerMixin implements ChunkSystemDistanceManage
|
|||||||
if (forceTicks) {
|
if (forceTicks) {
|
||||||
final Ticket<T> forceTicket = new Ticket<>(type, level, identifier, forceTicks);
|
final Ticket<T> forceTicket = new Ticket<>(type, level, identifier, forceTicks);
|
||||||
|
|
||||||
this.mtSafeForcedTickets.computeIfPresent(pos.toLong(), (final long keyInMap, final SortedArraySet<Ticket<?>> valueInMap) -> {
|
this.forcedTickets.computeIfPresent(pos.toLong(), (final Long keyInMap, final SortedArraySet<Ticket<?>> valueInMap) -> {
|
||||||
valueInMap.remove(forceTicket);
|
if (valueInMap.remove(forceTicket)) {
|
||||||
|
((ChunkTickServerLevel)NeoForgeDistanceManagerMixin.this.moonrise$getChunkMap().level).moonrise$removePlayerTickingRequest(
|
||||||
|
CoordinateUtils.getChunkX(keyInMap.longValue()), CoordinateUtils.getChunkZ(keyInMap.longValue())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return valueInMap.isEmpty() ? null : valueInMap;
|
return valueInMap.isEmpty() ? null : valueInMap;
|
||||||
});
|
});
|
||||||
@@ -69,11 +77,11 @@ abstract class NeoForgeDistanceManagerMixin implements ChunkSystemDistanceManage
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Make this API thread-safe
|
* @reason Only use containsKey, as we fix the leak with this impl
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public boolean shouldForceTicks(final long chunkPos) {
|
public boolean shouldForceTicks(final long chunkPos) {
|
||||||
return this.mtSafeForcedTickets.containsKey(chunkPos);
|
return this.forcedTickets.containsKey(chunkPos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,199 @@
|
|||||||
|
package ca.spottedleaf.moonrise.neoforge.mixin.collisions;
|
||||||
|
|
||||||
|
import ca.spottedleaf.moonrise.common.util.WorldUtil;
|
||||||
|
import ca.spottedleaf.moonrise.neoforge.patches.collisions.FluidPushCalculation;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Reference2ReferenceArrayMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Reference2ReferenceMap;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.util.Mth;
|
||||||
|
import net.minecraft.world.entity.Entity;
|
||||||
|
import net.minecraft.world.entity.player.Player;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
|
import net.minecraft.world.level.chunk.ChunkSource;
|
||||||
|
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||||
|
import net.minecraft.world.level.chunk.PalettedContainer;
|
||||||
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
|
import net.minecraft.world.level.material.FluidState;
|
||||||
|
import net.minecraft.world.phys.AABB;
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
import net.neoforged.neoforge.common.extensions.IEntityExtension;
|
||||||
|
import net.neoforged.neoforge.fluids.FluidType;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
|
@Mixin(Entity.class)
|
||||||
|
abstract class EntityMixin implements IEntityExtension {
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
public abstract boolean touchingUnloadedChunk();
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
public abstract AABB getBoundingBox();
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
private Level level;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
protected abstract void setFluidTypeHeight(final FluidType type, final double height);
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
public abstract Vec3 getDeltaMovement();
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
public abstract void setDeltaMovement(final Vec3 arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Optimise the block reading in this function
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Overwrite
|
||||||
|
public void updateFluidHeightAndDoFluidPushing() {
|
||||||
|
if (this.touchingUnloadedChunk()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final AABB boundingBox = this.getBoundingBox().deflate(1.0E-3);
|
||||||
|
|
||||||
|
final Level world = this.level;
|
||||||
|
final int minSection = WorldUtil.getMinSection(world);
|
||||||
|
|
||||||
|
final int minBlockX = Mth.floor(boundingBox.minX);
|
||||||
|
final int minBlockY = Math.max((minSection << 4), Mth.floor(boundingBox.minY));
|
||||||
|
final int minBlockZ = Mth.floor(boundingBox.minZ);
|
||||||
|
|
||||||
|
// note: bounds are exclusive in Vanilla, so we subtract 1
|
||||||
|
final int maxBlockX = Mth.ceil(boundingBox.maxX) - 1;
|
||||||
|
final int maxBlockY = Math.min((WorldUtil.getMaxSection(world) << 4) | 15, Mth.ceil(boundingBox.maxY) - 1);
|
||||||
|
final int maxBlockZ = Mth.ceil(boundingBox.maxZ) - 1;
|
||||||
|
|
||||||
|
final BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos();
|
||||||
|
|
||||||
|
final int minChunkX = minBlockX >> 4;
|
||||||
|
final int maxChunkX = maxBlockX >> 4;
|
||||||
|
|
||||||
|
final int minChunkY = minBlockY >> 4;
|
||||||
|
final int maxChunkY = maxBlockY >> 4;
|
||||||
|
|
||||||
|
final int minChunkZ = minBlockZ >> 4;
|
||||||
|
final int maxChunkZ = maxBlockZ >> 4;
|
||||||
|
|
||||||
|
final ChunkSource chunkSource = world.getChunkSource();
|
||||||
|
|
||||||
|
final Reference2ReferenceArrayMap<FluidType, FluidPushCalculation> calculations = new Reference2ReferenceArrayMap<>();
|
||||||
|
|
||||||
|
for (int currChunkZ = minChunkZ; currChunkZ <= maxChunkZ; ++currChunkZ) {
|
||||||
|
for (int currChunkX = minChunkX; currChunkX <= maxChunkX; ++currChunkX) {
|
||||||
|
final LevelChunkSection[] sections = chunkSource.getChunk(currChunkX, currChunkZ, ChunkStatus.FULL, false).getSections();
|
||||||
|
|
||||||
|
// bound y
|
||||||
|
for (int currChunkY = minChunkY; currChunkY <= maxChunkY; ++currChunkY) {
|
||||||
|
final int sectionIdx = currChunkY - minSection;
|
||||||
|
if (sectionIdx < 0 || sectionIdx >= sections.length) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final LevelChunkSection section = sections[sectionIdx];
|
||||||
|
if (section.hasOnlyAir()) {
|
||||||
|
// empty
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final PalettedContainer<BlockState> blocks = section.states;
|
||||||
|
|
||||||
|
final int minXIterate = currChunkX == minChunkX ? (minBlockX & 15) : 0;
|
||||||
|
final int maxXIterate = currChunkX == maxChunkX ? (maxBlockX & 15) : 15;
|
||||||
|
final int minZIterate = currChunkZ == minChunkZ ? (minBlockZ & 15) : 0;
|
||||||
|
final int maxZIterate = currChunkZ == maxChunkZ ? (maxBlockZ & 15) : 15;
|
||||||
|
final int minYIterate = currChunkY == minChunkY ? (minBlockY & 15) : 0;
|
||||||
|
final int maxYIterate = currChunkY == maxChunkY ? (maxBlockY & 15) : 15;
|
||||||
|
|
||||||
|
for (int currY = minYIterate; currY <= maxYIterate; ++currY) {
|
||||||
|
for (int currZ = minZIterate; currZ <= maxZIterate; ++currZ) {
|
||||||
|
for (int currX = minXIterate; currX <= maxXIterate; ++currX) {
|
||||||
|
final FluidState fluidState = blocks.get((currX) | (currZ << 4) | ((currY) << 8)).getFluidState();
|
||||||
|
|
||||||
|
if (fluidState.isEmpty()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
mutablePos.set(currX | (currChunkX << 4), currY | (currChunkY << 4), currZ | (currChunkZ << 4));
|
||||||
|
|
||||||
|
final FluidType type = fluidState.getFluidType();
|
||||||
|
|
||||||
|
// note: assume fluidState.isEmpty() == type.isAir()
|
||||||
|
|
||||||
|
final FluidPushCalculation calculation = calculations.computeIfAbsent(type, (final FluidType key) -> {
|
||||||
|
return new FluidPushCalculation();
|
||||||
|
});
|
||||||
|
|
||||||
|
final double height = (double)((float)mutablePos.getY() + fluidState.getHeight(world, mutablePos));
|
||||||
|
final double diff = height - boundingBox.minY;
|
||||||
|
|
||||||
|
if (diff < 0.0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
calculation.maxHeightDiff = Math.max(calculation.maxHeightDiff, diff);
|
||||||
|
|
||||||
|
if (calculation.isPushed == Boolean.FALSE) {
|
||||||
|
continue;
|
||||||
|
} else if (calculation.isPushed == null) {
|
||||||
|
final boolean isPushed = this.isPushedByFluid(type);
|
||||||
|
calculation.isPushed = Boolean.valueOf(isPushed);
|
||||||
|
if (!isPushed) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
++calculation.totalPushes;
|
||||||
|
|
||||||
|
final Vec3 flow = fluidState.getFlow(world, mutablePos);
|
||||||
|
|
||||||
|
if (diff < 0.4) {
|
||||||
|
calculation.pushVector = calculation.pushVector.add(flow.scale(diff));
|
||||||
|
} else {
|
||||||
|
calculation.pushVector = calculation.pushVector.add(flow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (calculations.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final Iterator<Reference2ReferenceMap.Entry<FluidType, FluidPushCalculation>> iterator = calculations.reference2ReferenceEntrySet().fastIterator(); iterator.hasNext();) {
|
||||||
|
final Reference2ReferenceMap.Entry<FluidType, FluidPushCalculation> entry = iterator.next();
|
||||||
|
final FluidType type = entry.getKey();
|
||||||
|
final FluidPushCalculation calculation = entry.getValue();
|
||||||
|
|
||||||
|
this.setFluidTypeHeight(type, calculation.maxHeightDiff);
|
||||||
|
|
||||||
|
Vec3 pushVector = calculation.pushVector;
|
||||||
|
|
||||||
|
if (pushVector.lengthSqr() == 0.0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// note: totalPushes != 0 as pushVector != 0
|
||||||
|
pushVector = pushVector.scale(1.0 / calculation.totalPushes);
|
||||||
|
final Vec3 currMovement = this.getDeltaMovement();
|
||||||
|
|
||||||
|
if (!((Entity)(Object)this instanceof Player)) {
|
||||||
|
pushVector = pushVector.normalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
pushVector = pushVector.scale(this.getFluidMotionScale(type));
|
||||||
|
if (Math.abs(currMovement.x) < 0.003 && Math.abs(currMovement.z) < 0.003 && pushVector.length() < 0.0045000000000000005) {
|
||||||
|
pushVector = pushVector.normalize().scale(0.0045000000000000005);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setDeltaMovement(currMovement.add(pushVector));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package ca.spottedleaf.moonrise.neoforge.patches.collisions;
|
||||||
|
|
||||||
|
import net.minecraft.world.phys.Vec3;
|
||||||
|
|
||||||
|
public final class FluidPushCalculation {
|
||||||
|
|
||||||
|
public Vec3 pushVector = Vec3.ZERO;
|
||||||
|
public double totalPushes = 0.0;
|
||||||
|
public double maxHeightDiff = 0.0;
|
||||||
|
public Boolean isPushed = null;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -24,7 +24,7 @@ side = "BOTH"
|
|||||||
[[dependencies.moonrise]]
|
[[dependencies.moonrise]]
|
||||||
modId = "minecraft"
|
modId = "minecraft"
|
||||||
type = "required"
|
type = "required"
|
||||||
versionRange = "[1.21,1.21.2)"
|
versionRange = "(1.21.1,1.21.4)"
|
||||||
ordering = "NONE"
|
ordering = "NONE"
|
||||||
side = "BOTH"
|
side = "BOTH"
|
||||||
|
|
||||||
@@ -36,20 +36,11 @@ type = "incompatible"
|
|||||||
modId = "starlight"
|
modId = "starlight"
|
||||||
type = "incompatible"
|
type = "incompatible"
|
||||||
|
|
||||||
[[dependencies.moonrise]]
|
|
||||||
modId = "lithium"
|
|
||||||
type = "incompatible"
|
|
||||||
|
|
||||||
[[dependencies.moonrise]]
|
[[dependencies.moonrise]]
|
||||||
# unofficial lithium port
|
# unofficial lithium port
|
||||||
modId = "canary"
|
modId = "canary"
|
||||||
type = "incompatible"
|
type = "incompatible"
|
||||||
|
|
||||||
[[dependencies.moonrise]]
|
|
||||||
# unofficial lithium port
|
|
||||||
modId = "radium"
|
|
||||||
type = "incompatible"
|
|
||||||
|
|
||||||
[[dependencies.moonrise]]
|
[[dependencies.moonrise]]
|
||||||
modId = "c2me"
|
modId = "c2me"
|
||||||
type = "incompatible"
|
type = "incompatible"
|
||||||
@@ -59,3 +50,33 @@ config = "moonrise.mixins.json"
|
|||||||
|
|
||||||
[[mixins]]
|
[[mixins]]
|
||||||
config = "moonrise-neoforge.mixins.json"
|
config = "moonrise-neoforge.mixins.json"
|
||||||
|
|
||||||
|
[mods."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
|
||||||
|
"mixin.chunk.entity_class_groups" = false
|
||||||
|
"mixin.chunk.no_validation" = false
|
||||||
|
"mixin.collections.chunk_tickets" = false
|
||||||
|
"mixin.collections.entity_ticking" = false
|
||||||
|
"mixin.entity.collisions.intersection" = false
|
||||||
|
"mixin.entity.collisions.movement" = false
|
||||||
|
"mixin.entity.collisions.unpushable_cramming" = false
|
||||||
|
"mixin.entity.replace_entitytype_predicates" = false
|
||||||
|
"mixin.math.fast_blockpos" = false
|
||||||
|
"mixin.math.fast_util" = false
|
||||||
|
"mixin.minimal_nonvanilla.collisions.empty_space" = false
|
||||||
|
"mixin.minimal_nonvanilla.world.expiring_chunk_tickets" = false
|
||||||
|
"mixin.shapes.blockstate_cache" = false
|
||||||
|
"mixin.shapes.optimized_matching" = false
|
||||||
|
"mixin.shapes.specialized_shapes" = false
|
||||||
|
"mixin.util.block_tracking" = false
|
||||||
|
"mixin.util.entity_movement_tracking" = false
|
||||||
|
"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
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
"mixins": [
|
"mixins": [
|
||||||
"chunk_system.NeoForgeDistanceManagerMixin",
|
"chunk_system.NeoForgeDistanceManagerMixin",
|
||||||
"chunk_system.NeoForgeMinecraftServerMixin",
|
"chunk_system.NeoForgeMinecraftServerMixin",
|
||||||
"chunk_system.NeoForgeServerLevelMixin"
|
"chunk_system.NeoForgeServerLevelMixin",
|
||||||
|
"collisions.EntityMixin"
|
||||||
],
|
],
|
||||||
"client": [
|
"client": [
|
||||||
"command.ClientCommandSourceStackMixin"
|
"command.ClientCommandSourceStackMixin"
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ pluginManagement {
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
|
id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0"
|
||||||
id("xyz.jpenilla.quiet-architectury-loom") version "1.7.294" apply false
|
id("xyz.jpenilla.quiet-architectury-loom") version "1.7.297" apply false
|
||||||
id 'io.github.goooler.shadow' version '8.1.8' apply false
|
id 'com.gradleup.shadow' version '8.3.0' apply false
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencyResolutionManagement {
|
dependencyResolutionManagement {
|
||||||
@@ -37,7 +37,7 @@ dependencyResolutionManagement {
|
|||||||
}
|
}
|
||||||
versionCatalogs {
|
versionCatalogs {
|
||||||
create("fabricApiLibs") {
|
create("fabricApiLibs") {
|
||||||
from("net.fabricmc.fabric-api:fabric-api-catalog:0.102.0+1.21.1")
|
from("net.fabricmc.fabric-api:fabric-api-catalog:${fabric_api_version}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,23 +1,25 @@
|
|||||||
package ca.spottedleaf.moonrise.common;
|
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.core.BlockPos;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.server.level.ChunkHolder;
|
||||||
import net.minecraft.server.level.GenerationChunkHolder;
|
import net.minecraft.server.level.GenerationChunkHolder;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.util.datafix.DataFixTypes;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.level.BlockGetter;
|
import net.minecraft.world.level.BlockGetter;
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
import net.minecraft.world.level.Explosion;
|
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||||
|
import net.minecraft.world.level.chunk.storage.SerializableChunkData;
|
||||||
import net.minecraft.world.level.entity.EntityTypeTest;
|
import net.minecraft.world.level.entity.EntityTypeTest;
|
||||||
import net.minecraft.world.phys.AABB;
|
import net.minecraft.world.phys.AABB;
|
||||||
import net.minecraft.world.phys.Vec3;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.ServiceLoader;
|
import java.util.ServiceLoader;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
@@ -33,10 +35,6 @@ public interface PlatformHooks {
|
|||||||
|
|
||||||
public Predicate<BlockState> maybeHasLightEmission();
|
public Predicate<BlockState> maybeHasLightEmission();
|
||||||
|
|
||||||
public void onExplosion(final Level world, final Explosion explosion, final List<Entity> possiblyAffecting, final double diameter);
|
|
||||||
|
|
||||||
public Vec3 modifyExplosionKnockback(final Level world, final Explosion explosion, final Entity entity, final Vec3 original);
|
|
||||||
|
|
||||||
public boolean hasCurrentlyLoadingChunk();
|
public boolean hasCurrentlyLoadingChunk();
|
||||||
|
|
||||||
public LevelChunk getCurrentlyLoadingChunk(final GenerationChunkHolder holder);
|
public LevelChunk getCurrentlyLoadingChunk(final GenerationChunkHolder holder);
|
||||||
@@ -47,11 +45,11 @@ public interface PlatformHooks {
|
|||||||
|
|
||||||
public boolean allowAsyncTicketUpdates();
|
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);
|
public void chunkUnloadFromWorld(final LevelChunk chunk);
|
||||||
|
|
||||||
public void chunkSyncSave(final ServerLevel world, final ChunkAccess chunk, final CompoundTag data);
|
public void chunkSyncSave(final ServerLevel world, final ChunkAccess chunk, final SerializableChunkData data);
|
||||||
|
|
||||||
public void onChunkWatch(final ServerLevel world, final LevelChunk chunk, final ServerPlayer player);
|
public void onChunkWatch(final ServerLevel world, final LevelChunk chunk, final ServerPlayer player);
|
||||||
|
|
||||||
@@ -82,12 +80,30 @@ public interface PlatformHooks {
|
|||||||
|
|
||||||
public int configPlayerMaxConcurrentGens();
|
public int configPlayerMaxConcurrentGens();
|
||||||
|
|
||||||
public long configAutoSaveInterval();
|
public long configAutoSaveInterval(final ServerLevel world);
|
||||||
|
|
||||||
public int configMaxAutoSavePerTick();
|
public int configMaxAutoSavePerTick(final ServerLevel world);
|
||||||
|
|
||||||
public boolean configFixMC159283();
|
public boolean configFixMC159283();
|
||||||
|
|
||||||
|
// support for CB chunk mustNotSave
|
||||||
|
public boolean forceNoSave(final ChunkAccess chunk);
|
||||||
|
|
||||||
|
public CompoundTag convertNBT(final DSL.TypeReference type, final DataFixer dataFixer, final CompoundTag nbt,
|
||||||
|
final int fromVersion, final int toVersion);
|
||||||
|
|
||||||
|
public boolean hasMainChunkLoadHook();
|
||||||
|
|
||||||
|
public void mainChunkLoad(final ChunkAccess chunk, final SerializableChunkData chunkData);
|
||||||
|
|
||||||
|
public List<Entity> modifySavedEntities(final ServerLevel world, final int chunkX, final int chunkZ, final List<Entity> entities);
|
||||||
|
|
||||||
|
public void unloadEntity(final Entity entity);
|
||||||
|
|
||||||
|
public void postLoadProtoChunk(final ServerLevel world, final ProtoChunk chunk);
|
||||||
|
|
||||||
|
public int modifyEntityTrackingRange(final Entity entity, final int currentRange);
|
||||||
|
|
||||||
public static final class Holder {
|
public static final class Holder {
|
||||||
private Holder() {
|
private Holder() {
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,6 +19,13 @@ public final class IntList {
|
|||||||
return this.count;
|
return this.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void setMinCapacity(final int len) {
|
||||||
|
final int[] byIndex = this.byIndex;
|
||||||
|
if (byIndex.length < len) {
|
||||||
|
this.byIndex = Arrays.copyOf(byIndex, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public int getRaw(final int index) {
|
public int getRaw(final int index) {
|
||||||
return this.byIndex[index];
|
return this.byIndex[index];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package ca.spottedleaf.moonrise.common.list;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.shorts.Short2ShortOpenHashMap;
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
|
public final class ShortList {
|
||||||
|
|
||||||
|
private final Short2ShortOpenHashMap map = new Short2ShortOpenHashMap();
|
||||||
|
{
|
||||||
|
this.map.defaultReturnValue(Short.MIN_VALUE);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static final short[] EMPTY_LIST = new short[0];
|
||||||
|
|
||||||
|
private short[] byIndex = EMPTY_LIST;
|
||||||
|
private short count;
|
||||||
|
|
||||||
|
public int size() {
|
||||||
|
return (int)this.count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public short getRaw(final int index) {
|
||||||
|
return this.byIndex[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setMinCapacity(final int len) {
|
||||||
|
final short[] byIndex = this.byIndex;
|
||||||
|
if (byIndex.length < len) {
|
||||||
|
this.byIndex = Arrays.copyOf(byIndex, len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean add(final short value) {
|
||||||
|
final int count = (int)this.count;
|
||||||
|
final short currIndex = this.map.putIfAbsent(value, (short)count);
|
||||||
|
|
||||||
|
if (currIndex != Short.MIN_VALUE) {
|
||||||
|
return false; // already in this list
|
||||||
|
}
|
||||||
|
|
||||||
|
short[] list = this.byIndex;
|
||||||
|
|
||||||
|
if (list.length == count) {
|
||||||
|
// resize required
|
||||||
|
list = this.byIndex = Arrays.copyOf(list, (int)Math.max(4L, count * 2L)); // overflow results in negative
|
||||||
|
}
|
||||||
|
|
||||||
|
list[count] = value;
|
||||||
|
this.count = (short)(count + 1);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean remove(final short value) {
|
||||||
|
final short index = this.map.remove(value);
|
||||||
|
if (index == Short.MIN_VALUE) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// move the entry at the end to this index
|
||||||
|
final short endIndex = --this.count;
|
||||||
|
final short end = this.byIndex[endIndex];
|
||||||
|
if (index != endIndex) {
|
||||||
|
// not empty after this call
|
||||||
|
this.map.put(end, index);
|
||||||
|
}
|
||||||
|
this.byIndex[(int)index] = end;
|
||||||
|
this.byIndex[(int)endIndex] = (short)0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
this.count = (short)0;
|
||||||
|
this.map.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,13 +4,17 @@ import ca.spottedleaf.moonrise.common.list.ReferenceList;
|
|||||||
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
||||||
import ca.spottedleaf.moonrise.common.util.MoonriseConstants;
|
import ca.spottedleaf.moonrise.common.util.MoonriseConstants;
|
||||||
import ca.spottedleaf.moonrise.common.util.ChunkSystem;
|
import ca.spottedleaf.moonrise.common.util.ChunkSystem;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkData;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickConstants;
|
import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickConstants;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickServerLevel;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2ReferenceOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
public final class NearbyPlayers {
|
public final class NearbyPlayers {
|
||||||
|
|
||||||
@@ -20,7 +24,27 @@ public final class NearbyPlayers {
|
|||||||
GENERAL_REALLY_SMALL,
|
GENERAL_REALLY_SMALL,
|
||||||
TICK_VIEW_DISTANCE,
|
TICK_VIEW_DISTANCE,
|
||||||
VIEW_DISTANCE,
|
VIEW_DISTANCE,
|
||||||
SPAWN_RANGE, // Moonrise - chunk tick iteration
|
// Moonrise start - chunk tick iteration
|
||||||
|
SPAWN_RANGE {
|
||||||
|
@Override
|
||||||
|
void addTo(final ServerPlayer player, final ServerLevel world, final int chunkX, final int chunkZ) {
|
||||||
|
((ChunkTickServerLevel)world).moonrise$addPlayerTickingRequest(chunkX, chunkZ);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
void removeFrom(final ServerPlayer player, final ServerLevel world, final int chunkX, final int chunkZ) {
|
||||||
|
((ChunkTickServerLevel)world).moonrise$removePlayerTickingRequest(chunkX, chunkZ);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Moonrise end - chunk tick iteration
|
||||||
|
|
||||||
|
void addTo(final ServerPlayer player, final ServerLevel world, final int chunkX, final int chunkZ) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void removeFrom(final ServerPlayer player, final ServerLevel world, final int chunkX, final int chunkZ) {
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final NearbyMapType[] MAP_TYPES = NearbyMapType.values();
|
private static final NearbyMapType[] MAP_TYPES = NearbyMapType.values();
|
||||||
@@ -37,6 +61,12 @@ public final class NearbyPlayers {
|
|||||||
private final ServerLevel world;
|
private final ServerLevel world;
|
||||||
private final Reference2ReferenceOpenHashMap<ServerPlayer, TrackedPlayer[]> players = new Reference2ReferenceOpenHashMap<>();
|
private final Reference2ReferenceOpenHashMap<ServerPlayer, TrackedPlayer[]> players = new Reference2ReferenceOpenHashMap<>();
|
||||||
private final Long2ReferenceOpenHashMap<TrackedChunk> byChunk = new Long2ReferenceOpenHashMap<>();
|
private final Long2ReferenceOpenHashMap<TrackedChunk> byChunk = new Long2ReferenceOpenHashMap<>();
|
||||||
|
private final Long2ReferenceOpenHashMap<ReferenceList<ServerPlayer>>[] directByChunk = new Long2ReferenceOpenHashMap[TOTAL_MAP_TYPES];
|
||||||
|
{
|
||||||
|
for (int i = 0; i < this.directByChunk.length; ++i) {
|
||||||
|
this.directByChunk[i] = new Long2ReferenceOpenHashMap<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public NearbyPlayers(final ServerLevel world) {
|
public NearbyPlayers(final ServerLevel world) {
|
||||||
this.world = world;
|
this.world = world;
|
||||||
@@ -70,6 +100,16 @@ public final class NearbyPlayers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void clear() {
|
||||||
|
if (this.players.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (final ServerPlayer player : new ArrayList<>(this.players.keySet())) {
|
||||||
|
this.removePlayer(player);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void tickPlayer(final ServerPlayer player) {
|
public void tickPlayer(final ServerPlayer player) {
|
||||||
final TrackedPlayer[] players = this.players.get(player);
|
final TrackedPlayer[] players = this.players.get(player);
|
||||||
if (players == null) {
|
if (players == null) {
|
||||||
@@ -94,38 +134,41 @@ public final class NearbyPlayers {
|
|||||||
return this.byChunk.get(CoordinateUtils.getChunkKey(pos));
|
return this.byChunk.get(CoordinateUtils.getChunkKey(pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReferenceList<ServerPlayer> getPlayers(final BlockPos pos, final NearbyMapType type) {
|
public TrackedChunk getChunk(final int chunkX, final int chunkZ) {
|
||||||
final TrackedChunk chunk = this.byChunk.get(CoordinateUtils.getChunkKey(pos));
|
return this.byChunk.get(CoordinateUtils.getChunkKey(chunkX, chunkZ));
|
||||||
|
}
|
||||||
|
|
||||||
return chunk == null ? null : chunk.players[type.ordinal()];
|
public ReferenceList<ServerPlayer> getPlayers(final BlockPos pos, final NearbyMapType type) {
|
||||||
|
return this.directByChunk[type.ordinal()].get(CoordinateUtils.getChunkKey(pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReferenceList<ServerPlayer> getPlayers(final ChunkPos pos, final NearbyMapType type) {
|
public ReferenceList<ServerPlayer> getPlayers(final ChunkPos pos, final NearbyMapType type) {
|
||||||
final TrackedChunk chunk = this.byChunk.get(CoordinateUtils.getChunkKey(pos));
|
return this.directByChunk[type.ordinal()].get(CoordinateUtils.getChunkKey(pos));
|
||||||
|
|
||||||
return chunk == null ? null : chunk.players[type.ordinal()];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReferenceList<ServerPlayer> getPlayersByChunk(final int chunkX, final int chunkZ, final NearbyMapType type) {
|
public ReferenceList<ServerPlayer> getPlayersByChunk(final int chunkX, final int chunkZ, final NearbyMapType type) {
|
||||||
final TrackedChunk chunk = this.byChunk.get(CoordinateUtils.getChunkKey(chunkX, chunkZ));
|
return this.directByChunk[type.ordinal()].get(CoordinateUtils.getChunkKey(chunkX, chunkZ));
|
||||||
|
|
||||||
return chunk == null ? null : chunk.players[type.ordinal()];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReferenceList<ServerPlayer> getPlayersByBlock(final int blockX, final int blockZ, final NearbyMapType type) {
|
public ReferenceList<ServerPlayer> getPlayersByBlock(final int blockX, final int blockZ, final NearbyMapType type) {
|
||||||
final TrackedChunk chunk = this.byChunk.get(CoordinateUtils.getChunkKey(blockX >> 4, blockZ >> 4));
|
return this.directByChunk[type.ordinal()].get(CoordinateUtils.getChunkKey(blockX >> 4, blockZ >> 4));
|
||||||
|
|
||||||
return chunk == null ? null : chunk.players[type.ordinal()];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static final class TrackedChunk {
|
public static final class TrackedChunk {
|
||||||
|
|
||||||
private static final ServerPlayer[] EMPTY_PLAYERS_ARRAY = new ServerPlayer[0];
|
private static final ServerPlayer[] EMPTY_PLAYERS_ARRAY = new ServerPlayer[0];
|
||||||
|
|
||||||
|
private final long chunkKey;
|
||||||
|
private final NearbyPlayers nearbyPlayers;
|
||||||
private final ReferenceList<ServerPlayer>[] players = new ReferenceList[TOTAL_MAP_TYPES];
|
private final ReferenceList<ServerPlayer>[] players = new ReferenceList[TOTAL_MAP_TYPES];
|
||||||
private int nonEmptyLists;
|
private int nonEmptyLists;
|
||||||
private long updateCount;
|
private long updateCount;
|
||||||
|
|
||||||
|
public TrackedChunk(final long chunkKey, final NearbyPlayers nearbyPlayers) {
|
||||||
|
this.chunkKey = chunkKey;
|
||||||
|
this.nearbyPlayers = nearbyPlayers;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isEmpty() {
|
public boolean isEmpty() {
|
||||||
return this.nonEmptyLists == 0;
|
return this.nonEmptyLists == 0;
|
||||||
}
|
}
|
||||||
@@ -145,7 +188,10 @@ public final class NearbyPlayers {
|
|||||||
final ReferenceList<ServerPlayer> list = this.players[idx];
|
final ReferenceList<ServerPlayer> list = this.players[idx];
|
||||||
if (list == null) {
|
if (list == null) {
|
||||||
++this.nonEmptyLists;
|
++this.nonEmptyLists;
|
||||||
(this.players[idx] = new ReferenceList<>(EMPTY_PLAYERS_ARRAY)).add(player);
|
final ReferenceList<ServerPlayer> players = (this.players[idx] = new ReferenceList<>(EMPTY_PLAYERS_ARRAY));
|
||||||
|
this.nearbyPlayers.directByChunk[idx].put(this.chunkKey, players);
|
||||||
|
players.add(player);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,6 +215,7 @@ public final class NearbyPlayers {
|
|||||||
|
|
||||||
if (list.size() == 0) {
|
if (list.size() == 0) {
|
||||||
this.players[idx] = null;
|
this.players[idx] = null;
|
||||||
|
this.nearbyPlayers.directByChunk[idx].remove(this.chunkKey);
|
||||||
--this.nonEmptyLists;
|
--this.nonEmptyLists;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -187,9 +234,19 @@ public final class NearbyPlayers {
|
|||||||
protected void addCallback(final ServerPlayer parameter, final int chunkX, final int chunkZ) {
|
protected void addCallback(final ServerPlayer parameter, final int chunkX, final int chunkZ) {
|
||||||
final long chunkKey = CoordinateUtils.getChunkKey(chunkX, chunkZ);
|
final long chunkKey = CoordinateUtils.getChunkKey(chunkX, chunkZ);
|
||||||
|
|
||||||
NearbyPlayers.this.byChunk.computeIfAbsent(chunkKey, (final long keyInMap) -> {
|
final TrackedChunk chunk = NearbyPlayers.this.byChunk.get(chunkKey);
|
||||||
return new TrackedChunk();
|
final NearbyMapType type = this.type;
|
||||||
}).addPlayer(parameter, this.type);
|
if (chunk != null) {
|
||||||
|
chunk.addPlayer(parameter, type);
|
||||||
|
type.addTo(parameter, NearbyPlayers.this.world, chunkX, chunkZ);
|
||||||
|
} else {
|
||||||
|
final TrackedChunk created = new TrackedChunk(chunkKey, NearbyPlayers.this);
|
||||||
|
NearbyPlayers.this.byChunk.put(chunkKey, created);
|
||||||
|
created.addPlayer(parameter, type);
|
||||||
|
type.addTo(parameter, NearbyPlayers.this.world, chunkX, chunkZ);
|
||||||
|
|
||||||
|
((ChunkSystemLevel)NearbyPlayers.this.world).moonrise$requestChunkData(chunkKey).nearbyPlayers = created;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -201,10 +258,16 @@ public final class NearbyPlayers {
|
|||||||
throw new IllegalStateException("Chunk should exist at " + new ChunkPos(chunkKey));
|
throw new IllegalStateException("Chunk should exist at " + new ChunkPos(chunkKey));
|
||||||
}
|
}
|
||||||
|
|
||||||
chunk.removePlayer(parameter, this.type);
|
final NearbyMapType type = this.type;
|
||||||
|
chunk.removePlayer(parameter, type);
|
||||||
|
type.removeFrom(parameter, NearbyPlayers.this.world, chunkX, chunkZ);
|
||||||
|
|
||||||
if (chunk.isEmpty()) {
|
if (chunk.isEmpty()) {
|
||||||
NearbyPlayers.this.byChunk.remove(chunkKey);
|
NearbyPlayers.this.byChunk.remove(chunkKey);
|
||||||
|
final ChunkData chunkData = ((ChunkSystemLevel)NearbyPlayers.this.world).moonrise$releaseChunkData(chunkKey);
|
||||||
|
if (chunkData != null) {
|
||||||
|
chunkData.nearbyPlayers = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package ca.spottedleaf.moonrise.common.misc;
|
|||||||
|
|
||||||
import ca.spottedleaf.concurrentutil.util.IntPairUtil;
|
import ca.spottedleaf.concurrentutil.util.IntPairUtil;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
||||||
|
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||||
import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.objects.ReferenceSet;
|
import it.unimi.dsi.fastutil.objects.ReferenceSet;
|
||||||
|
|
||||||
@@ -14,6 +15,10 @@ public final class PositionCountingAreaMap<T> {
|
|||||||
return this.counters.keySet();
|
return this.counters.keySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public LongSet getPositions() {
|
||||||
|
return this.positions.keySet();
|
||||||
|
}
|
||||||
|
|
||||||
public int getTotalPositions() {
|
public int getTotalPositions() {
|
||||||
return this.positions.size();
|
return this.positions.size();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel
|
|||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader;
|
import ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemServerChunkCache;
|
import ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemServerChunkCache;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickServerLevel;
|
||||||
import com.mojang.logging.LogUtils;
|
import com.mojang.logging.LogUtils;
|
||||||
import net.minecraft.server.level.ChunkHolder;
|
import net.minecraft.server.level.ChunkHolder;
|
||||||
import net.minecraft.server.level.FullChunkStatus;
|
import net.minecraft.server.level.FullChunkStatus;
|
||||||
@@ -117,16 +118,18 @@ public final class ChunkSystem {
|
|||||||
((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder()
|
((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder()
|
||||||
);
|
);
|
||||||
if (!((ChunkSystemLevelChunk)chunk).moonrise$isPostProcessingDone()) {
|
if (!((ChunkSystemLevelChunk)chunk).moonrise$isPostProcessingDone()) {
|
||||||
chunk.postProcessGeneration();
|
chunk.postProcessGeneration((ServerLevel)chunk.getLevel());
|
||||||
}
|
}
|
||||||
((ServerLevel)chunk.getLevel()).startTickingChunk(chunk);
|
((ServerLevel)chunk.getLevel()).startTickingChunk(chunk);
|
||||||
((ServerLevel)chunk.getLevel()).getChunkSource().chunkMap.tickingGenerated.incrementAndGet();
|
((ServerLevel)chunk.getLevel()).getChunkSource().chunkMap.tickingGenerated.incrementAndGet();
|
||||||
|
((ChunkTickServerLevel)(ServerLevel)chunk.getLevel()).moonrise$markChunkForPlayerTicking(chunk); // Moonrise - chunk tick iteration
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void onChunkNotTicking(final LevelChunk chunk, final ChunkHolder holder) {
|
public static void onChunkNotTicking(final LevelChunk chunk, final ChunkHolder holder) {
|
||||||
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getTickingChunks().remove(
|
((ChunkSystemServerLevel)((ServerLevel)chunk.getLevel())).moonrise$getTickingChunks().remove(
|
||||||
((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder()
|
((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder()
|
||||||
);
|
);
|
||||||
|
((ChunkTickServerLevel)(ServerLevel)chunk.getLevel()).moonrise$removeChunkForPlayerTicking(chunk); // Moonrise - chunk tick iteration
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void onChunkEntityTicking(final LevelChunk chunk, final ChunkHolder holder) {
|
public static void onChunkEntityTicking(final LevelChunk chunk, final ChunkHolder holder) {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package ca.spottedleaf.moonrise.common.util;
|
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.adapter.TypeAdapterRegistry;
|
||||||
import ca.spottedleaf.moonrise.common.config.config.YamlConfig;
|
import ca.spottedleaf.moonrise.common.config.config.YamlConfig;
|
||||||
import ca.spottedleaf.moonrise.common.config.moonrise.MoonriseConfig;
|
import ca.spottedleaf.moonrise.common.config.moonrise.MoonriseConfig;
|
||||||
@@ -13,7 +14,7 @@ public final class ConfigHolder {
|
|||||||
|
|
||||||
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigHolder.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(ConfigHolder.class);
|
||||||
|
|
||||||
private static final File CONFIG_FILE = new File(System.getProperty("Moonrise.ConfigFile", "config/moonrise.yml"));
|
private static final File CONFIG_FILE = new File(System.getProperty(PlatformHooks.get().getBrand() + ".ConfigFile", "config/moonrise.yml"));
|
||||||
private static final TypeAdapterRegistry CONFIG_ADAPTERS = new TypeAdapterRegistry();
|
private static final TypeAdapterRegistry CONFIG_ADAPTERS = new TypeAdapterRegistry();
|
||||||
private static final YamlConfig<MoonriseConfig> CONFIG;
|
private static final YamlConfig<MoonriseConfig> CONFIG;
|
||||||
static {
|
static {
|
||||||
@@ -25,7 +26,7 @@ public final class ConfigHolder {
|
|||||||
throw new RuntimeException(ex);
|
throw new RuntimeException(ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private static final String CONFIG_HEADER = """
|
private static final String CONFIG_HEADER = String.format("""
|
||||||
This is the configuration file for Moonrise.
|
This is the configuration file for Moonrise.
|
||||||
|
|
||||||
Each configuration option is prefixed with a comment to explain what it does. Additional changes to this file
|
Each configuration option is prefixed with a comment to explain what it does. Additional changes to this file
|
||||||
@@ -33,9 +34,10 @@ public final class ConfigHolder {
|
|||||||
|
|
||||||
Below are the Moonrise startup flags. Note that startup flags must be placed in the JVM arguments, not
|
Below are the Moonrise startup flags. Note that startup flags must be placed in the JVM arguments, not
|
||||||
program arguments.
|
program arguments.
|
||||||
-DMoonrise.ConfigFile=<file> - Override the config file location. Might be useful for multiple game versions.
|
-D%1$s.ConfigFile=<file> - Override the config file location. Might be useful for multiple game versions.
|
||||||
-DMoonrise.WorkerThreadCount=<number> - Override the auto configured worker thread counts (worker-threads).
|
-D%1$s.WorkerThreadCount=<number> - Override the auto configured worker thread counts (worker-threads).
|
||||||
""";
|
-D%1$s.MaxViewDistance=<number> - Overrides the maximum view distance, should only use for debugging purposes.
|
||||||
|
""", PlatformHooks.get().getBrand());
|
||||||
|
|
||||||
static {
|
static {
|
||||||
reloadConfig();
|
reloadConfig();
|
||||||
|
|||||||
@@ -3,8 +3,12 @@ package ca.spottedleaf.moonrise.common.util;
|
|||||||
public final class MixinWorkarounds {
|
public final class MixinWorkarounds {
|
||||||
|
|
||||||
// mixins tries to find the owner of the clone() method, which doesn't exist and NPEs
|
// mixins tries to find the owner of the clone() method, which doesn't exist and NPEs
|
||||||
|
// https://github.com/FabricMC/Mixin/pull/147
|
||||||
public static long[] clone(final long[] values) {
|
public static long[] clone(final long[] values) {
|
||||||
return values.clone();
|
return values.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static byte[] clone(final byte[] values) {
|
||||||
|
return values.clone();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public final class MoonriseCommon {
|
|||||||
@Override
|
@Override
|
||||||
public void accept(Thread thread) {
|
public void accept(Thread thread) {
|
||||||
thread.setDaemon(true);
|
thread.setDaemon(true);
|
||||||
thread.setName("Moonrise Common Worker #" + this.idGenerator.getAndIncrement());
|
thread.setName(PlatformHooks.get().getBrand() + " Common Worker #" + this.idGenerator.getAndIncrement());
|
||||||
thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
|
thread.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
|
||||||
@Override
|
@Override
|
||||||
public void uncaughtException(final Thread thread, final Throwable throwable) {
|
public void uncaughtException(final Thread thread, final Throwable throwable) {
|
||||||
@@ -44,7 +44,7 @@ public final class MoonriseCommon {
|
|||||||
} else {
|
} else {
|
||||||
defaultWorkerThreads = defaultWorkerThreads / 2;
|
defaultWorkerThreads = defaultWorkerThreads / 2;
|
||||||
}
|
}
|
||||||
defaultWorkerThreads = Integer.getInteger("Moonrise.WorkerThreadCount", Integer.valueOf(defaultWorkerThreads));
|
defaultWorkerThreads = Integer.getInteger(PlatformHooks.get().getBrand() + ".WorkerThreadCount", Integer.valueOf(defaultWorkerThreads));
|
||||||
|
|
||||||
int workerThreads = configWorkerThreads;
|
int workerThreads = configWorkerThreads;
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package ca.spottedleaf.moonrise.common.util;
|
package ca.spottedleaf.moonrise.common.util;
|
||||||
|
|
||||||
|
import ca.spottedleaf.moonrise.common.PlatformHooks;
|
||||||
|
|
||||||
public final class MoonriseConstants {
|
public final class MoonriseConstants {
|
||||||
|
|
||||||
public static final int MAX_VIEW_DISTANCE = 32;
|
public static final int MAX_VIEW_DISTANCE = Integer.getInteger(PlatformHooks.get().getBrand() + ".MaxViewDistance", 32);
|
||||||
|
|
||||||
private MoonriseConstants() {}
|
private MoonriseConstants() {}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ public final class SimpleRandom extends LegacyRandomSource {
|
|||||||
return (int)(seed >>> (BITS - Integer.SIZE));
|
return (int)(seed >>> (BITS - Integer.SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int nextInt(final int bound) {
|
public int nextInt(final int bound) {
|
||||||
if (bound <= 0) {
|
if (bound <= 0) {
|
||||||
|
|||||||
@@ -8,11 +8,19 @@ public final class WorldUtil {
|
|||||||
// min, max are inclusive
|
// min, max are inclusive
|
||||||
|
|
||||||
public static int getMaxSection(final LevelHeightAccessor world) {
|
public static int getMaxSection(final LevelHeightAccessor world) {
|
||||||
return world.getMaxSection() - 1; // getMaxSection() is exclusive
|
return world.getMaxSectionY();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getMaxSection(final Level world) {
|
||||||
|
return world.getMaxSectionY();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getMinSection(final LevelHeightAccessor world) {
|
public static int getMinSection(final LevelHeightAccessor world) {
|
||||||
return world.getMinSection();
|
return world.getMinSectionY();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int getMinSection(final Level world) {
|
||||||
|
return world.getMinSectionY();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int getMaxLightSection(final LevelHeightAccessor world) {
|
public static int getMaxLightSection(final LevelHeightAccessor world) {
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package ca.spottedleaf.moonrise.mixin.block_counting;
|
|||||||
import ca.spottedleaf.moonrise.patches.block_counting.BlockCountingBitStorage;
|
import ca.spottedleaf.moonrise.patches.block_counting.BlockCountingBitStorage;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||||
|
import it.unimi.dsi.fastutil.shorts.ShortArrayList;
|
||||||
import net.minecraft.util.BitStorage;
|
import net.minecraft.util.BitStorage;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
@@ -18,15 +19,15 @@ interface BitStorageMixin extends BlockCountingBitStorage {
|
|||||||
|
|
||||||
// provide default impl in case mods implement this...
|
// provide default impl in case mods implement this...
|
||||||
@Override
|
@Override
|
||||||
public default Int2ObjectOpenHashMap<IntArrayList> moonrise$countEntries() {
|
public default Int2ObjectOpenHashMap<ShortArrayList> moonrise$countEntries() {
|
||||||
final Int2ObjectOpenHashMap<IntArrayList> ret = new Int2ObjectOpenHashMap<>();
|
final Int2ObjectOpenHashMap<ShortArrayList> ret = new Int2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
final int size = this.getSize();
|
final int size = this.getSize();
|
||||||
for (int index = 0; index < size; ++index) {
|
for (int index = 0; index < size; ++index) {
|
||||||
final int paletteIdx = this.get(index);
|
final int paletteIdx = this.get(index);
|
||||||
ret.computeIfAbsent(paletteIdx, (final int key) -> {
|
ret.computeIfAbsent(paletteIdx, (final int key) -> {
|
||||||
return new IntArrayList();
|
return new ShortArrayList(64);
|
||||||
}).add(index);
|
}).add((short)index);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
package ca.spottedleaf.moonrise.mixin.block_counting;
|
package ca.spottedleaf.moonrise.mixin.block_counting;
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.list.IntList;
|
import ca.spottedleaf.moonrise.common.list.ShortList;
|
||||||
import ca.spottedleaf.moonrise.patches.block_counting.BlockCountingBitStorage;
|
import ca.spottedleaf.moonrise.patches.block_counting.BlockCountingBitStorage;
|
||||||
import ca.spottedleaf.moonrise.patches.collisions.CollisionUtil;
|
import ca.spottedleaf.moonrise.patches.collisions.CollisionUtil;
|
||||||
import ca.spottedleaf.moonrise.patches.block_counting.BlockCountingChunkSection;
|
import ca.spottedleaf.moonrise.patches.block_counting.BlockCountingChunkSection;
|
||||||
import com.llamalad7.mixinextras.sugar.Local;
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
import it.unimi.dsi.fastutil.shorts.ShortArrayList;
|
||||||
import net.minecraft.util.BitStorage;
|
import net.minecraft.util.BitStorage;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||||
@@ -48,26 +48,32 @@ abstract class LevelChunkSectionMixin implements BlockCountingChunkSection {
|
|||||||
public abstract boolean maybeHas(Predicate<BlockState> predicate);
|
public abstract boolean maybeHas(Predicate<BlockState> predicate);
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private static final IntArrayList FULL_LIST = new IntArrayList(16*16*16);
|
private static final ShortArrayList FULL_LIST = new ShortArrayList(16*16*16);
|
||||||
static {
|
static {
|
||||||
for (int i = 0; i < (16*16*16); ++i) {
|
for (short i = 0; i < (16*16*16); ++i) {
|
||||||
FULL_LIST.add(i);
|
FULL_LIST.add(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private int specialCollidingBlocks;
|
private boolean isClient;
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private final IntList tickingBlocks = new IntList();
|
private static final short CLIENT_FORCED_SPECIAL_COLLIDING_BLOCKS = (short)9999;
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private short specialCollidingBlocks;
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private final ShortList tickingBlocks = new ShortList();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final int moonrise$getSpecialCollidingBlocks() {
|
public final boolean moonrise$hasSpecialCollidingBlocks() {
|
||||||
return this.specialCollidingBlocks;
|
return this.specialCollidingBlocks != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final IntList moonrise$getTickingBlockList() {
|
public final ShortList moonrise$getTickingBlockList() {
|
||||||
return this.tickingBlocks;
|
return this.tickingBlocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,20 +92,35 @@ abstract class LevelChunkSectionMixin implements BlockCountingChunkSection {
|
|||||||
if (oldState == newState) {
|
if (oldState == newState) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (CollisionUtil.isSpecialCollidingBlock(oldState)) {
|
|
||||||
--this.specialCollidingBlocks;
|
if (this.isClient) {
|
||||||
}
|
|
||||||
if (CollisionUtil.isSpecialCollidingBlock(newState)) {
|
if (CollisionUtil.isSpecialCollidingBlock(newState)) {
|
||||||
|
this.specialCollidingBlocks = CLIENT_FORCED_SPECIAL_COLLIDING_BLOCKS;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean isSpecialOld = CollisionUtil.isSpecialCollidingBlock(oldState);
|
||||||
|
final boolean isSpecialNew = CollisionUtil.isSpecialCollidingBlock(newState);
|
||||||
|
if (isSpecialOld != isSpecialNew) {
|
||||||
|
if (isSpecialOld) {
|
||||||
|
--this.specialCollidingBlocks;
|
||||||
|
} else {
|
||||||
++this.specialCollidingBlocks;
|
++this.specialCollidingBlocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int position = x | (z << 4) | (y << (4+4));
|
|
||||||
|
|
||||||
if (oldState.isRandomlyTicking()) {
|
|
||||||
this.tickingBlocks.remove(position);
|
|
||||||
}
|
}
|
||||||
if (newState.isRandomlyTicking()) {
|
|
||||||
this.tickingBlocks.add(position);
|
final boolean oldTicking = oldState.isRandomlyTicking();
|
||||||
|
final boolean newTicking = newState.isRandomlyTicking();
|
||||||
|
if (oldTicking != newTicking) {
|
||||||
|
final ShortList tickingBlocks = this.tickingBlocks;
|
||||||
|
final short position = (short)(x | (z << 4) | (y << (4+4)));
|
||||||
|
|
||||||
|
if (oldTicking) {
|
||||||
|
tickingBlocks.remove(position);
|
||||||
|
} else {
|
||||||
|
tickingBlocks.add(position);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,11 +154,11 @@ abstract class LevelChunkSectionMixin implements BlockCountingChunkSection {
|
|||||||
|
|
||||||
if (this.maybeHas((final BlockState state) -> !state.isAir())) {
|
if (this.maybeHas((final BlockState state) -> !state.isAir())) {
|
||||||
final PalettedContainer.Data<BlockState> data = this.states.data;
|
final PalettedContainer.Data<BlockState> data = this.states.data;
|
||||||
final Palette<BlockState> palette = data.palette;
|
final Palette<BlockState> palette = data.palette();
|
||||||
final int paletteSize = palette.getSize();
|
final int paletteSize = palette.getSize();
|
||||||
final BitStorage storage = data.storage;
|
final BitStorage storage = data.storage();
|
||||||
|
|
||||||
final Int2ObjectOpenHashMap<IntArrayList> counts;
|
final Int2ObjectOpenHashMap<ShortArrayList> counts;
|
||||||
if (paletteSize == 1) {
|
if (paletteSize == 1) {
|
||||||
counts = new Int2ObjectOpenHashMap<>(1);
|
counts = new Int2ObjectOpenHashMap<>(1);
|
||||||
counts.put(0, FULL_LIST);
|
counts.put(0, FULL_LIST);
|
||||||
@@ -145,10 +166,10 @@ abstract class LevelChunkSectionMixin implements BlockCountingChunkSection {
|
|||||||
counts = ((BlockCountingBitStorage)storage).moonrise$countEntries();
|
counts = ((BlockCountingBitStorage)storage).moonrise$countEntries();
|
||||||
}
|
}
|
||||||
|
|
||||||
for (final Iterator<Int2ObjectMap.Entry<IntArrayList>> iterator = counts.int2ObjectEntrySet().fastIterator(); iterator.hasNext();) {
|
for (final Iterator<Int2ObjectMap.Entry<ShortArrayList>> iterator = counts.int2ObjectEntrySet().fastIterator(); iterator.hasNext();) {
|
||||||
final Int2ObjectMap.Entry<IntArrayList> entry = iterator.next();
|
final Int2ObjectMap.Entry<ShortArrayList> entry = iterator.next();
|
||||||
final int paletteIdx = entry.getIntKey();
|
final int paletteIdx = entry.getIntKey();
|
||||||
final IntArrayList coordinates = entry.getValue();
|
final ShortArrayList coordinates = entry.getValue();
|
||||||
final int paletteCount = coordinates.size();
|
final int paletteCount = coordinates.size();
|
||||||
|
|
||||||
final BlockState state = palette.valueFor(paletteIdx);
|
final BlockState state = palette.valueFor(paletteIdx);
|
||||||
@@ -158,16 +179,21 @@ abstract class LevelChunkSectionMixin implements BlockCountingChunkSection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (CollisionUtil.isSpecialCollidingBlock(state)) {
|
if (CollisionUtil.isSpecialCollidingBlock(state)) {
|
||||||
this.specialCollidingBlocks += paletteCount;
|
this.specialCollidingBlocks += (short)paletteCount;
|
||||||
}
|
}
|
||||||
this.nonEmptyBlockCount += paletteCount;
|
this.nonEmptyBlockCount += (short)paletteCount;
|
||||||
if (state.isRandomlyTicking()) {
|
if (state.isRandomlyTicking()) {
|
||||||
this.tickingBlockCount += paletteCount;
|
this.tickingBlockCount += (short)paletteCount;
|
||||||
final int[] raw = coordinates.elements();
|
final short[] raw = coordinates.elements();
|
||||||
|
final int rawLen = raw.length;
|
||||||
|
|
||||||
Objects.checkFromToIndex(0, paletteCount, raw.length);
|
final ShortList tickingBlocks = this.tickingBlocks;
|
||||||
|
|
||||||
|
tickingBlocks.setMinCapacity(Math.min((rawLen + tickingBlocks.size()) * 3 / 2, 16*16*16));
|
||||||
|
|
||||||
|
Objects.checkFromToIndex(0, paletteCount, rawLen);
|
||||||
for (int i = 0; i < paletteCount; ++i) {
|
for (int i = 0; i < paletteCount; ++i) {
|
||||||
this.tickingBlocks.add(raw[i]);
|
tickingBlocks.add(raw[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,7 +202,7 @@ abstract class LevelChunkSectionMixin implements BlockCountingChunkSection {
|
|||||||
if (!fluid.isEmpty()) {
|
if (!fluid.isEmpty()) {
|
||||||
//this.nonEmptyBlockCount += count; // fix vanilla bug: make non-empty block count correct
|
//this.nonEmptyBlockCount += count; // fix vanilla bug: make non-empty block count correct
|
||||||
if (fluid.isRandomlyTicking()) {
|
if (fluid.isRandomlyTicking()) {
|
||||||
this.tickingFluidCount += paletteCount;
|
this.tickingFluidCount += (short)paletteCount;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -184,7 +210,7 @@ abstract class LevelChunkSectionMixin implements BlockCountingChunkSection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Call recalcBlockCounts on the client, as the client does not invoke it when deserializing chunk sections.
|
* @reason Set up special colliding blocks on the client, as it is too expensive to perform a full calculation
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Inject(
|
@Inject(
|
||||||
@@ -194,6 +220,8 @@ abstract class LevelChunkSectionMixin implements BlockCountingChunkSection {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
private void callRecalcBlocksClient(final CallbackInfo ci) {
|
private void callRecalcBlocksClient(final CallbackInfo ci) {
|
||||||
this.recalcBlockCounts();
|
this.isClient = true;
|
||||||
|
// force has special colliding blocks to be true
|
||||||
|
this.specialCollidingBlocks = this.nonEmptyBlockCount != (short)0 && this.maybeHas(CollisionUtil::isSpecialCollidingBlock) ? CLIENT_FORCED_SPECIAL_COLLIDING_BLOCKS : (short)0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package ca.spottedleaf.moonrise.mixin.block_counting;
|
|||||||
import ca.spottedleaf.moonrise.patches.block_counting.BlockCountingBitStorage;
|
import ca.spottedleaf.moonrise.patches.block_counting.BlockCountingBitStorage;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||||
|
import it.unimi.dsi.fastutil.shorts.ShortArrayList;
|
||||||
import net.minecraft.util.BitStorage;
|
import net.minecraft.util.BitStorage;
|
||||||
import net.minecraft.util.SimpleBitStorage;
|
import net.minecraft.util.SimpleBitStorage;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
import org.spongepowered.asm.mixin.Final;
|
||||||
@@ -24,24 +25,48 @@ abstract class SimpleBitStorageMixin implements BitStorage, BlockCountingBitStor
|
|||||||
@Final
|
@Final
|
||||||
private int bits;
|
private int bits;
|
||||||
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
private long mask;
|
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
@Final
|
@Final
|
||||||
private int size;
|
private int size;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final Int2ObjectOpenHashMap<IntArrayList> moonrise$countEntries() {
|
public final Int2ObjectOpenHashMap<ShortArrayList> moonrise$countEntries() {
|
||||||
final int valuesPerLong = this.valuesPerLong;
|
final int valuesPerLong = this.valuesPerLong;
|
||||||
final int bits = this.bits;
|
final int bits = this.bits;
|
||||||
final long mask = this.mask;
|
final long mask = (1L << bits) - 1L;
|
||||||
final int size = this.size;
|
final int size = this.size;
|
||||||
|
|
||||||
// we may be backed by global palette, so limit bits for init capacity
|
if (bits <= 6) {
|
||||||
final Int2ObjectOpenHashMap<IntArrayList> ret = new Int2ObjectOpenHashMap<>(
|
final ShortArrayList[] byId = new ShortArrayList[1 << bits];
|
||||||
1 << Math.min(6, bits)
|
final Int2ObjectOpenHashMap<ShortArrayList> ret = new Int2ObjectOpenHashMap<>(1 << bits);
|
||||||
|
|
||||||
|
int index = 0;
|
||||||
|
|
||||||
|
for (long value : this.data) {
|
||||||
|
int li = 0;
|
||||||
|
do {
|
||||||
|
final int paletteIdx = (int)(value & mask);
|
||||||
|
value >>= bits;
|
||||||
|
++li;
|
||||||
|
|
||||||
|
final ShortArrayList coords = byId[paletteIdx];
|
||||||
|
if (coords != null) {
|
||||||
|
coords.add((short)index++);
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
final ShortArrayList newCoords = new ShortArrayList(64);
|
||||||
|
byId[paletteIdx] = newCoords;
|
||||||
|
newCoords.add((short)index++);
|
||||||
|
ret.put(paletteIdx, newCoords);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
} while (li < valuesPerLong && index < size);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
} else {
|
||||||
|
final Int2ObjectOpenHashMap<ShortArrayList> ret = new Int2ObjectOpenHashMap<>(
|
||||||
|
1 << 6
|
||||||
);
|
);
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
@@ -51,16 +76,15 @@ abstract class SimpleBitStorageMixin implements BitStorage, BlockCountingBitStor
|
|||||||
do {
|
do {
|
||||||
final int paletteIdx = (int)(value & mask);
|
final int paletteIdx = (int)(value & mask);
|
||||||
value >>= bits;
|
value >>= bits;
|
||||||
|
++li;
|
||||||
|
|
||||||
ret.computeIfAbsent(paletteIdx, (final int key) -> {
|
ret.computeIfAbsent(paletteIdx, (final int key) -> {
|
||||||
return new IntArrayList();
|
return new ShortArrayList(64);
|
||||||
}).add(index);
|
}).add((short)index++);
|
||||||
|
|
||||||
++li;
|
|
||||||
++index;
|
|
||||||
} while (li < valuesPerLong && index < size);
|
} while (li < valuesPerLong && index < size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package ca.spottedleaf.moonrise.mixin.block_counting;
|
|||||||
import ca.spottedleaf.moonrise.patches.block_counting.BlockCountingBitStorage;
|
import ca.spottedleaf.moonrise.patches.block_counting.BlockCountingBitStorage;
|
||||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
import it.unimi.dsi.fastutil.ints.IntArrayList;
|
||||||
|
import it.unimi.dsi.fastutil.shorts.ShortArrayList;
|
||||||
import net.minecraft.util.BitStorage;
|
import net.minecraft.util.BitStorage;
|
||||||
import net.minecraft.util.ZeroBitStorage;
|
import net.minecraft.util.ZeroBitStorage;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
import org.spongepowered.asm.mixin.Final;
|
||||||
@@ -17,17 +18,17 @@ abstract class ZeroBitStorageMixin implements BitStorage, BlockCountingBitStorag
|
|||||||
private int size;
|
private int size;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final Int2ObjectOpenHashMap<IntArrayList> moonrise$countEntries() {
|
public final Int2ObjectOpenHashMap<ShortArrayList> moonrise$countEntries() {
|
||||||
final int size = this.size;
|
final int size = this.size;
|
||||||
|
|
||||||
final int[] raw = new int[size];
|
final short[] raw = new short[size];
|
||||||
for (int i = 0; i < size; ++i) {
|
for (int i = 0; i < size; ++i) {
|
||||||
raw[i] = i;
|
raw[i] = (short)i;
|
||||||
}
|
}
|
||||||
|
|
||||||
final IntArrayList coordinates = IntArrayList.wrap(raw, size);
|
final ShortArrayList coordinates = ShortArrayList.wrap(raw, size);
|
||||||
|
|
||||||
final Int2ObjectOpenHashMap<IntArrayList> ret = new Int2ObjectOpenHashMap<>(1);
|
final Int2ObjectOpenHashMap<ShortArrayList> ret = new Int2ObjectOpenHashMap<>(1);
|
||||||
ret.put(0, coordinates);
|
ret.put(0, coordinates);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import com.llamalad7.mixinextras.injector.wrapoperation.WrapOperation;
|
|||||||
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
import net.minecraft.world.level.block.state.properties.BooleanProperty;
|
||||||
import net.minecraft.world.level.block.state.properties.Property;
|
import net.minecraft.world.level.block.state.properties.Property;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Constant;
|
import org.spongepowered.asm.mixin.injection.Constant;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
@@ -17,6 +18,9 @@ abstract class BooleanPropertyMixin extends Property<Boolean> implements Propert
|
|||||||
super(string, class_);
|
super(string, class_);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private static final Boolean[] BY_ID = new Boolean[]{ Boolean.FALSE, Boolean.TRUE };
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final int moonrise$getIdFor(final Boolean value) {
|
public final int moonrise$getIdFor(final Boolean value) {
|
||||||
return value.booleanValue() ? 1 : 0;
|
return value.booleanValue() ? 1 : 0;
|
||||||
@@ -33,23 +37,6 @@ abstract class BooleanPropertyMixin extends Property<Boolean> implements Propert
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
private void init(final CallbackInfo ci) {
|
private void init(final CallbackInfo ci) {
|
||||||
this.moonrise$setById(new Boolean[]{ Boolean.FALSE, Boolean.TRUE });
|
this.moonrise$setById(BY_ID);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This skips all ops after the identity comparison in the original code.
|
|
||||||
*
|
|
||||||
* @reason Properties are identity comparable
|
|
||||||
* @author Spottedleaf
|
|
||||||
*/
|
|
||||||
@WrapOperation(
|
|
||||||
method = "equals",
|
|
||||||
constant = @Constant(
|
|
||||||
classValue = BooleanProperty.class,
|
|
||||||
ordinal = 0
|
|
||||||
)
|
|
||||||
)
|
|
||||||
private boolean skipFurtherComparison(final Object obj, final Operation<Boolean> orig) {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,9 +18,6 @@ import java.util.Collection;
|
|||||||
@Mixin(EnumProperty.class)
|
@Mixin(EnumProperty.class)
|
||||||
abstract class EnumPropertyMixin<T extends Enum<T> & StringRepresentable> extends Property<T> implements PropertyAccess<T> {
|
abstract class EnumPropertyMixin<T extends Enum<T> & StringRepresentable> extends Property<T> implements PropertyAccess<T> {
|
||||||
|
|
||||||
@Shadow
|
|
||||||
public abstract Collection<T> getPossibleValues();
|
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private int[] idLookupTable;
|
private int[] idLookupTable;
|
||||||
|
|
||||||
|
|||||||
@@ -83,7 +83,6 @@ abstract class StateHolderMixin<O, S> implements PropertyAccessStateHolder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// remove values arrays
|
// remove values arrays
|
||||||
this.values = null;
|
|
||||||
for (final Map.Entry<Map<Property<?>, Comparable<?>>, S> entry : map.entrySet()) {
|
for (final Map.Entry<Map<Property<?>, Comparable<?>>, S> entry : map.entrySet()) {
|
||||||
final S value = entry.getValue();
|
final S value = entry.getValue();
|
||||||
((StateHolderMixin<O, S>)(Object)(StateHolder<O, S>)value).values = null;
|
((StateHolderMixin<O, S>)(Object)(StateHolder<O, S>)value).values = null;
|
||||||
@@ -126,8 +125,8 @@ abstract class StateHolderMixin<O, S> implements PropertyAccessStateHolder {
|
|||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public <T extends Comparable<T>> Optional<T> getOptionalValue(final Property<T> property) {
|
public <T extends Comparable<T>> T getNullableValue(Property<T> property) {
|
||||||
return property == null ? Optional.empty() : Optional.ofNullable(this.optimisedTable.get(this.tableIndex, property));
|
return property == null ? null : this.optimisedTable.get(this.tableIndex, property);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -302,6 +302,10 @@ abstract class ChunkHolderMixin extends GenerationChunkHolder implements ChunkSy
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
private LevelChunk redirectLightUpdate(final ChunkHolder instance) {
|
private LevelChunk redirectLightUpdate(final ChunkHolder instance) {
|
||||||
|
if (this.playersSentChunkTo.size() == 0) {
|
||||||
|
// no players to sent to, so don't need to update anything
|
||||||
|
return null;
|
||||||
|
}
|
||||||
return this.getChunkToSend();
|
return this.getChunkToSend();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,14 +11,17 @@ import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder;
|
|||||||
import com.mojang.datafixers.DataFixer;
|
import com.mojang.datafixers.DataFixer;
|
||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
import java.util.function.IntConsumer;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.StreamTagVisitor;
|
import net.minecraft.nbt.StreamTagVisitor;
|
||||||
import net.minecraft.server.level.ChunkGenerationTask;
|
import net.minecraft.server.level.ChunkGenerationTask;
|
||||||
import net.minecraft.server.level.ChunkHolder;
|
import net.minecraft.server.level.ChunkHolder;
|
||||||
import net.minecraft.server.level.ChunkMap;
|
import net.minecraft.server.level.ChunkMap;
|
||||||
import net.minecraft.server.level.ChunkResult;
|
import net.minecraft.server.level.ChunkResult;
|
||||||
import net.minecraft.server.level.ChunkTaskPriorityQueueSorter;
|
import net.minecraft.server.level.ChunkTaskDispatcher;
|
||||||
import net.minecraft.server.level.ChunkTrackingView;
|
import net.minecraft.server.level.ChunkTrackingView;
|
||||||
import net.minecraft.server.level.GeneratingChunkMap;
|
import net.minecraft.server.level.GeneratingChunkMap;
|
||||||
import net.minecraft.server.level.GenerationChunkHolder;
|
import net.minecraft.server.level.GenerationChunkHolder;
|
||||||
@@ -28,7 +31,6 @@ import net.minecraft.server.level.progress.ChunkProgressListener;
|
|||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
import net.minecraft.util.StaticCache2D;
|
import net.minecraft.util.StaticCache2D;
|
||||||
import net.minecraft.util.thread.BlockableEventLoop;
|
import net.minecraft.util.thread.BlockableEventLoop;
|
||||||
import net.minecraft.util.thread.ProcessorHandle;
|
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||||
@@ -78,13 +80,10 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
|
|||||||
private volatile Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunkMap;
|
private volatile Long2ObjectLinkedOpenHashMap<ChunkHolder> visibleChunkMap;
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
private ChunkTaskPriorityQueueSorter queueSorter;
|
private ChunkTaskDispatcher worldgenTaskDispatcher;
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
private ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> worldgenMailbox;
|
private ChunkTaskDispatcher lightTaskDispatcher;
|
||||||
|
|
||||||
@Shadow
|
|
||||||
private ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> mainThreadMailbox;
|
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
private int serverViewDistance;
|
private int serverViewDistance;
|
||||||
@@ -98,6 +97,12 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
|
|||||||
@Shadow
|
@Shadow
|
||||||
private Queue<Runnable> unloadQueue;
|
private Queue<Runnable> unloadQueue;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
private LongSet chunksToEagerlySave;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
private AtomicInteger activeChunkWrites;
|
||||||
|
|
||||||
public ChunkMapMixin(RegionStorageInfo regionStorageInfo, Path path, DataFixer dataFixer, boolean bl) {
|
public ChunkMapMixin(RegionStorageInfo regionStorageInfo, Path path, DataFixer dataFixer, boolean bl) {
|
||||||
super(regionStorageInfo, path, dataFixer, bl);
|
super(regionStorageInfo, path, dataFixer, bl);
|
||||||
}
|
}
|
||||||
@@ -128,11 +133,12 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
|
|||||||
this.updatingChunkMap = null;
|
this.updatingChunkMap = null;
|
||||||
this.visibleChunkMap = null;
|
this.visibleChunkMap = null;
|
||||||
this.pendingUnloads = null;
|
this.pendingUnloads = null;
|
||||||
this.queueSorter = null;
|
this.worldgenTaskDispatcher = null;
|
||||||
this.worldgenMailbox = null;
|
this.lightTaskDispatcher = null;
|
||||||
this.mainThreadMailbox = null;
|
|
||||||
this.pendingGenerationTasks = null;
|
this.pendingGenerationTasks = null;
|
||||||
this.unloadQueue = null;
|
this.unloadQueue = null;
|
||||||
|
this.chunksToEagerlySave = null;
|
||||||
|
this.activeChunkWrites = null;
|
||||||
|
|
||||||
// Dummy impl for mods that try to loadAsync directly
|
// Dummy impl for mods that try to loadAsync directly
|
||||||
this.worker = new IOWorker(
|
this.worker = new IOWorker(
|
||||||
@@ -152,7 +158,7 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
|
|||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Optional<CompoundTag>> loadAsync(final ChunkPos chunkPos) {
|
public CompletableFuture<Optional<CompoundTag>> loadAsync(final ChunkPos chunkPos) {
|
||||||
final CompletableFuture<Optional<CompoundTag>> future = new CompletableFuture<>();
|
final CompletableFuture<Optional<CompoundTag>> future = new CompletableFuture<>();
|
||||||
MoonriseRegionFileIO.loadDataAsync(ChunkMapMixin.this.level, chunkPos.x, chunkPos.z, MoonriseRegionFileIO.RegionFileType.CHUNK_DATA, (tag, throwable) -> {
|
MoonriseRegionFileIO.loadDataAsync(ChunkMapMixin.this.level, chunkPos.x, chunkPos.z, MoonriseRegionFileIO.RegionFileType.CHUNK_DATA, (final CompoundTag tag, final Throwable throwable) -> {
|
||||||
if (throwable != null) {
|
if (throwable != null) {
|
||||||
future.completeExceptionally(throwable);
|
future.completeExceptionally(throwable);
|
||||||
} else {
|
} else {
|
||||||
@@ -184,6 +190,15 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason This map is not needed, we maintain our own ordered set of chunks to autosave.
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Overwrite
|
||||||
|
public void setChunkUnsaved(final ChunkPos pos) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Route to new chunk system hooks
|
* @reason Route to new chunk system hooks
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
@@ -261,6 +276,15 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
|
|||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Destroy old chunk system hooks
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Overwrite
|
||||||
|
public void onLevelChange(final ChunkPos chunkPos, final IntSupplier intSupplier, final int i, final IntConsumer intConsumer) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Destroy old chunk system hooks
|
* @reason Destroy old chunk system hooks
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
@@ -309,6 +333,15 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
|
|||||||
((ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.autoSave();
|
((ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.autoSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Destroy old chunk system hooks
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Overwrite
|
||||||
|
public void saveChunksEagerly(final BooleanSupplier hasTime) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Destroy old chunk system hooks
|
* @reason Destroy old chunk system hooks
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
@@ -403,7 +436,7 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
|
|||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public void onChunkReadyToSend(final LevelChunk chunk) {
|
public void onChunkReadyToSend(final ChunkHolder holder, final LevelChunk chunk) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -422,7 +455,7 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
|
|||||||
* @see NewChunkHolder#save(boolean)
|
* @see NewChunkHolder#save(boolean)
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public boolean saveChunkIfNeeded(final ChunkHolder chunkHolder) {
|
public boolean saveChunkIfNeeded(final ChunkHolder chunkHolder, final long time) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -505,6 +538,21 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
|
|||||||
throw new UnsupportedOperationException();
|
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
|
@Override
|
||||||
public CompletableFuture<Optional<CompoundTag>> read(final ChunkPos pos) {
|
public CompletableFuture<Optional<CompoundTag>> read(final ChunkPos pos) {
|
||||||
final CompletableFuture<Optional<CompoundTag>> ret = new CompletableFuture<>();
|
final CompletableFuture<Optional<CompoundTag>> ret = new CompletableFuture<>();
|
||||||
@@ -524,10 +572,11 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkSystemChunkMap
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<Void> write(final ChunkPos pos, final CompoundTag tag) {
|
public CompletableFuture<Void> write(final ChunkPos pos, final Supplier<CompoundTag> tag) {
|
||||||
MoonriseRegionFileIO.scheduleSave(
|
MoonriseRegionFileIO.scheduleSave(
|
||||||
this.level, pos.x, pos.z, tag,
|
this.level, pos.x, pos.z, tag.get(),
|
||||||
MoonriseRegionFileIO.RegionFileType.CHUNK_DATA);
|
MoonriseRegionFileIO.RegionFileType.CHUNK_DATA
|
||||||
|
);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,12 +22,13 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
@Mixin(ChunkStorage.class)
|
@Mixin(ChunkStorage.class)
|
||||||
abstract class ChunkStorageMixin implements ChunkSystemChunkStorage, AutoCloseable {
|
abstract class ChunkStorageMixin implements ChunkSystemChunkStorage, AutoCloseable {
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
private IOWorker worker;
|
public IOWorker worker;
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private static final Logger LOGGER = LogUtils.getLogger();
|
private static final Logger LOGGER = LogUtils.getLogger();
|
||||||
@@ -118,13 +119,13 @@ abstract class ChunkStorageMixin implements ChunkSystemChunkStorage, AutoCloseab
|
|||||||
method = "write",
|
method = "write",
|
||||||
at = @At(
|
at = @At(
|
||||||
value = "INVOKE",
|
value = "INVOKE",
|
||||||
target = "Lnet/minecraft/world/level/chunk/storage/IOWorker;store(Lnet/minecraft/world/level/ChunkPos;Lnet/minecraft/nbt/CompoundTag;)Ljava/util/concurrent/CompletableFuture;"
|
target = "Lnet/minecraft/world/level/chunk/storage/IOWorker;store(Lnet/minecraft/world/level/ChunkPos;Ljava/util/function/Supplier;)Ljava/util/concurrent/CompletableFuture;"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
private CompletableFuture<Void> redirectWrite(final IOWorker instance, final ChunkPos chunkPos,
|
private CompletableFuture<Void> redirectWrite(final IOWorker instance, final ChunkPos chunkPos,
|
||||||
final CompoundTag compoundTag) {
|
final Supplier<CompoundTag> compoundTag) {
|
||||||
try {
|
try {
|
||||||
this.storage.write(chunkPos, compoundTag);
|
this.storage.write(chunkPos, compoundTag.get());
|
||||||
return CompletableFuture.completedFuture(null);
|
return CompletableFuture.completedFuture(null);
|
||||||
} catch (final Throwable throwable) {
|
} catch (final Throwable throwable) {
|
||||||
return CompletableFuture.failedFuture(throwable);
|
return CompletableFuture.failedFuture(throwable);
|
||||||
|
|||||||
@@ -41,8 +41,8 @@ abstract class ClientLevelMixin extends Level implements ChunkSystemLevel {
|
|||||||
@Final
|
@Final
|
||||||
private ClientChunkCache chunkSource;
|
private ClientChunkCache chunkSource;
|
||||||
|
|
||||||
protected ClientLevelMixin(WritableLevelData writableLevelData, ResourceKey<Level> resourceKey, RegistryAccess registryAccess, Holder<DimensionType> holder, Supplier<ProfilerFiller> supplier, boolean bl, boolean bl2, long l, int i) {
|
protected ClientLevelMixin(final WritableLevelData writableLevelData, final ResourceKey<Level> resourceKey, final RegistryAccess registryAccess, final Holder<DimensionType> holder, final boolean bl, final boolean bl2, final long l, final int i) {
|
||||||
super(writableLevelData, resourceKey, registryAccess, holder, supplier, bl, bl2, l, i);
|
super(writableLevelData, resourceKey, registryAccess, holder, bl, bl2, l, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -55,14 +55,28 @@ abstract class ClientLevelMixin extends Level implements ChunkSystemLevel {
|
|||||||
value = "RETURN"
|
value = "RETURN"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
private void init(ClientPacketListener clientPacketListener, ClientLevel.ClientLevelData clientLevelData,
|
private void init(ClientPacketListener clientPacketListener, ClientLevel.ClientLevelData clientLevelData, ResourceKey<Level> resourceKey,
|
||||||
ResourceKey<Level> resourceKey, Holder<DimensionType> holder, int i, int j, Supplier<ProfilerFiller> supplier,
|
Holder<DimensionType> holder, int i, int j, LevelRenderer levelRenderer, boolean bl, long l, int k, CallbackInfo ci) {
|
||||||
LevelRenderer levelRenderer, boolean bl, long l, CallbackInfo ci) {
|
|
||||||
this.entityStorage = null;
|
this.entityStorage = null;
|
||||||
|
|
||||||
this.moonrise$setEntityLookup(new ClientEntityLookup(this, ((ClientLevel)(Object)this).new EntityCallbacks()));
|
this.moonrise$setEntityLookup(new ClientEntityLookup(this, ((ClientLevel)(Object)this).new EntityCallbacks()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean moonrise$areChunksLoaded(final int fromX, final int fromZ, final int toX, final int toZ) {
|
||||||
|
final ClientChunkCache chunkSource = this.chunkSource;
|
||||||
|
|
||||||
|
for (int currZ = fromZ; currZ <= toZ; ++currZ) {
|
||||||
|
for (int currX = fromX; currX <= toX; ++currX) {
|
||||||
|
if (!chunkSource.hasChunk(currX, currZ)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Redirect to new entity manager
|
* @reason Redirect to new entity manager
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
|
|||||||
@@ -8,13 +8,12 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
|||||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||||
import net.minecraft.server.level.ChunkHolder;
|
import net.minecraft.server.level.ChunkHolder;
|
||||||
import net.minecraft.server.level.ChunkMap;
|
import net.minecraft.server.level.ChunkMap;
|
||||||
import net.minecraft.server.level.ChunkTaskPriorityQueueSorter;
|
|
||||||
import net.minecraft.server.level.DistanceManager;
|
import net.minecraft.server.level.DistanceManager;
|
||||||
|
import net.minecraft.server.level.ThrottlingChunkTaskDispatcher;
|
||||||
import net.minecraft.server.level.Ticket;
|
import net.minecraft.server.level.Ticket;
|
||||||
import net.minecraft.server.level.TicketType;
|
import net.minecraft.server.level.TicketType;
|
||||||
import net.minecraft.server.level.TickingTracker;
|
import net.minecraft.server.level.TickingTracker;
|
||||||
import net.minecraft.util.SortedArraySet;
|
import net.minecraft.util.SortedArraySet;
|
||||||
import net.minecraft.util.thread.ProcessorHandle;
|
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
@@ -45,13 +44,7 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
|
|||||||
Set<ChunkHolder> chunksToUpdateFutures;
|
Set<ChunkHolder> chunksToUpdateFutures;
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
ChunkTaskPriorityQueueSorter ticketThrottler;
|
ThrottlingChunkTaskDispatcher ticketDispatcher;
|
||||||
|
|
||||||
@Shadow
|
|
||||||
ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> ticketThrottlerInput;
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
ProcessorHandle<ChunkTaskPriorityQueueSorter.Release> ticketThrottlerReleaser;
|
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
LongSet ticketsToRelease;
|
LongSet ticketsToRelease;
|
||||||
@@ -59,12 +52,10 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
|
|||||||
@Shadow
|
@Shadow
|
||||||
Executor mainThreadExecutor;
|
Executor mainThreadExecutor;
|
||||||
|
|
||||||
@Shadow
|
|
||||||
private DistanceManager.FixedPlayerDistanceChunkTracker naturalSpawnChunkCounter;
|
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
private int simulationDistance;
|
private int simulationDistance;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ChunkMap moonrise$getChunkMap() {
|
public ChunkMap moonrise$getChunkMap() {
|
||||||
throw new AbstractMethodError();
|
throw new AbstractMethodError();
|
||||||
@@ -86,16 +77,14 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
|
|||||||
this.tickingTicketsTracker = null;
|
this.tickingTicketsTracker = null;
|
||||||
this.playerTicketManager = null;
|
this.playerTicketManager = null;
|
||||||
this.chunksToUpdateFutures = null;
|
this.chunksToUpdateFutures = null;
|
||||||
this.ticketThrottler = null;
|
this.ticketDispatcher = null;
|
||||||
this.ticketThrottlerInput = null;
|
|
||||||
this.ticketThrottlerReleaser = null;
|
|
||||||
this.ticketsToRelease = null;
|
this.ticketsToRelease = null;
|
||||||
this.mainThreadExecutor = null;
|
this.mainThreadExecutor = null;
|
||||||
this.simulationDistance = -1;
|
this.simulationDistance = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ChunkHolderManager moonrise$getChunkHolderManager() {
|
public final ChunkHolderManager moonrise$getChunkHolderManager() {
|
||||||
return ((ChunkSystemServerLevel)this.moonrise$getChunkMap().level).moonrise$getChunkTaskScheduler().chunkHolderManager;
|
return ((ChunkSystemServerLevel)this.moonrise$getChunkMap().level).moonrise$getChunkTaskScheduler().chunkHolderManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -326,6 +315,15 @@ abstract class DistanceManagerMixin implements ChunkSystemDistanceManager {
|
|||||||
throw new UnsupportedOperationException();
|
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}
|
* @reason This hack is not required anymore, see {@link MinecraftServerMixin}
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package ca.spottedleaf.moonrise.mixin.chunk_system;
|
package ca.spottedleaf.moonrise.mixin.chunk_system;
|
||||||
|
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkData;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity;
|
import ca.spottedleaf.moonrise.patches.chunk_system.entity.ChunkSystemEntity;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
@@ -49,6 +50,9 @@ abstract class EntityMixin implements ChunkSystemEntity {
|
|||||||
@Unique
|
@Unique
|
||||||
private FullChunkStatus chunkStatus;
|
private FullChunkStatus chunkStatus;
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private ChunkData chunkData;
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private int sectionX = Integer.MIN_VALUE;
|
private int sectionX = Integer.MIN_VALUE;
|
||||||
|
|
||||||
@@ -76,6 +80,16 @@ abstract class EntityMixin implements ChunkSystemEntity {
|
|||||||
this.chunkStatus = status;
|
this.chunkStatus = status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final ChunkData moonrise$getChunkData() {
|
||||||
|
return this.chunkData;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void moonrise$setChunkData(final ChunkData chunkData) {
|
||||||
|
this.chunkData = chunkData;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final int moonrise$getSectionX() {
|
public final int moonrise$getSectionX() {
|
||||||
return this.sectionX;
|
return this.sectionX;
|
||||||
|
|||||||
@@ -99,8 +99,18 @@ abstract class EntityTickListMixin {
|
|||||||
* @reason Route to new entity list
|
* @reason Route to new entity list
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Inject(
|
||||||
public void forEach(final Consumer<Entity> action) {
|
method = "forEach",
|
||||||
|
at = @At("HEAD"),
|
||||||
|
cancellable = true
|
||||||
|
)
|
||||||
|
private void injectForEach(final Consumer<Entity> consumer, final CallbackInfo ci) {
|
||||||
|
this.forEach(consumer);
|
||||||
|
ci.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private void forEach(final Consumer<Entity> action) {
|
||||||
// To ensure nothing weird happens with dimension travelling, do not iterate over new entries...
|
// To ensure nothing weird happens with dimension travelling, do not iterate over new entries...
|
||||||
// (by dfl iterator() is configured to not iterate over new entries)
|
// (by dfl iterator() is configured to not iterate over new entries)
|
||||||
final IteratorSafeOrderedReferenceSet.Iterator<Entity> iterator = this.entities.iterator();
|
final IteratorSafeOrderedReferenceSet.Iterator<Entity> iterator = this.entities.iterator();
|
||||||
|
|||||||
@@ -195,15 +195,6 @@ abstract class GenerationChunkHolderMixin {
|
|||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @reason Chunk system is not built on futures anymore
|
|
||||||
* @author Spottedleaf
|
|
||||||
*/
|
|
||||||
@Overwrite
|
|
||||||
public int getGenerationRefCount() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Route to new chunk holder
|
* @reason Route to new chunk holder
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
|
|||||||
@@ -93,11 +93,15 @@ abstract class LevelChunkMixin extends ChunkAccess implements ChunkSystemLevelCh
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setUnsaved(final boolean needsSaving) {
|
public boolean tryMarkSaved() {
|
||||||
if (!needsSaving) {
|
if (!this.isUnsaved()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
((ChunkSystemLevelChunkTicks)this.blockTicks).moonrise$clearDirty();
|
((ChunkSystemLevelChunkTicks)this.blockTicks).moonrise$clearDirty();
|
||||||
((ChunkSystemLevelChunkTicks)this.fluidTicks).moonrise$clearDirty();
|
((ChunkSystemLevelChunkTicks)this.fluidTicks).moonrise$clearDirty();
|
||||||
}
|
|
||||||
super.setUnsaved(needsSaving);
|
super.tryMarkSaved();
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,18 +1,23 @@
|
|||||||
package ca.spottedleaf.moonrise.mixin.chunk_system;
|
package ca.spottedleaf.moonrise.mixin.chunk_system;
|
||||||
|
|
||||||
|
import ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable;
|
||||||
import ca.spottedleaf.moonrise.common.PlatformHooks;
|
import ca.spottedleaf.moonrise.common.PlatformHooks;
|
||||||
|
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkData;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevel;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.EntityLookup;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.EntityLookup;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.dfl.DefaultEntityLookup;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.dfl.DefaultEntityLookup;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemEntityGetter;
|
import ca.spottedleaf.moonrise.patches.chunk_system.world.ChunkSystemEntityGetter;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.server.level.FullChunkStatus;
|
import net.minecraft.server.level.FullChunkStatus;
|
||||||
|
import net.minecraft.util.profiling.Profiler;
|
||||||
import net.minecraft.util.profiling.ProfilerFiller;
|
import net.minecraft.util.profiling.ProfilerFiller;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.EntityType;
|
import net.minecraft.world.entity.EntityType;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.LevelAccessor;
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
|
import net.minecraft.world.level.chunk.ChunkSource;
|
||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
import net.minecraft.world.level.entity.EntityTypeTest;
|
import net.minecraft.world.level.entity.EntityTypeTest;
|
||||||
@@ -33,9 +38,6 @@ import java.util.function.Predicate;
|
|||||||
@Mixin(Level.class)
|
@Mixin(Level.class)
|
||||||
abstract class LevelMixin implements ChunkSystemLevel, ChunkSystemEntityGetter, LevelAccessor, AutoCloseable {
|
abstract class LevelMixin implements ChunkSystemLevel, ChunkSystemEntityGetter, LevelAccessor, AutoCloseable {
|
||||||
|
|
||||||
@Shadow
|
|
||||||
public abstract ProfilerFiller getProfiler();
|
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
public abstract LevelChunk getChunk(int i, int j);
|
public abstract LevelChunk getChunk(int i, int j);
|
||||||
|
|
||||||
@@ -46,13 +48,16 @@ abstract class LevelMixin implements ChunkSystemLevel, ChunkSystemEntityGetter,
|
|||||||
@Unique
|
@Unique
|
||||||
private EntityLookup entityLookup;
|
private EntityLookup entityLookup;
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private final ConcurrentLong2ReferenceChainedHashTable<ChunkData> chunkData = new ConcurrentLong2ReferenceChainedHashTable<>();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final EntityLookup moonrise$getEntityLookup() {
|
public final EntityLookup moonrise$getEntityLookup() {
|
||||||
return this.entityLookup;
|
return this.entityLookup;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void moonrise$setEntityLookup(final EntityLookup entityLookup) {
|
public final void moonrise$setEntityLookup(final EntityLookup entityLookup) {
|
||||||
if (this.entityLookup != null && !(this.entityLookup instanceof DefaultEntityLookup)) {
|
if (this.entityLookup != null && !(this.entityLookup instanceof DefaultEntityLookup)) {
|
||||||
throw new IllegalStateException("Entity lookup already initialised");
|
throw new IllegalStateException("Entity lookup already initialised");
|
||||||
}
|
}
|
||||||
@@ -80,7 +85,7 @@ abstract class LevelMixin implements ChunkSystemLevel, ChunkSystemEntityGetter,
|
|||||||
@Overwrite
|
@Overwrite
|
||||||
@Override
|
@Override
|
||||||
public List<Entity> getEntities(final Entity entity, final AABB boundingBox, final Predicate<? super Entity> predicate) {
|
public List<Entity> getEntities(final Entity entity, final AABB boundingBox, final Predicate<? super Entity> predicate) {
|
||||||
this.getProfiler().incrementCounter("getEntities");
|
Profiler.get().incrementCounter("getEntities");
|
||||||
final List<Entity> ret = new ArrayList<>();
|
final List<Entity> ret = new ArrayList<>();
|
||||||
|
|
||||||
((ChunkSystemLevel)this).moonrise$getEntityLookup().getEntities(entity, boundingBox, ret, predicate);
|
((ChunkSystemLevel)this).moonrise$getEntityLookup().getEntities(entity, boundingBox, ret, predicate);
|
||||||
@@ -98,7 +103,7 @@ abstract class LevelMixin implements ChunkSystemLevel, ChunkSystemEntityGetter,
|
|||||||
public <T extends Entity> void getEntities(final EntityTypeTest<Entity, T> entityTypeTest,
|
public <T extends Entity> void getEntities(final EntityTypeTest<Entity, T> entityTypeTest,
|
||||||
final AABB boundingBox, final Predicate<? super T> predicate,
|
final AABB boundingBox, final Predicate<? super T> predicate,
|
||||||
final List<? super T> into, final int maxCount) {
|
final List<? super T> into, final int maxCount) {
|
||||||
this.getProfiler().incrementCounter("getEntities");
|
Profiler.get().incrementCounter("getEntities");
|
||||||
|
|
||||||
if (entityTypeTest instanceof EntityType<T> byType) {
|
if (entityTypeTest instanceof EntityType<T> byType) {
|
||||||
if (maxCount != Integer.MAX_VALUE) {
|
if (maxCount != Integer.MAX_VALUE) {
|
||||||
@@ -171,7 +176,7 @@ abstract class LevelMixin implements ChunkSystemLevel, ChunkSystemEntityGetter,
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public final <T extends Entity> List<T> getEntitiesOfClass(final Class<T> entityClass, final AABB boundingBox, final Predicate<? super T> predicate) {
|
public final <T extends Entity> List<T> getEntitiesOfClass(final Class<T> entityClass, final AABB boundingBox, final Predicate<? super T> predicate) {
|
||||||
this.getProfiler().incrementCounter("getEntities");
|
Profiler.get().incrementCounter("getEntities");
|
||||||
final List<T> ret = new ArrayList<>();
|
final List<T> ret = new ArrayList<>();
|
||||||
|
|
||||||
((ChunkSystemLevel)this).moonrise$getEntityLookup().getEntities(entityClass, null, boundingBox, ret, predicate);
|
((ChunkSystemLevel)this).moonrise$getEntityLookup().getEntities(entityClass, null, boundingBox, ret, predicate);
|
||||||
@@ -189,7 +194,7 @@ abstract class LevelMixin implements ChunkSystemLevel, ChunkSystemEntityGetter,
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public final List<Entity> moonrise$getHardCollidingEntities(final Entity entity, final AABB box, final Predicate<? super Entity> predicate) {
|
public final List<Entity> moonrise$getHardCollidingEntities(final Entity entity, final AABB box, final Predicate<? super Entity> predicate) {
|
||||||
this.getProfiler().incrementCounter("getEntities");
|
Profiler.get().incrementCounter("getEntities");
|
||||||
final List<Entity> ret = new ArrayList<>();
|
final List<Entity> ret = new ArrayList<>();
|
||||||
|
|
||||||
((ChunkSystemLevel)this).moonrise$getEntityLookup().getHardCollidingEntities(entity, box, ret, predicate);
|
((ChunkSystemLevel)this).moonrise$getEntityLookup().getHardCollidingEntities(entity, box, ret, predicate);
|
||||||
@@ -217,6 +222,52 @@ abstract class LevelMixin implements ChunkSystemLevel, ChunkSystemEntityGetter,
|
|||||||
// no-op on ClientLevel
|
// no-op on ClientLevel
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final ChunkData moonrise$getChunkData(final long chunkKey) {
|
||||||
|
return this.chunkData.get(chunkKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final ChunkData moonrise$getChunkData(final int chunkX, final int chunkZ) {
|
||||||
|
return this.chunkData.get(CoordinateUtils.getChunkKey(chunkX, chunkZ));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final ChunkData moonrise$requestChunkData(final long chunkKey) {
|
||||||
|
return this.chunkData.compute(chunkKey, (final long keyInMap, final ChunkData valueInMap) -> {
|
||||||
|
if (valueInMap == null) {
|
||||||
|
final ChunkData ret = new ChunkData();
|
||||||
|
ret.increaseRef();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
valueInMap.increaseRef();
|
||||||
|
return valueInMap;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final ChunkData moonrise$releaseChunkData(final long chunkKey) {
|
||||||
|
return this.chunkData.compute(chunkKey, (final long keyInMap, final ChunkData chunkData) -> {
|
||||||
|
return chunkData.decreaseRef() == 0 ? null : chunkData;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean moonrise$areChunksLoaded(final int fromX, final int fromZ, final int toX, final int toZ) {
|
||||||
|
final ChunkSource chunkSource = this.getChunkSource();
|
||||||
|
|
||||||
|
for (int currZ = fromZ; currZ <= toZ; ++currZ) {
|
||||||
|
for (int currX = fromX; currX <= toX; ++currX) {
|
||||||
|
if (!chunkSource.hasChunk(currX, currZ)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Declare method in this class so that any invocations are virtual, and not interface.
|
* @reason Declare method in this class so that any invocations are virtual, and not interface.
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
@@ -226,6 +277,13 @@ abstract class LevelMixin implements ChunkSystemLevel, ChunkSystemEntityGetter,
|
|||||||
return this.getChunkSource().hasChunk(x, z);
|
return this.getChunkSource().hasChunk(x, z);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasChunksAt(final int minBlockX, final int minBlockZ, final int maxBlockX, final int maxBlockZ) {
|
||||||
|
return this.moonrise$areChunksLoaded(
|
||||||
|
minBlockX >> 4, minBlockZ >> 4, maxBlockX >> 4, maxBlockZ >> 4
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Turn all getChunk(x, z, status) calls into virtual invokes, instead of interface invokes:
|
* @reason Turn all getChunk(x, z, status) calls into virtual invokes, instead of interface invokes:
|
||||||
* 1. The interface invoke is expensive
|
* 1. The interface invoke is expensive
|
||||||
|
|||||||
@@ -240,6 +240,7 @@ abstract class MinecraftServerMixin extends ReentrantBlockableEventLoop<TickTask
|
|||||||
private void closeIOThreads(final CallbackInfo ci) {
|
private void closeIOThreads(final CallbackInfo ci) {
|
||||||
LOGGER.info("Waiting for I/O tasks to complete...");
|
LOGGER.info("Waiting for I/O tasks to complete...");
|
||||||
MoonriseRegionFileIO.flush((MinecraftServer)(Object)this);
|
MoonriseRegionFileIO.flush((MinecraftServer)(Object)this);
|
||||||
|
LOGGER.info("All I/O tasks to complete");
|
||||||
if ((Object)this instanceof DedicatedServer) {
|
if ((Object)this instanceof DedicatedServer) {
|
||||||
MoonriseCommon.haltExecutors();
|
MoonriseCommon.haltExecutors();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.BooleanSupplier;
|
import java.util.function.BooleanSupplier;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
@@ -44,7 +45,14 @@ import java.util.stream.Stream;
|
|||||||
@Mixin(PoiManager.class)
|
@Mixin(PoiManager.class)
|
||||||
// Declare the generic type as Object so that our Overrides match the method signature of the superclass
|
// Declare the generic type as Object so that our Overrides match the method signature of the superclass
|
||||||
// Specifically, getOrCreate must return Object so that existing invokes do not route to the superclass
|
// Specifically, getOrCreate must return Object so that existing invokes do not route to the superclass
|
||||||
public abstract class PoiManagerMixin extends SectionStorage<Object> implements ChunkSystemPoiManager {
|
public abstract class PoiManagerMixin extends SectionStorage<Object, Object> implements ChunkSystemPoiManager {
|
||||||
|
|
||||||
|
public PoiManagerMixin(final SimpleRegionStorage simpleRegionStorage, final Codec<Object> codec, final Function<Object, Object> function,
|
||||||
|
final BiFunction<Object, Runnable, Object> biFunction, final Function<Runnable, Object> function2,
|
||||||
|
final RegistryAccess registryAccess, final ChunkIOErrorReporter chunkIOErrorReporter,
|
||||||
|
final LevelHeightAccessor levelHeightAccessor) {
|
||||||
|
super(simpleRegionStorage, codec, function, biFunction, function2, registryAccess, chunkIOErrorReporter, levelHeightAccessor);
|
||||||
|
}
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
abstract boolean isVillageCenter(long l);
|
abstract boolean isVillageCenter(long l);
|
||||||
@@ -52,10 +60,6 @@ public abstract class PoiManagerMixin extends SectionStorage<Object> implements
|
|||||||
@Shadow
|
@Shadow
|
||||||
public abstract void checkConsistencyWithBlocks(SectionPos sectionPos, LevelChunkSection levelChunkSection);
|
public abstract void checkConsistencyWithBlocks(SectionPos sectionPos, LevelChunkSection levelChunkSection);
|
||||||
|
|
||||||
public PoiManagerMixin(SimpleRegionStorage simpleRegionStorage, Function<Runnable, Codec<Object>> function, Function<Runnable, Object> function2, RegistryAccess registryAccess, ChunkIOErrorReporter chunkIOErrorReporter, LevelHeightAccessor levelHeightAccessor) {
|
|
||||||
super(simpleRegionStorage, function, function2, registryAccess, chunkIOErrorReporter, levelHeightAccessor);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private ServerLevel world;
|
private ServerLevel world;
|
||||||
|
|
||||||
@@ -151,8 +155,8 @@ public abstract class PoiManagerMixin extends SectionStorage<Object> implements
|
|||||||
|
|
||||||
TickThread.ensureTickThread(this.world, chunkX, chunkZ, "Accessing poi chunk off-main");
|
TickThread.ensureTickThread(this.world, chunkX, chunkZ, "Accessing poi chunk off-main");
|
||||||
|
|
||||||
final ChunkHolderManager manager = ((ChunkSystemServerLevel)this.world).moonrise$getChunkTaskScheduler().chunkHolderManager;
|
final PoiChunk ret = ((ChunkSystemServerLevel)this.world).moonrise$getChunkTaskScheduler().chunkHolderManager
|
||||||
final PoiChunk ret = manager.getPoiChunkIfLoaded(chunkX, chunkZ, true);
|
.getPoiChunkIfLoaded(chunkX, chunkZ, true);
|
||||||
|
|
||||||
return ret == null ? Optional.empty() : (Optional)ret.getSectionForVanilla(chunkY);
|
return ret == null ? Optional.empty() : (Optional)ret.getSectionForVanilla(chunkY);
|
||||||
}
|
}
|
||||||
@@ -206,9 +210,13 @@ public abstract class PoiManagerMixin extends SectionStorage<Object> implements
|
|||||||
public final void moonrise$onUnload(final long coordinate) { // Paper - rewrite chunk system
|
public final void moonrise$onUnload(final long coordinate) { // Paper - rewrite chunk system
|
||||||
final int chunkX = CoordinateUtils.getChunkX(coordinate);
|
final int chunkX = CoordinateUtils.getChunkX(coordinate);
|
||||||
final int chunkZ = CoordinateUtils.getChunkZ(coordinate);
|
final int chunkZ = CoordinateUtils.getChunkZ(coordinate);
|
||||||
|
|
||||||
|
final int minY = WorldUtil.getMinSection(this.world);
|
||||||
|
final int maxY = WorldUtil.getMaxSection(this.world);
|
||||||
|
|
||||||
TickThread.ensureTickThread(this.world, chunkX, chunkZ, "Unloading poi chunk off-main");
|
TickThread.ensureTickThread(this.world, chunkX, chunkZ, "Unloading poi chunk off-main");
|
||||||
for (int section = this.levelHeightAccessor.getMinSection(); section < this.levelHeightAccessor.getMaxSection(); ++section) {
|
for (int sectionY = minY; sectionY <= maxY; ++sectionY) {
|
||||||
final long sectionPos = SectionPos.asLong(chunkX, section, chunkZ);
|
final long sectionPos = SectionPos.asLong(chunkX, sectionY, chunkZ);
|
||||||
this.updateDistanceTracking(sectionPos);
|
this.updateDistanceTracking(sectionPos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -217,8 +225,12 @@ public abstract class PoiManagerMixin extends SectionStorage<Object> implements
|
|||||||
public final void moonrise$loadInPoiChunk(final PoiChunk poiChunk) {
|
public final void moonrise$loadInPoiChunk(final PoiChunk poiChunk) {
|
||||||
final int chunkX = poiChunk.chunkX;
|
final int chunkX = poiChunk.chunkX;
|
||||||
final int chunkZ = poiChunk.chunkZ;
|
final int chunkZ = poiChunk.chunkZ;
|
||||||
|
|
||||||
|
final int minY = WorldUtil.getMinSection(this.world);
|
||||||
|
final int maxY = WorldUtil.getMaxSection(this.world);
|
||||||
|
|
||||||
TickThread.ensureTickThread(this.world, chunkX, chunkZ, "Loading poi chunk off-main");
|
TickThread.ensureTickThread(this.world, chunkX, chunkZ, "Loading poi chunk off-main");
|
||||||
for (int sectionY = this.levelHeightAccessor.getMinSection(); sectionY < this.levelHeightAccessor.getMaxSection(); ++sectionY) {
|
for (int sectionY = minY; sectionY <= maxY; ++sectionY) {
|
||||||
final PoiSection section = poiChunk.getSection(sectionY);
|
final PoiSection section = poiChunk.getSection(sectionY);
|
||||||
if (section != null && !((ChunkSystemPoiSection)section).moonrise$isEmpty()) {
|
if (section != null && !((ChunkSystemPoiSection)section).moonrise$isEmpty()) {
|
||||||
this.onSectionLoad(SectionPos.asLong(chunkX, sectionY, chunkZ));
|
this.onSectionLoad(SectionPos.asLong(chunkX, sectionY, chunkZ));
|
||||||
@@ -254,20 +266,4 @@ public abstract class PoiManagerMixin extends SectionStorage<Object> implements
|
|||||||
private <T> Stream<T> skipLoadedSet(final Stream<T> instance, final Predicate<? super T> predicate) {
|
private <T> Stream<T> skipLoadedSet(final Stream<T> instance, final Predicate<? super T> predicate) {
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void moonrise$close() throws IOException {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final CompoundTag moonrise$read(final int chunkX, final int chunkZ) throws IOException {
|
|
||||||
return MoonriseRegionFileIO.loadData(
|
|
||||||
this.world, chunkX, chunkZ, MoonriseRegionFileIO.RegionFileType.POI_DATA,
|
|
||||||
MoonriseRegionFileIO.getIOBlockingPriorityForCurrentThread()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final void moonrise$write(final int chunkX, final int chunkZ, final CompoundTag data) throws IOException {
|
|
||||||
MoonriseRegionFileIO.scheduleSave(this.world, chunkX, chunkZ, data, MoonriseRegionFileIO.RegionFileType.POI_DATA);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ abstract class PoiSectionMixin implements ChunkSystemPoiSection {
|
|||||||
|
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private final Optional<PoiSection> noAllocOptional = Optional.of((PoiSection)(Object)this);;
|
private final Optional<PoiSection> noAllocOptional = Optional.of((PoiSection)(Object)this);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean moonrise$isEmpty() {
|
public final boolean moonrise$isEmpty() {
|
||||||
|
|||||||
@@ -2,8 +2,6 @@ package ca.spottedleaf.moonrise.mixin.chunk_system;
|
|||||||
|
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.storage.ChunkSystemSectionStorage;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.storage.ChunkSystemSectionStorage;
|
||||||
import net.minecraft.nbt.CompoundTag;
|
import net.minecraft.nbt.CompoundTag;
|
||||||
import net.minecraft.nbt.Tag;
|
|
||||||
import net.minecraft.resources.RegistryOps;
|
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
import net.minecraft.world.level.chunk.storage.RegionFileStorage;
|
import net.minecraft.world.level.chunk.storage.RegionFileStorage;
|
||||||
import net.minecraft.world.level.chunk.storage.SectionStorage;
|
import net.minecraft.world.level.chunk.storage.SectionStorage;
|
||||||
@@ -23,15 +21,11 @@ import java.util.Optional;
|
|||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
|
|
||||||
@Mixin(SectionStorage.class)
|
@Mixin(SectionStorage.class)
|
||||||
abstract class SectionStorageMixin implements ChunkSystemSectionStorage, AutoCloseable {
|
abstract class SectionStorageMixin<R, P> implements ChunkSystemSectionStorage, AutoCloseable {
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
private SimpleRegionStorage simpleRegionStorage;
|
private SimpleRegionStorage simpleRegionStorage;
|
||||||
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
private static Logger LOGGER;
|
|
||||||
|
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private RegionFileStorage storage;
|
private RegionFileStorage storage;
|
||||||
@@ -41,6 +35,9 @@ abstract class SectionStorageMixin implements ChunkSystemSectionStorage, AutoClo
|
|||||||
return this.storage;
|
return this.storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void moonrise$close() throws IOException {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Retrieve storage from IOWorker, and then nuke it
|
* @reason Retrieve storage from IOWorker, and then nuke it
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
@@ -61,12 +58,8 @@ abstract class SectionStorageMixin implements ChunkSystemSectionStorage, AutoClo
|
|||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public final CompletableFuture<Optional<CompoundTag>> tryRead(final ChunkPos pos) {
|
public final CompletableFuture<Optional<SectionStorage.PackedChunk<P>>> tryRead(final ChunkPos pos) {
|
||||||
try {
|
throw new IllegalStateException("Only chunk system can write state, offending class:" + this.getClass().getName());
|
||||||
return CompletableFuture.completedFuture(Optional.ofNullable(this.moonrise$read(pos.x, pos.z)));
|
|
||||||
} catch (final Throwable thr) {
|
|
||||||
return CompletableFuture.failedFuture(thr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -74,29 +67,17 @@ abstract class SectionStorageMixin implements ChunkSystemSectionStorage, AutoClo
|
|||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public void readColumn(final ChunkPos pos, final RegistryOps<Tag> ops, final CompoundTag data) {
|
public void unpackChunk(final ChunkPos chunkPos, final SectionStorage.PackedChunk<P> packedChunk) {
|
||||||
throw new IllegalStateException("Only chunk system can load in state, offending class:" + this.getClass().getName());
|
throw new IllegalStateException("Only chunk system can load in state, offending class:" + this.getClass().getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Route to new chunk system hook
|
* @reason Destroy old chunk system hook
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Redirect(
|
@Overwrite
|
||||||
method = "writeColumn(Lnet/minecraft/world/level/ChunkPos;)V",
|
private void writeChunk(final ChunkPos chunkPos) {
|
||||||
at = @At(
|
throw new IllegalStateException("Only chunk system can write state, offending class:" + this.getClass().getName());
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,13 +3,13 @@ package ca.spottedleaf.moonrise.mixin.chunk_system;
|
|||||||
import net.minecraft.core.SectionPos;
|
import net.minecraft.core.SectionPos;
|
||||||
import net.minecraft.world.entity.ai.village.poi.PoiManager;
|
import net.minecraft.world.entity.ai.village.poi.PoiManager;
|
||||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||||
import net.minecraft.world.level.chunk.storage.ChunkSerializer;
|
import net.minecraft.world.level.chunk.storage.SerializableChunkData;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
@Mixin(ChunkSerializer.class)
|
@Mixin(SerializableChunkData.class)
|
||||||
abstract class ChunkSerializerMixin {
|
abstract class SerializableChunkDataMixin {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Chunk system handles this during full transition
|
* @reason Chunk system handles this during full transition
|
||||||
@@ -23,6 +23,6 @@ abstract class ChunkSerializerMixin {
|
|||||||
target = "Lnet/minecraft/world/entity/ai/village/poi/PoiManager;checkConsistencyWithBlocks(Lnet/minecraft/core/SectionPos;Lnet/minecraft/world/level/chunk/LevelChunkSection;)V"
|
target = "Lnet/minecraft/world/entity/ai/village/poi/PoiManager;checkConsistencyWithBlocks(Lnet/minecraft/core/SectionPos;Lnet/minecraft/world/level/chunk/LevelChunkSection;)V"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
private static void skipConsistencyCheck(PoiManager instance, SectionPos sectionPos, LevelChunkSection levelChunkSection) {}
|
private void skipConsistencyCheck(final PoiManager instance, final SectionPos sectionPos, final LevelChunkSection levelChunkSection) {}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,7 @@ package ca.spottedleaf.moonrise.mixin.chunk_system;
|
|||||||
import ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable;
|
import ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable;
|
||||||
import ca.spottedleaf.concurrentutil.util.Priority;
|
import ca.spottedleaf.concurrentutil.util.Priority;
|
||||||
import ca.spottedleaf.moonrise.common.PlatformHooks;
|
import ca.spottedleaf.moonrise.common.PlatformHooks;
|
||||||
|
import ca.spottedleaf.moonrise.common.list.ReferenceList;
|
||||||
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
||||||
import ca.spottedleaf.moonrise.common.util.TickThread;
|
import ca.spottedleaf.moonrise.common.util.TickThread;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
||||||
@@ -23,6 +24,7 @@ import net.minecraft.world.level.chunk.ChunkSource;
|
|||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
import net.minecraft.world.level.chunk.LightChunk;
|
import net.minecraft.world.level.chunk.LightChunk;
|
||||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
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.Final;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
@@ -33,6 +35,8 @@ import org.spongepowered.asm.mixin.injection.Inject;
|
|||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.concurrent.CompletableFuture;
|
import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
@@ -48,6 +52,10 @@ abstract class ServerChunkCacheMixin extends ChunkSource implements ChunkSystemS
|
|||||||
@Final
|
@Final
|
||||||
public ServerLevel level;
|
public ServerLevel level;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
private DimensionDataStorage dataStorage;
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private final ConcurrentLong2ReferenceChainedHashTable<LevelChunk> fullChunks = new ConcurrentLong2ReferenceChainedHashTable<>();
|
private final ConcurrentLong2ReferenceChainedHashTable<LevelChunk> fullChunks = new ConcurrentLong2ReferenceChainedHashTable<>();
|
||||||
|
|
||||||
@@ -258,6 +266,7 @@ abstract class ServerChunkCacheMixin extends ChunkSource implements ChunkSystemS
|
|||||||
@Override
|
@Override
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
|
this.dataStorage.close();
|
||||||
((ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.close(true, true);
|
((ChunkSystemServerLevel)this.level).moonrise$getChunkTaskScheduler().chunkHolderManager.close(true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -282,7 +291,8 @@ abstract class ServerChunkCacheMixin extends ChunkSource implements ChunkSystemS
|
|||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public void getFullChunk(final long pos, final Consumer<LevelChunk> consumer) {
|
public void getFullChunk(final long pos, final Consumer<LevelChunk> consumer) {
|
||||||
final LevelChunk fullChunk = this.getChunkNow(CoordinateUtils.getChunkX(pos), CoordinateUtils.getChunkZ(pos));
|
// note: bypass currentlyLoaded from getChunkNow
|
||||||
|
final LevelChunk fullChunk = this.fullChunks.get(pos);
|
||||||
if (fullChunk != null) {
|
if (fullChunk != null) {
|
||||||
consumer.accept(fullChunk);
|
consumer.accept(fullChunk);
|
||||||
}
|
}
|
||||||
@@ -310,7 +320,7 @@ abstract class ServerChunkCacheMixin extends ChunkSource implements ChunkSystemS
|
|||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Inject(
|
@Inject(
|
||||||
method = "tickChunks",
|
method = "tickChunks(Lnet/minecraft/util/profiling/ProfilerFiller;JLjava/util/List;)V",
|
||||||
at = @At(
|
at = @At(
|
||||||
value = "INVOKE",
|
value = "INVOKE",
|
||||||
shift = At.Shift.AFTER,
|
shift = At.Shift.AFTER,
|
||||||
@@ -331,23 +341,7 @@ abstract class ServerChunkCacheMixin extends ChunkSource implements ChunkSystemS
|
|||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Redirect(
|
@Redirect(
|
||||||
method = "tickChunks",
|
method = "tickChunks(Lnet/minecraft/util/profiling/ProfilerFiller;JLjava/util/List;)V",
|
||||||
at = @At(
|
|
||||||
value = "INVOKE",
|
|
||||||
target = "Lnet/minecraft/server/level/ServerLevel;isNaturalSpawningAllowed(Lnet/minecraft/world/level/ChunkPos;)Z"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
private boolean shortNaturalSpawning(final ServerLevel instance, final ChunkPos chunkPos) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @reason In the chunk system, ticking chunks always have loaded entities. Of course, they are also always
|
|
||||||
* marked to be as ticking as well.
|
|
||||||
* @author Spottedleaf
|
|
||||||
*/
|
|
||||||
@Redirect(
|
|
||||||
method = "tickChunks",
|
|
||||||
at = @At(
|
at = @At(
|
||||||
value = "INVOKE",
|
value = "INVOKE",
|
||||||
target = "Lnet/minecraft/server/level/ServerLevel;shouldTickBlocksAt(J)Z"
|
target = "Lnet/minecraft/server/level/ServerLevel;shouldTickBlocksAt(J)Z"
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.EntityData
|
|||||||
import ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.PoiDataController;
|
import ca.spottedleaf.moonrise.patches.chunk_system.io.datacontroller.PoiDataController;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevelReader;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemLevelReader;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunkHolder;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server.ServerEntityLookup;
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.entity.server.ServerEntityLookup;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader;
|
import ca.spottedleaf.moonrise.patches.chunk_system.player.RegionizedPlayerChunkLoader;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager;
|
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.ChunkHolderManager;
|
||||||
@@ -26,6 +27,7 @@ import net.minecraft.core.Holder;
|
|||||||
import net.minecraft.core.RegistryAccess;
|
import net.minecraft.core.RegistryAccess;
|
||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.server.MinecraftServer;
|
import net.minecraft.server.MinecraftServer;
|
||||||
|
import net.minecraft.server.level.ChunkHolder;
|
||||||
import net.minecraft.server.level.ChunkMap;
|
import net.minecraft.server.level.ChunkMap;
|
||||||
import net.minecraft.server.level.DistanceManager;
|
import net.minecraft.server.level.DistanceManager;
|
||||||
import net.minecraft.server.level.ServerChunkCache;
|
import net.minecraft.server.level.ServerChunkCache;
|
||||||
@@ -62,6 +64,7 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
@@ -83,8 +86,8 @@ abstract class ServerLevelMixin extends Level implements ChunkSystemServerLevel,
|
|||||||
@Final
|
@Final
|
||||||
private ServerChunkCache chunkSource;
|
private ServerChunkCache chunkSource;
|
||||||
|
|
||||||
protected ServerLevelMixin(WritableLevelData writableLevelData, ResourceKey<Level> resourceKey, RegistryAccess registryAccess, Holder<DimensionType> holder, Supplier<ProfilerFiller> supplier, boolean bl, boolean bl2, long l, int i) {
|
protected ServerLevelMixin(final WritableLevelData writableLevelData, final ResourceKey<Level> resourceKey, final RegistryAccess registryAccess, final Holder<DimensionType> holder, final boolean bl, final boolean bl2, final long l, final int i) {
|
||||||
super(writableLevelData, resourceKey, registryAccess, holder, supplier, bl, bl2, l, i);
|
super(writableLevelData, resourceKey, registryAccess, holder, bl, bl2, l, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
@@ -345,6 +348,21 @@ abstract class ServerLevelMixin extends Level implements ChunkSystemServerLevel,
|
|||||||
return this.entityTickingChunks;
|
return this.entityTickingChunks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean moonrise$areChunksLoaded(final int fromX, final int fromZ, final int toX, final int toZ) {
|
||||||
|
final ServerChunkCache chunkSource = this.chunkSource;
|
||||||
|
|
||||||
|
for (int currZ = fromZ; currZ <= toZ; ++currZ) {
|
||||||
|
for (int currX = fromX; currX <= toX; ++currX) {
|
||||||
|
if (!chunkSource.hasChunk(currX, currZ)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Declare method in this class so that any invocations are virtual, and not interface.
|
* @reason Declare method in this class so that any invocations are virtual, and not interface.
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ abstract class ChunkMapMixin {
|
|||||||
public ServerLevel level;
|
public ServerLevel level;
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
protected abstract boolean playerIsCloseEnoughForSpawning(ServerPlayer serverPlayer, ChunkPos chunkPos);
|
public abstract boolean playerIsCloseEnoughForSpawning(ServerPlayer serverPlayer, ChunkPos chunkPos);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Hook for updating the spawn tracker in distance manager. We add our own hook instead of using the
|
* @reason Hook for updating the spawn tracker in distance manager. We add our own hook instead of using the
|
||||||
@@ -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
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public boolean anyPlayerCloseEnoughForSpawning(final ChunkPos pos) {
|
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(
|
final ReferenceList<ServerPlayer> players = ((ChunkSystemServerLevel)this.level).moonrise$getNearbyPlayers().getPlayers(
|
||||||
pos, NearbyPlayers.NearbyMapType.SPAWN_RANGE
|
pos, NearbyPlayers.NearbyMapType.SPAWN_RANGE
|
||||||
);
|
);
|
||||||
@@ -116,15 +125,15 @@ abstract class ChunkMapMixin {
|
|||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public List<ServerPlayer> getPlayersCloseForSpawning(final ChunkPos pos) {
|
public List<ServerPlayer> getPlayersCloseForSpawning(final ChunkPos pos) {
|
||||||
final List<ServerPlayer> ret = new ArrayList<>();
|
|
||||||
|
|
||||||
final ReferenceList<ServerPlayer> players = ((ChunkSystemServerLevel)this.level).moonrise$getNearbyPlayers().getPlayers(
|
final ReferenceList<ServerPlayer> players = ((ChunkSystemServerLevel)this.level).moonrise$getNearbyPlayers().getPlayers(
|
||||||
pos, NearbyPlayers.NearbyMapType.SPAWN_RANGE
|
pos, NearbyPlayers.NearbyMapType.SPAWN_RANGE
|
||||||
);
|
);
|
||||||
if (players == null) {
|
if (players == null) {
|
||||||
return ret;
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
List<ServerPlayer> ret = null;
|
||||||
|
|
||||||
final ServerPlayer[] raw = players.getRawDataUnchecked();
|
final ServerPlayer[] raw = players.getRawDataUnchecked();
|
||||||
final int len = players.size();
|
final int len = players.size();
|
||||||
|
|
||||||
@@ -132,10 +141,15 @@ abstract class ChunkMapMixin {
|
|||||||
for (int i = 0; i < len; ++i) {
|
for (int i = 0; i < len; ++i) {
|
||||||
final ServerPlayer player = raw[i];
|
final ServerPlayer player = raw[i];
|
||||||
if (this.playerIsCloseEnoughForSpawning(player, pos)) {
|
if (this.playerIsCloseEnoughForSpawning(player, pos)) {
|
||||||
|
if (ret == null) {
|
||||||
|
ret = new ArrayList<>(len - i);
|
||||||
|
ret.add(player);
|
||||||
|
} else {
|
||||||
ret.add(player);
|
ret.add(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret == null ? new ArrayList<>() : ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import ca.spottedleaf.moonrise.common.misc.PositionCountingAreaMap;
|
|||||||
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickConstants;
|
import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickConstants;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickDistanceManager;
|
import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickDistanceManager;
|
||||||
|
import it.unimi.dsi.fastutil.longs.LongIterator;
|
||||||
import net.minecraft.core.SectionPos;
|
import net.minecraft.core.SectionPos;
|
||||||
import net.minecraft.server.level.DistanceManager;
|
import net.minecraft.server.level.DistanceManager;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
@@ -106,4 +107,13 @@ abstract class DistanceManagerMixin implements ChunkTickDistanceManager {
|
|||||||
public boolean hasPlayersNearby(final long pos) {
|
public boolean hasPlayersNearby(final long pos) {
|
||||||
return this.spawnChunkTracker.hasObjectsNear(CoordinateUtils.getChunkX(pos), CoordinateUtils.getChunkZ(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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,24 +1,30 @@
|
|||||||
package ca.spottedleaf.moonrise.mixin.chunk_tick_iteration;
|
package ca.spottedleaf.moonrise.mixin.chunk_tick_iteration;
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.list.ReferenceList;
|
import ca.spottedleaf.moonrise.common.list.ReferenceList;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
import ca.spottedleaf.moonrise.common.misc.NearbyPlayers;
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
import ca.spottedleaf.moonrise.common.util.SimpleRandom;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkData;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemChunkHolder;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickServerLevel;
|
||||||
|
import net.minecraft.Util;
|
||||||
|
import net.minecraft.server.level.ChunkMap;
|
||||||
import net.minecraft.server.level.ServerChunkCache;
|
import net.minecraft.server.level.ServerChunkCache;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
|
import net.minecraft.util.RandomSource;
|
||||||
|
import net.minecraft.world.level.ChunkPos;
|
||||||
import net.minecraft.world.level.chunk.ChunkSource;
|
import net.minecraft.world.level.chunk.ChunkSource;
|
||||||
import org.objectweb.asm.Opcodes;
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
import org.spongepowered.asm.mixin.Final;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.ModifyVariable;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Iterator;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
@Mixin(ServerChunkCache.class)
|
@Mixin(ServerChunkCache.class)
|
||||||
abstract class ServerChunkCacheMixin extends ChunkSource {
|
abstract class ServerChunkCacheMixin extends ChunkSource {
|
||||||
@@ -27,94 +33,84 @@ abstract class ServerChunkCacheMixin extends ChunkSource {
|
|||||||
@Final
|
@Final
|
||||||
public ServerLevel level;
|
public ServerLevel level;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
public ChunkMap chunkMap;
|
||||||
|
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private ServerChunkCache.ChunkAndHolder[] iterationCopy;
|
private final SimpleRandom shuffleRandom = new SimpleRandom(0L);
|
||||||
|
|
||||||
/**
|
@Unique
|
||||||
* @reason Avoid creating the list, which is sized at the chunkholder count. The actual number of ticking
|
private boolean isChunkNearPlayer(final ChunkMap chunkMap, final ChunkPos chunkPos, final LevelChunk levelChunk) {
|
||||||
* chunks is always lower. The mixin below will initialise the list to non-null.
|
final ChunkData chunkData = ((ChunkSystemChunkHolder)((ChunkSystemLevelChunk)levelChunk).moonrise$getChunkAndHolder().holder())
|
||||||
* @author Spottedleaf
|
.moonrise$getRealChunkHolder().holderData;
|
||||||
*/
|
final NearbyPlayers.TrackedChunk nearbyPlayers = chunkData.nearbyPlayers;
|
||||||
@Redirect(
|
if (nearbyPlayers == null) {
|
||||||
method = "tickChunks",
|
return false;
|
||||||
at = @At(
|
|
||||||
value = "INVOKE",
|
|
||||||
target = "Lcom/google/common/collect/Lists;newArrayListWithCapacity(I)Ljava/util/ArrayList;"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
private <T> ArrayList<T> avoidListCreation(final int initialArraySize) {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
final ReferenceList<ServerPlayer> players = nearbyPlayers.getPlayers(NearbyPlayers.NearbyMapType.SPAWN_RANGE);
|
||||||
* @reason Initialise the list to contain only the ticking chunks.
|
|
||||||
* @author Spottedleaf
|
|
||||||
*/
|
|
||||||
@ModifyVariable(
|
|
||||||
method = "tickChunks",
|
|
||||||
at = @At(
|
|
||||||
value = "STORE",
|
|
||||||
opcode = Opcodes.ASTORE,
|
|
||||||
ordinal = 0
|
|
||||||
)
|
|
||||||
)
|
|
||||||
private List<ServerChunkCache.ChunkAndHolder> initTickChunks(final List<ServerChunkCache.ChunkAndHolder> shouldBeNull) {
|
|
||||||
final ReferenceList<ServerChunkCache.ChunkAndHolder> tickingChunks =
|
|
||||||
((ChunkSystemServerLevel)this.level).moonrise$getTickingChunks();
|
|
||||||
|
|
||||||
final ServerChunkCache.ChunkAndHolder[] raw = tickingChunks.getRawDataUnchecked();
|
if (players == null) {
|
||||||
final int size = tickingChunks.size();
|
return false;
|
||||||
|
}
|
||||||
if (this.iterationCopy == null || this.iterationCopy.length < size) {
|
|
||||||
this.iterationCopy = new ServerChunkCache.ChunkAndHolder[raw.length];
|
final ServerPlayer[] raw = players.getRawDataUnchecked();
|
||||||
}
|
final int len = players.size();
|
||||||
System.arraycopy(raw, 0, this.iterationCopy, 0, size);
|
|
||||||
|
Objects.checkFromIndexSize(0, len, raw.length);
|
||||||
return ObjectArrayList.wrap(
|
for (int i = 0; i < len; ++i) {
|
||||||
this.iterationCopy, size
|
if (chunkMap.playerIsCloseEnoughForSpawning(raw[i], chunkPos)) {
|
||||||
);
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @reason Do not initialise ticking chunk list, as we did that above.
|
|
||||||
* @author Spottedleaf
|
|
||||||
*/
|
|
||||||
@Redirect(
|
|
||||||
method = "tickChunks",
|
|
||||||
at = @At(
|
|
||||||
value = "INVOKE",
|
|
||||||
target = "Ljava/util/Iterator;hasNext()Z",
|
|
||||||
ordinal = 0
|
|
||||||
)
|
|
||||||
)
|
|
||||||
private <E> boolean skipTickAdd(final Iterator<E> instance) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Clear the iteration array, and at the same time broadcast chunk changes.
|
* @reason Use the player ticking chunks list, which already contains chunks that are:
|
||||||
|
* 1. block ticking
|
||||||
|
* 2. within spawn range (8 chunks on any axis)
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Overwrite
|
||||||
|
private void collectTickingChunks(final List<LevelChunk> list) {
|
||||||
|
final ReferenceList<ServerChunkCache.ChunkAndHolder> tickingChunks =
|
||||||
|
((ChunkTickServerLevel)this.level).moonrise$getPlayerTickingChunks();
|
||||||
|
|
||||||
|
final ServerChunkCache.ChunkAndHolder[] raw = tickingChunks.getRawDataUnchecked();
|
||||||
|
final int size = tickingChunks.size();
|
||||||
|
|
||||||
|
final ChunkMap chunkMap = this.chunkMap;
|
||||||
|
|
||||||
|
for (int i = 0; i < size; ++i) {
|
||||||
|
final ServerChunkCache.ChunkAndHolder chunkAndHolder = raw[i];
|
||||||
|
final LevelChunk levelChunk = chunkAndHolder.chunk();
|
||||||
|
|
||||||
|
if (!this.isChunkNearPlayer(chunkMap, levelChunk.getPos(), levelChunk)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
list.add(levelChunk);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Use random implementation which does not use CAS and has a faster nextInt(int)
|
||||||
|
* function
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Redirect(
|
@Redirect(
|
||||||
method = "tickChunks",
|
method = "tickChunks()V",
|
||||||
at = @At(
|
at = @At(
|
||||||
value = "INVOKE",
|
value = "INVOKE",
|
||||||
target = "Ljava/util/List;forEach(Ljava/util/function/Consumer;)V",
|
target = "Lnet/minecraft/Util;shuffle(Ljava/util/List;Lnet/minecraft/util/RandomSource;)V"
|
||||||
ordinal = 0
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
private void broadcastChanges(final List<ServerChunkCache.ChunkAndHolder> instance,
|
private <T> void useBetterRandom(final List<T> list, final RandomSource randomSource) {
|
||||||
final Consumer<ServerChunkCache.ChunkAndHolder> consumer) {
|
this.shuffleRandom.setSeed(randomSource.nextLong());
|
||||||
final ObjectArrayList<ServerChunkCache.ChunkAndHolder> chunks = (ObjectArrayList<ServerChunkCache.ChunkAndHolder>)instance;
|
Util.shuffle(list, this.shuffleRandom);
|
||||||
final ServerChunkCache.ChunkAndHolder[] raw = chunks.elements();
|
|
||||||
final int size = chunks.size();
|
|
||||||
|
|
||||||
Objects.checkFromToIndex(0, size, raw.length);
|
|
||||||
for (int i = 0; i < size; ++i) {
|
|
||||||
final ServerChunkCache.ChunkAndHolder holder = raw[i];
|
|
||||||
raw[i] = null;
|
|
||||||
|
|
||||||
holder.holder().broadcastChanges(holder.chunk());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
package ca.spottedleaf.moonrise.mixin.chunk_tick_iteration;
|
||||||
|
|
||||||
|
import ca.spottedleaf.moonrise.common.list.ReferenceList;
|
||||||
|
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
||||||
|
import ca.spottedleaf.moonrise.common.util.TickThread;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.ChunkSystemServerLevel;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.level.chunk.ChunkSystemLevelChunk;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_system.scheduling.NewChunkHolder;
|
||||||
|
import ca.spottedleaf.moonrise.patches.chunk_tick_iteration.ChunkTickServerLevel;
|
||||||
|
import it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap;
|
||||||
|
import net.minecraft.server.level.ServerChunkCache;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.level.ChunkPos;
|
||||||
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
|
||||||
|
@Mixin(ServerLevel.class)
|
||||||
|
abstract class ServerLevelMixin implements ChunkTickServerLevel {
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private static final ServerChunkCache.ChunkAndHolder[] EMPTY_PLAYER_CHUNK_HOLDERS = new ServerChunkCache.ChunkAndHolder[0];
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private final ReferenceList<ServerChunkCache.ChunkAndHolder> playerTickingChunks = new ReferenceList<>(EMPTY_PLAYER_CHUNK_HOLDERS);
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private final Long2IntOpenHashMap playerTickingRequests = new Long2IntOpenHashMap();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final ReferenceList<ServerChunkCache.ChunkAndHolder> moonrise$getPlayerTickingChunks() {
|
||||||
|
return this.playerTickingChunks;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void moonrise$markChunkForPlayerTicking(final LevelChunk chunk) {
|
||||||
|
final ChunkPos pos = chunk.getPos();
|
||||||
|
if (!this.playerTickingRequests.containsKey(CoordinateUtils.getChunkKey(pos))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.playerTickingChunks.add(((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void moonrise$removeChunkForPlayerTicking(final LevelChunk chunk) {
|
||||||
|
this.playerTickingChunks.remove(((ChunkSystemLevelChunk)chunk).moonrise$getChunkAndHolder());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void moonrise$addPlayerTickingRequest(final int chunkX, final int chunkZ) {
|
||||||
|
TickThread.ensureTickThread((ServerLevel)(Object)this, chunkX, chunkZ, "Cannot add ticking request async");
|
||||||
|
|
||||||
|
final long chunkKey = CoordinateUtils.getChunkKey(chunkX, chunkZ);
|
||||||
|
|
||||||
|
if (this.playerTickingRequests.addTo(chunkKey, 1) != 0) {
|
||||||
|
// already added
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final NewChunkHolder chunkHolder = ((ChunkSystemServerLevel)(ServerLevel)(Object)this).moonrise$getChunkTaskScheduler()
|
||||||
|
.chunkHolderManager.getChunkHolder(chunkKey);
|
||||||
|
|
||||||
|
if (chunkHolder == null || !chunkHolder.isTickingReady()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.playerTickingChunks.add(
|
||||||
|
((ChunkSystemLevelChunk)(LevelChunk)chunkHolder.getCurrentChunk()).moonrise$getChunkAndHolder()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void moonrise$removePlayerTickingRequest(final int chunkX, final int chunkZ) {
|
||||||
|
TickThread.ensureTickThread((ServerLevel)(Object)this, chunkX, chunkZ, "Cannot remove ticking request async");
|
||||||
|
|
||||||
|
final long chunkKey = CoordinateUtils.getChunkKey(chunkX, chunkZ);
|
||||||
|
final int val = this.playerTickingRequests.addTo(chunkKey, -1);
|
||||||
|
|
||||||
|
if (val <= 0) {
|
||||||
|
throw new IllegalStateException("Negative counter");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val != 1) {
|
||||||
|
// still has at least one request
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final NewChunkHolder chunkHolder = ((ChunkSystemServerLevel)(ServerLevel)(Object)this).moonrise$getChunkTaskScheduler()
|
||||||
|
.chunkHolderManager.getChunkHolder(chunkKey);
|
||||||
|
|
||||||
|
if (chunkHolder == null || !chunkHolder.isTickingReady()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.playerTickingChunks.remove(
|
||||||
|
((ChunkSystemLevelChunk)(LevelChunk)chunkHolder.getCurrentChunk()).moonrise$getChunkAndHolder()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -6,37 +6,32 @@ import net.minecraft.world.entity.LivingEntity;
|
|||||||
import net.minecraft.world.entity.decoration.ArmorStand;
|
import net.minecraft.world.entity.decoration.ArmorStand;
|
||||||
import net.minecraft.world.entity.vehicle.AbstractMinecart;
|
import net.minecraft.world.entity.vehicle.AbstractMinecart;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
import net.minecraft.world.phys.AABB;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
@Mixin(ArmorStand.class)
|
@Mixin(ArmorStand.class)
|
||||||
abstract class ArmorStandMixin extends LivingEntity {
|
abstract class ArmorStandMixin extends LivingEntity {
|
||||||
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
private static Predicate<Entity> RIDABLE_MINECARTS;
|
|
||||||
|
|
||||||
protected ArmorStandMixin(EntityType<? extends LivingEntity> entityType, Level level) {
|
protected ArmorStandMixin(EntityType<? extends LivingEntity> entityType, Level level) {
|
||||||
super(entityType, level);
|
super(entityType, level);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Optimise this method by making it use the class lookup
|
* @reason Optimise by making it use the class lookup
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Redirect(
|
||||||
public void pushEntities() {
|
method = "pushEntities",
|
||||||
final List<AbstractMinecart> nearby = this.level().getEntitiesOfClass(AbstractMinecart.class, this.getBoundingBox(), RIDABLE_MINECARTS);
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
for (int i = 0, len = nearby.size(); i < len; ++i) {
|
target = "Lnet/minecraft/world/level/Level;getEntities(Lnet/minecraft/world/entity/Entity;Lnet/minecraft/world/phys/AABB;Ljava/util/function/Predicate;)Ljava/util/List;"
|
||||||
final AbstractMinecart minecart = nearby.get(i);
|
)
|
||||||
if (this.distanceToSqr(minecart) <= 0.2) {
|
)
|
||||||
minecart.push(this);
|
private List<Entity> redirectGetEntities(final Level instance, final Entity entity, final AABB list, final Predicate<? super Entity> arg) {
|
||||||
}
|
return (List)this.level().getEntitiesOfClass(AbstractMinecart.class, this.getBoundingBox(), arg);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,14 @@ import net.minecraft.core.BlockPos;
|
|||||||
import net.minecraft.core.Vec3i;
|
import net.minecraft.core.Vec3i;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
|
||||||
@Mixin(BlockPos.class)
|
@Mixin(BlockPos.class)
|
||||||
abstract class BlockPosMixin extends Vec3i {
|
abstract class BlockPosMixin extends Vec3i {
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
public abstract BlockPos immutable();
|
||||||
|
|
||||||
public BlockPosMixin(int i, int j, int k) {
|
public BlockPosMixin(int i, int j, int k) {
|
||||||
super(i, j, k);
|
super(i, j, k);
|
||||||
}
|
}
|
||||||
@@ -29,7 +33,7 @@ abstract class BlockPosMixin extends Vec3i {
|
|||||||
@Overwrite
|
@Overwrite
|
||||||
@Override
|
@Override
|
||||||
public BlockPos above(final int distance) {
|
public BlockPos above(final int distance) {
|
||||||
return distance == 0 ? (BlockPos)(Object)this : new BlockPos(this.getX(), this.getY() + distance, this.getZ());
|
return distance == 0 ? this.immutable() : new BlockPos(this.getX(), this.getY() + distance, this.getZ());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -49,7 +53,7 @@ abstract class BlockPosMixin extends Vec3i {
|
|||||||
@Overwrite
|
@Overwrite
|
||||||
@Override
|
@Override
|
||||||
public BlockPos below(final int distance) {
|
public BlockPos below(final int distance) {
|
||||||
return distance == 0 ? (BlockPos)(Object)this : new BlockPos(this.getX(), this.getY() - distance, this.getZ());
|
return distance == 0 ? this.immutable() : new BlockPos(this.getX(), this.getY() - distance, this.getZ());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,7 +73,7 @@ abstract class BlockPosMixin extends Vec3i {
|
|||||||
@Overwrite
|
@Overwrite
|
||||||
@Override
|
@Override
|
||||||
public BlockPos north(final int distance) {
|
public BlockPos north(final int distance) {
|
||||||
return distance == 0 ? (BlockPos)(Object)this : new BlockPos(this.getX(), this.getY(), this.getZ() - distance);
|
return distance == 0 ? this.immutable() : new BlockPos(this.getX(), this.getY(), this.getZ() - distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -89,7 +93,7 @@ abstract class BlockPosMixin extends Vec3i {
|
|||||||
@Overwrite
|
@Overwrite
|
||||||
@Override
|
@Override
|
||||||
public BlockPos south(final int distance) {
|
public BlockPos south(final int distance) {
|
||||||
return distance == 0 ? (BlockPos)(Object)this : new BlockPos(this.getX(), this.getY(), this.getZ() + distance);
|
return distance == 0 ? this.immutable() : new BlockPos(this.getX(), this.getY(), this.getZ() + distance);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -109,7 +113,7 @@ abstract class BlockPosMixin extends Vec3i {
|
|||||||
@Overwrite
|
@Overwrite
|
||||||
@Override
|
@Override
|
||||||
public BlockPos west(final int distance) {
|
public BlockPos west(final int distance) {
|
||||||
return distance == 0 ? (BlockPos)(Object)this : new BlockPos(this.getX() - distance, this.getY(), this.getZ());
|
return distance == 0 ? this.immutable() : new BlockPos(this.getX() - distance, this.getY(), this.getZ());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -129,6 +133,6 @@ abstract class BlockPosMixin extends Vec3i {
|
|||||||
@Overwrite
|
@Overwrite
|
||||||
@Override
|
@Override
|
||||||
public BlockPos east(final int distance) {
|
public BlockPos east(final int distance) {
|
||||||
return distance == 0 ? (BlockPos)(Object)this : new BlockPos(this.getX() + distance, this.getY(), this.getZ());
|
return distance == 0 ? this.immutable() : new BlockPos(this.getX() + distance, this.getY(), this.getZ());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,12 @@ abstract class BlockStateBaseMixin extends StateHolder<Block, BlockState> implem
|
|||||||
@Shadow
|
@Shadow
|
||||||
public abstract VoxelShape getCollisionShape(BlockGetter blockGetter, BlockPos blockPos, CollisionContext collisionContext);
|
public abstract VoxelShape getCollisionShape(BlockGetter blockGetter, BlockPos blockPos, CollisionContext collisionContext);
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
public VoxelShape[] occlusionShapesByFace;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
public VoxelShape occlusionShape;
|
||||||
|
|
||||||
protected BlockStateBaseMixin(Block object, Reference2ObjectArrayMap<Property<?>, Comparable<?>> reference2ObjectArrayMap, MapCodec<BlockState> mapCodec) {
|
protected BlockStateBaseMixin(Block object, Reference2ObjectArrayMap<Property<?>, Comparable<?>> reference2ObjectArrayMap, MapCodec<BlockState> mapCodec) {
|
||||||
super(object, reference2ObjectArrayMap, mapCodec);
|
super(object, reference2ObjectArrayMap, mapCodec);
|
||||||
}
|
}
|
||||||
@@ -74,7 +80,7 @@ abstract class BlockStateBaseMixin extends StateHolder<Block, BlockState> implem
|
|||||||
}
|
}
|
||||||
if (neighbours) {
|
if (neighbours) {
|
||||||
for (final Direction direction : DIRECTIONS_CACHED) {
|
for (final Direction direction : DIRECTIONS_CACHED) {
|
||||||
initCaches(Shapes.getFaceShape(shape, direction), false);
|
initCaches(((CollisionVoxelShape)shape).moonrise$getFaceShapeClamped(direction), false);
|
||||||
initCaches(shape.getFaceShape(direction), false);
|
initCaches(shape.getFaceShape(direction), false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -107,17 +113,21 @@ abstract class BlockStateBaseMixin extends StateHolder<Block, BlockState> implem
|
|||||||
if (this.constantCollisionShape != null) {
|
if (this.constantCollisionShape != null) {
|
||||||
initCaches(this.constantCollisionShape, true);
|
initCaches(this.constantCollisionShape, true);
|
||||||
}
|
}
|
||||||
if (this.cache.occlusionShapes != null) {
|
|
||||||
for (final VoxelShape shape : this.cache.occlusionShapes) {
|
|
||||||
initCaches(shape, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
this.occludesFullBlock = false;
|
this.occludesFullBlock = false;
|
||||||
this.emptyCollisionShape = false;
|
this.emptyCollisionShape = false;
|
||||||
this.emptyConstantCollisionShape = false;
|
this.emptyConstantCollisionShape = false;
|
||||||
this.constantCollisionShape = null;
|
this.constantCollisionShape = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.occlusionShape != null) {
|
||||||
|
initCaches(this.occlusionShape, true);
|
||||||
|
}
|
||||||
|
if (this.occlusionShapesByFace != null) {
|
||||||
|
for (final VoxelShape shape : this.occlusionShapesByFace) {
|
||||||
|
initCaches(shape, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package ca.spottedleaf.moonrise.mixin.collisions;
|
package ca.spottedleaf.moonrise.mixin.collisions;
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
import ca.spottedleaf.moonrise.common.util.WorldUtil;
|
||||||
import ca.spottedleaf.moonrise.patches.collisions.CollisionUtil;
|
import ca.spottedleaf.moonrise.patches.collisions.CollisionUtil;
|
||||||
import ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState;
|
import ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState;
|
||||||
import ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape;
|
import ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape;
|
||||||
@@ -10,11 +10,11 @@ import net.minecraft.core.BlockPos;
|
|||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.EntityDimensions;
|
import net.minecraft.world.entity.EntityDimensions;
|
||||||
import net.minecraft.world.level.ChunkPos;
|
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.chunk.ChunkSource;
|
import net.minecraft.world.level.chunk.ChunkSource;
|
||||||
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.chunk.status.ChunkStatus;
|
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||||
import net.minecraft.world.phys.AABB;
|
import net.minecraft.world.phys.AABB;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
@@ -48,7 +48,7 @@ abstract class EntityMixin {
|
|||||||
public abstract Vec3 getEyePosition();
|
public abstract Vec3 getEyePosition();
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
public abstract boolean onGround();
|
private boolean onGround;
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private static float[] calculateStepHeights(final AABB box, final List<VoxelShape> voxels, final List<AABB> aabbs, final float stepHeight,
|
private static float[] calculateStepHeights(final AABB box, final List<VoxelShape> voxels, final List<AABB> aabbs, final float stepHeight,
|
||||||
@@ -144,9 +144,9 @@ abstract class EntityMixin {
|
|||||||
|
|
||||||
final boolean collidedDownwards = collidedY && movement.y < 0.0;
|
final boolean collidedDownwards = collidedY && movement.y < 0.0;
|
||||||
|
|
||||||
final double stepHeight = (double)this.maxUpStep();
|
final double stepHeight;
|
||||||
|
|
||||||
if (stepHeight <= 0.0 || (!collidedDownwards && !this.onGround()) || (!collidedX && !collidedZ)) {
|
if ((!collidedDownwards && !this.onGround) || (!collidedX && !collidedZ) || (stepHeight = (double)this.maxUpStep()) <= 0.0) {
|
||||||
return collided;
|
return collided;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -184,51 +184,83 @@ abstract class EntityMixin {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final float reducedWith = this.dimensions.width() * 0.8F;
|
final double reducedWith = (double)(this.dimensions.width() * 0.8F);
|
||||||
final AABB box = AABB.ofSize(this.getEyePosition(), reducedWith, 1.0E-6D, reducedWith);
|
final AABB boundingBox = AABB.ofSize(this.getEyePosition(), reducedWith, 1.0E-6D, reducedWith);
|
||||||
|
final Level world = this.level;
|
||||||
|
|
||||||
if (CollisionUtil.isEmpty(box)) {
|
if (CollisionUtil.isEmpty(boundingBox)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final BlockPos.MutableBlockPos tempPos = new BlockPos.MutableBlockPos();
|
final int minBlockX = Mth.floor(boundingBox.minX);
|
||||||
|
final int minBlockY = Mth.floor(boundingBox.minY);
|
||||||
|
final int minBlockZ = Mth.floor(boundingBox.minZ);
|
||||||
|
|
||||||
final int minX = Mth.floor(box.minX);
|
final int maxBlockX = Mth.floor(boundingBox.maxX);
|
||||||
final int minY = Mth.floor(box.minY);
|
final int maxBlockY = Mth.floor(boundingBox.maxY);
|
||||||
final int minZ = Mth.floor(box.minZ);
|
final int maxBlockZ = Mth.floor(boundingBox.maxZ);
|
||||||
final int maxX = Mth.floor(box.maxX);
|
|
||||||
final int maxY = Mth.floor(box.maxY);
|
|
||||||
final int maxZ = Mth.floor(box.maxZ);
|
|
||||||
|
|
||||||
final ChunkSource chunkProvider = this.level.getChunkSource();
|
final int minChunkX = minBlockX >> 4;
|
||||||
|
final int minChunkY = minBlockY >> 4;
|
||||||
|
final int minChunkZ = minBlockZ >> 4;
|
||||||
|
|
||||||
long lastChunkKey = ChunkPos.INVALID_CHUNK_POS;
|
final int maxChunkX = maxBlockX >> 4;
|
||||||
LevelChunk lastChunk = null;
|
final int maxChunkY = maxBlockY >> 4;
|
||||||
for (int fz = minZ; fz <= maxZ; ++fz) {
|
final int maxChunkZ = maxBlockZ >> 4;
|
||||||
tempPos.setZ(fz);
|
|
||||||
for (int fx = minX; fx <= maxX; ++fx) {
|
|
||||||
final int newChunkX = fx >> 4;
|
|
||||||
final int newChunkZ = fz >> 4;
|
|
||||||
final LevelChunk chunk = lastChunkKey == (lastChunkKey = CoordinateUtils.getChunkKey(newChunkX, newChunkZ)) ?
|
|
||||||
lastChunk : (lastChunk = (LevelChunk)chunkProvider.getChunk(newChunkX, newChunkZ, ChunkStatus.FULL, true));
|
|
||||||
tempPos.setX(fx);
|
|
||||||
for (int fy = minY; fy <= maxY; ++fy) {
|
|
||||||
tempPos.setY(fy);
|
|
||||||
|
|
||||||
final BlockState state = chunk.getBlockState(tempPos);
|
final int minSection = WorldUtil.getMinSection(world);
|
||||||
|
final ChunkSource chunkSource = world.getChunkSource();
|
||||||
|
final BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos();
|
||||||
|
|
||||||
if (((CollisionBlockState)state).moonrise$emptyCollisionShape() || !state.isSuffocating(this.level, tempPos)) {
|
for (int currChunkZ = minChunkZ; currChunkZ <= maxChunkZ; ++currChunkZ) {
|
||||||
|
for (int currChunkX = minChunkX; currChunkX <= maxChunkX; ++currChunkX) {
|
||||||
|
final LevelChunkSection[] sections = chunkSource.getChunk(currChunkX, currChunkZ, ChunkStatus.FULL, true).getSections();
|
||||||
|
|
||||||
|
for (int currChunkY = minChunkY; currChunkY <= maxChunkY; ++currChunkY) {
|
||||||
|
final int sectionIdx = currChunkY - minSection;
|
||||||
|
if (sectionIdx < 0 || sectionIdx >= sections.length) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final LevelChunkSection section = sections[sectionIdx];
|
||||||
|
if (section.hasOnlyAir()) {
|
||||||
|
// empty
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final PalettedContainer<BlockState> blocks = section.states;
|
||||||
|
|
||||||
|
final int minXIterate = currChunkX == minChunkX ? (minBlockX & 15) : 0;
|
||||||
|
final int maxXIterate = currChunkX == maxChunkX ? (maxBlockX & 15) : 15;
|
||||||
|
final int minZIterate = currChunkZ == minChunkZ ? (minBlockZ & 15) : 0;
|
||||||
|
final int maxZIterate = currChunkZ == maxChunkZ ? (maxBlockZ & 15) : 15;
|
||||||
|
final int minYIterate = currChunkY == minChunkY ? (minBlockY & 15) : 0;
|
||||||
|
final int maxYIterate = currChunkY == maxChunkY ? (maxBlockY & 15) : 15;
|
||||||
|
|
||||||
|
for (int currY = minYIterate; currY <= maxYIterate; ++currY) {
|
||||||
|
final int blockY = currY | (currChunkY << 4);
|
||||||
|
mutablePos.setY(blockY);
|
||||||
|
for (int currZ = minZIterate; currZ <= maxZIterate; ++currZ) {
|
||||||
|
final int blockZ = currZ | (currChunkZ << 4);
|
||||||
|
mutablePos.setZ(blockZ);
|
||||||
|
for (int currX = minXIterate; currX <= maxXIterate; ++currX) {
|
||||||
|
final int blockX = currX | (currChunkX << 4);
|
||||||
|
mutablePos.setX(blockX);
|
||||||
|
|
||||||
|
final BlockState blockState = blocks.get((currX) | (currZ << 4) | ((currY) << 8));
|
||||||
|
|
||||||
|
if (((CollisionBlockState)blockState).moonrise$emptyCollisionShape()
|
||||||
|
|| !blockState.isSuffocating(world, mutablePos)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Yes, it does not use the Entity context stuff.
|
// Yes, it does not use the Entity context stuff.
|
||||||
final VoxelShape collisionShape = state.getCollisionShape(this.level, tempPos);
|
final VoxelShape collisionShape = blockState.getCollisionShape(world, mutablePos);
|
||||||
|
|
||||||
if (collisionShape.isEmpty()) {
|
if (collisionShape.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
final AABB toCollide = box.move(-(double)fx, -(double)fy, -(double)fz);
|
final AABB toCollide = boundingBox.move(-(double)blockX, -(double)blockY, -(double)blockZ);
|
||||||
|
|
||||||
final AABB singleAABB = ((CollisionVoxelShape)collisionShape).moonrise$getSingleAABBRepresentation();
|
final AABB singleAABB = ((CollisionVoxelShape)collisionShape).moonrise$getSingleAABBRepresentation();
|
||||||
if (singleAABB != null) {
|
if (singleAABB != null) {
|
||||||
@@ -245,6 +277,9 @@ abstract class EntityMixin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
package ca.spottedleaf.moonrise.mixin.collisions;
|
package ca.spottedleaf.moonrise.mixin.collisions;
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.util.WorldUtil;
|
import ca.spottedleaf.moonrise.common.util.WorldUtil;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_getblock.GetBlockChunk;
|
import ca.spottedleaf.moonrise.patches.block_counting.BlockCountingChunkSection;
|
||||||
import ca.spottedleaf.moonrise.patches.collisions.CollisionUtil;
|
import ca.spottedleaf.moonrise.patches.collisions.CollisionUtil;
|
||||||
import ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState;
|
import ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState;
|
||||||
import ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape;
|
import ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape;
|
||||||
import ca.spottedleaf.moonrise.patches.collisions.world.CollisionLevel;
|
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
@@ -16,6 +15,7 @@ import net.minecraft.world.level.LevelAccessor;
|
|||||||
import net.minecraft.world.level.block.Blocks;
|
import net.minecraft.world.level.block.Blocks;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.level.border.WorldBorder;
|
import net.minecraft.world.level.border.WorldBorder;
|
||||||
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
import net.minecraft.world.level.chunk.ChunkSource;
|
import net.minecraft.world.level.chunk.ChunkSource;
|
||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||||
@@ -27,20 +27,18 @@ import net.minecraft.world.phys.AABB;
|
|||||||
import net.minecraft.world.phys.BlockHitResult;
|
import net.minecraft.world.phys.BlockHitResult;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
import net.minecraft.world.phys.shapes.BooleanOp;
|
import net.minecraft.world.phys.shapes.BooleanOp;
|
||||||
|
import net.minecraft.world.phys.shapes.CollisionContext;
|
||||||
import net.minecraft.world.phys.shapes.Shapes;
|
import net.minecraft.world.phys.shapes.Shapes;
|
||||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@Mixin(Level.class)
|
@Mixin(Level.class)
|
||||||
abstract class LevelMixin implements CollisionLevel, LevelAccessor, AutoCloseable {
|
abstract class LevelMixin implements LevelAccessor, AutoCloseable {
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
public abstract LevelChunk getChunk(int x, int z);
|
public abstract LevelChunk getChunk(int x, int z);
|
||||||
@@ -48,38 +46,6 @@ abstract class LevelMixin implements CollisionLevel, LevelAccessor, AutoCloseabl
|
|||||||
@Shadow
|
@Shadow
|
||||||
public abstract WorldBorder getWorldBorder();
|
public abstract WorldBorder getWorldBorder();
|
||||||
|
|
||||||
|
|
||||||
@Unique
|
|
||||||
private int minSection;
|
|
||||||
|
|
||||||
@Unique
|
|
||||||
private int maxSection;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final int moonrise$getMinSection() {
|
|
||||||
return this.minSection;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public final int moonrise$getMaxSection() {
|
|
||||||
return this.maxSection;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @reason Init min/max section
|
|
||||||
* @author Spottedleaf
|
|
||||||
*/
|
|
||||||
@Inject(
|
|
||||||
method = "<init>",
|
|
||||||
at = @At(
|
|
||||||
value = "RETURN"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
private void init(final CallbackInfo ci) {
|
|
||||||
this.minSection = WorldUtil.getMinSection(this);
|
|
||||||
this.maxSection = WorldUtil.getMaxSection(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Route to faster lookup.
|
* Route to faster lookup.
|
||||||
* See {@link EntityGetterMixin#isUnobstructed(Entity, VoxelShape)} for expected behavior
|
* See {@link EntityGetterMixin#isUnobstructed(Entity, VoxelShape)} for expected behavior
|
||||||
@@ -117,7 +83,7 @@ abstract class LevelMixin implements CollisionLevel, LevelAccessor, AutoCloseabl
|
|||||||
final Vec3 to = clipContext.getTo();
|
final Vec3 to = clipContext.getTo();
|
||||||
final Vec3 from = clipContext.getFrom();
|
final Vec3 from = clipContext.getFrom();
|
||||||
|
|
||||||
return BlockHitResult.miss(to, Direction.getNearest(from.x - to.x, from.y - to.y, from.z - to.z), BlockPos.containing(to.x, to.y, to.z));
|
return BlockHitResult.miss(to, Direction.getApproximateNearest(from.x - to.x, from.y - to.y, from.z - to.z), BlockPos.containing(to.x, to.y, to.z));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
@@ -173,7 +139,7 @@ abstract class LevelMixin implements CollisionLevel, LevelAccessor, AutoCloseabl
|
|||||||
int lastChunkY = Integer.MIN_VALUE;
|
int lastChunkY = Integer.MIN_VALUE;
|
||||||
int lastChunkZ = Integer.MIN_VALUE;
|
int lastChunkZ = Integer.MIN_VALUE;
|
||||||
|
|
||||||
final int minSection = ((CollisionLevel)level).moonrise$getMinSection();
|
final int minSection = WorldUtil.getMinSection(level);
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
currPos.set(currX, currY, currZ);
|
currPos.set(currX, currY, currZ);
|
||||||
@@ -368,83 +334,116 @@ abstract class LevelMixin implements CollisionLevel, LevelAccessor, AutoCloseabl
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Optional<BlockPos> findSupportingBlock(final Entity entity, final AABB aabb) {
|
public Optional<BlockPos> findSupportingBlock(final Entity entity, final AABB aabb) {
|
||||||
|
final int minSection = WorldUtil.getMinSection((Level)(Object)this);
|
||||||
|
|
||||||
final int minBlockX = Mth.floor(aabb.minX - CollisionUtil.COLLISION_EPSILON) - 1;
|
final int minBlockX = Mth.floor(aabb.minX - CollisionUtil.COLLISION_EPSILON) - 1;
|
||||||
final int maxBlockX = Mth.floor(aabb.maxX + CollisionUtil.COLLISION_EPSILON) + 1;
|
final int maxBlockX = Mth.floor(aabb.maxX + CollisionUtil.COLLISION_EPSILON) + 1;
|
||||||
|
|
||||||
final int minBlockY = Mth.floor(aabb.minY - CollisionUtil.COLLISION_EPSILON) - 1;
|
final int minBlockY = Math.max((minSection << 4) - 1, Mth.floor(aabb.minY - CollisionUtil.COLLISION_EPSILON) - 1);
|
||||||
final int maxBlockY = Mth.floor(aabb.maxY + CollisionUtil.COLLISION_EPSILON) + 1;
|
final int maxBlockY = Math.min((WorldUtil.getMaxSection((Level)(Object)this) << 4) + 16, Mth.floor(aabb.maxY + CollisionUtil.COLLISION_EPSILON) + 1);
|
||||||
|
|
||||||
final int minBlockZ = Mth.floor(aabb.minZ - CollisionUtil.COLLISION_EPSILON) - 1;
|
final int minBlockZ = Mth.floor(aabb.minZ - CollisionUtil.COLLISION_EPSILON) - 1;
|
||||||
final int maxBlockZ = Mth.floor(aabb.maxZ + CollisionUtil.COLLISION_EPSILON) + 1;
|
final int maxBlockZ = Mth.floor(aabb.maxZ + CollisionUtil.COLLISION_EPSILON) + 1;
|
||||||
|
|
||||||
CollisionUtil.LazyEntityCollisionContext collisionContext = null;
|
final BlockPos.MutableBlockPos mutablePos = new BlockPos.MutableBlockPos();
|
||||||
|
final CollisionContext collisionShape = new CollisionUtil.LazyEntityCollisionContext(entity);
|
||||||
final BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
|
|
||||||
BlockPos selected = null;
|
BlockPos selected = null;
|
||||||
double selectedDistance = Double.MAX_VALUE;
|
double selectedDistance = Double.MAX_VALUE;
|
||||||
|
|
||||||
final Vec3 entityPos = entity.position();
|
final Vec3 entityPos = entity.position();
|
||||||
|
|
||||||
LevelChunk lastChunk = null;
|
// special cases:
|
||||||
int lastChunkX = Integer.MIN_VALUE;
|
if (minBlockY > maxBlockY) {
|
||||||
int lastChunkZ = Integer.MIN_VALUE;
|
// no point in checking
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
final int minChunkX = minBlockX >> 4;
|
||||||
|
final int maxChunkX = maxBlockX >> 4;
|
||||||
|
|
||||||
|
final int minChunkY = minBlockY >> 4;
|
||||||
|
final int maxChunkY = maxBlockY >> 4;
|
||||||
|
|
||||||
|
final int minChunkZ = minBlockZ >> 4;
|
||||||
|
final int maxChunkZ = maxBlockZ >> 4;
|
||||||
|
|
||||||
final ChunkSource chunkSource = this.getChunkSource();
|
final ChunkSource chunkSource = this.getChunkSource();
|
||||||
|
|
||||||
for (int currZ = minBlockZ; currZ <= maxBlockZ; ++currZ) {
|
for (int currChunkZ = minChunkZ; currChunkZ <= maxChunkZ; ++currChunkZ) {
|
||||||
pos.setZ(currZ);
|
for (int currChunkX = minChunkX; currChunkX <= maxChunkX; ++currChunkX) {
|
||||||
for (int currX = minBlockX; currX <= maxBlockX; ++currX) {
|
final ChunkAccess chunk = chunkSource.getChunk(currChunkX, currChunkZ, ChunkStatus.FULL, false);
|
||||||
pos.setX(currX);
|
|
||||||
|
|
||||||
final int newChunkX = currX >> 4;
|
if (chunk == null) {
|
||||||
final int newChunkZ = currZ >> 4;
|
|
||||||
|
|
||||||
if (((newChunkX ^ lastChunkX) | (newChunkZ ^ lastChunkZ)) != 0) {
|
|
||||||
lastChunkX = newChunkX;
|
|
||||||
lastChunkZ = newChunkZ;
|
|
||||||
lastChunk = (LevelChunk)chunkSource.getChunk(newChunkX, newChunkZ, ChunkStatus.FULL, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lastChunk == null) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (int currY = minBlockY; currY <= maxBlockY; ++currY) {
|
|
||||||
int edgeCount = ((currX == minBlockX || currX == maxBlockX) ? 1 : 0) +
|
final LevelChunkSection[] sections = chunk.getSections();
|
||||||
((currY == minBlockY || currY == maxBlockY) ? 1 : 0) +
|
|
||||||
((currZ == minBlockZ || currZ == maxBlockZ) ? 1 : 0);
|
// bound y
|
||||||
|
for (int currChunkY = minChunkY; currChunkY <= maxChunkY; ++currChunkY) {
|
||||||
|
final int sectionIdx = currChunkY - minSection;
|
||||||
|
if (sectionIdx < 0 || sectionIdx >= sections.length) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
final LevelChunkSection section = sections[sectionIdx];
|
||||||
|
if (section.hasOnlyAir()) {
|
||||||
|
// empty
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final boolean hasSpecial = ((BlockCountingChunkSection)section).moonrise$hasSpecialCollidingBlocks();
|
||||||
|
final int sectionAdjust = !hasSpecial ? 1 : 0;
|
||||||
|
|
||||||
|
final PalettedContainer<BlockState> blocks = section.states;
|
||||||
|
|
||||||
|
final int minXIterate = currChunkX == minChunkX ? (minBlockX & 15) + sectionAdjust : 0;
|
||||||
|
final int maxXIterate = currChunkX == maxChunkX ? (maxBlockX & 15) - sectionAdjust : 15;
|
||||||
|
final int minZIterate = currChunkZ == minChunkZ ? (minBlockZ & 15) + sectionAdjust : 0;
|
||||||
|
final int maxZIterate = currChunkZ == maxChunkZ ? (maxBlockZ & 15) - sectionAdjust : 15;
|
||||||
|
final int minYIterate = currChunkY == minChunkY ? (minBlockY & 15) + sectionAdjust : 0;
|
||||||
|
final int maxYIterate = currChunkY == maxChunkY ? (maxBlockY & 15) - sectionAdjust : 15;
|
||||||
|
|
||||||
|
for (int currY = minYIterate; currY <= maxYIterate; ++currY) {
|
||||||
|
final int blockY = currY | (currChunkY << 4);
|
||||||
|
mutablePos.setY(blockY);
|
||||||
|
for (int currZ = minZIterate; currZ <= maxZIterate; ++currZ) {
|
||||||
|
final int blockZ = currZ | (currChunkZ << 4);
|
||||||
|
mutablePos.setZ(blockZ);
|
||||||
|
for (int currX = minXIterate; currX <= maxXIterate; ++currX) {
|
||||||
|
final int localBlockIndex = (currX) | (currZ << 4) | ((currY) << 8);
|
||||||
|
final int blockX = currX | (currChunkX << 4);
|
||||||
|
mutablePos.setX(blockX);
|
||||||
|
|
||||||
|
final int edgeCount = hasSpecial ? ((blockX == minBlockX || blockX == maxBlockX) ? 1 : 0) +
|
||||||
|
((blockY == minBlockY || blockY == maxBlockY) ? 1 : 0) +
|
||||||
|
((blockZ == minBlockZ || blockZ == maxBlockZ) ? 1 : 0) : 0;
|
||||||
if (edgeCount == 3) {
|
if (edgeCount == 3) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
pos.setY(currY);
|
final double distance = mutablePos.distToCenterSqr(entityPos);
|
||||||
|
if (distance > selectedDistance || (distance == selectedDistance && selected.compareTo(mutablePos) >= 0)) {
|
||||||
final double distance = pos.distToCenterSqr(entityPos);
|
|
||||||
if (distance > selectedDistance || (distance == selectedDistance && selected.compareTo(pos) >= 0)) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
final BlockState state = ((GetBlockChunk)lastChunk).moonrise$getBlock(currX, currY, currZ);
|
final BlockState blockData = blocks.get(localBlockIndex);
|
||||||
if (((CollisionBlockState)state).moonrise$emptyContextCollisionShape()) {
|
|
||||||
|
if (((CollisionBlockState)blockData).moonrise$emptyContextCollisionShape()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
VoxelShape blockCollision = ((CollisionBlockState)state).moonrise$getConstantContextCollisionShape();
|
VoxelShape blockCollision = ((CollisionBlockState)blockData).moonrise$getConstantContextCollisionShape();
|
||||||
|
|
||||||
if ((edgeCount != 1 || state.hasLargeCollisionShape()) && (edgeCount != 2 || state.getBlock() == Blocks.MOVING_PISTON)) {
|
|
||||||
if (collisionContext == null) {
|
|
||||||
collisionContext = new CollisionUtil.LazyEntityCollisionContext(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (edgeCount == 0 || ((edgeCount != 1 || blockData.hasLargeCollisionShape()) && (edgeCount != 2 || blockData.getBlock() == Blocks.MOVING_PISTON))) {
|
||||||
if (blockCollision == null) {
|
if (blockCollision == null) {
|
||||||
blockCollision = state.getCollisionShape((Level)(Object)this, pos, collisionContext);
|
blockCollision = blockData.getCollisionShape((Level)(Object)this, mutablePos, collisionShape);
|
||||||
}
|
|
||||||
|
|
||||||
if (blockCollision.isEmpty()) {
|
if (blockCollision.isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// avoid VoxelShape#move by shifting the entity collision shape instead
|
// avoid VoxelShape#move by shifting the entity collision shape instead
|
||||||
final AABB shiftedAABB = aabb.move(-(double)currX, -(double)currY, -(double)currZ);
|
final AABB shiftedAABB = aabb.move(-(double)blockX, -(double)blockY, -(double)blockZ);
|
||||||
|
|
||||||
final AABB singleAABB = ((CollisionVoxelShape)blockCollision).moonrise$getSingleAABBRepresentation();
|
final AABB singleAABB = ((CollisionVoxelShape)blockCollision).moonrise$getSingleAABBRepresentation();
|
||||||
if (singleAABB != null) {
|
if (singleAABB != null) {
|
||||||
@@ -452,7 +451,7 @@ abstract class LevelMixin implements CollisionLevel, LevelAccessor, AutoCloseabl
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
selected = pos.immutable();
|
selected = mutablePos.immutable();
|
||||||
selectedDistance = distance;
|
selectedDistance = distance;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -461,13 +460,16 @@ abstract class LevelMixin implements CollisionLevel, LevelAccessor, AutoCloseabl
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
selected = pos.immutable();
|
selected = mutablePos.immutable();
|
||||||
selectedDistance = distance;
|
selectedDistance = distance;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return Optional.ofNullable(selected);
|
return Optional.ofNullable(selected);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,7 @@ import ca.spottedleaf.moonrise.patches.collisions.CollisionUtil;
|
|||||||
import ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape;
|
import ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape;
|
||||||
import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
|
import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
|
||||||
import net.minecraft.client.renderer.block.LiquidBlockRenderer;
|
import net.minecraft.client.renderer.block.LiquidBlockRenderer;
|
||||||
import net.minecraft.core.BlockPos;
|
|
||||||
import net.minecraft.core.Direction;
|
import net.minecraft.core.Direction;
|
||||||
import net.minecraft.world.level.BlockGetter;
|
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
import net.minecraft.world.phys.shapes.ArrayVoxelShape;
|
import net.minecraft.world.phys.shapes.ArrayVoxelShape;
|
||||||
import net.minecraft.world.phys.shapes.BooleanOp;
|
import net.minecraft.world.phys.shapes.BooleanOp;
|
||||||
@@ -23,12 +21,7 @@ abstract class LiquidBlockRendererMixin {
|
|||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
private static boolean isFaceOccludedByState(final BlockGetter world, final Direction direction, final float height,
|
private static boolean isFaceOccludedByState(final Direction direction, final float height, final BlockState state) {
|
||||||
final BlockPos pos, final BlockState state) {
|
|
||||||
if (!state.canOcclude()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// check for created shape is empty
|
// check for created shape is empty
|
||||||
if (height < (float)CollisionUtil.COLLISION_EPSILON) {
|
if (height < (float)CollisionUtil.COLLISION_EPSILON) {
|
||||||
return false;
|
return false;
|
||||||
@@ -57,18 +50,19 @@ abstract class LiquidBlockRendererMixin {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
final VoxelShape stateShape = ((CollisionVoxelShape)state.getOcclusionShape(world, pos)).moonrise$getFaceShapeClamped(direction.getOpposite());
|
final VoxelShape occlusionShape = ((CollisionVoxelShape)state.getFaceOcclusionShape(direction.getOpposite()))
|
||||||
|
.moonrise$getFaceShapeClamped(direction.getOpposite());
|
||||||
|
|
||||||
if (stateShape.isEmpty()) {
|
if (occlusionShape.isEmpty()) {
|
||||||
// cannot occlude
|
// cannot occlude
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fast check for box
|
// fast check for box
|
||||||
if (heightShape == stateShape) {
|
if (heightShape == occlusionShape) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return !Shapes.joinIsNotEmpty(heightShape, stateShape, BooleanOp.ONLY_FIRST);
|
return !Shapes.joinIsNotEmpty(heightShape, occlusionShape, BooleanOp.ONLY_FIRST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.mixin.collisions;
|
|
||||||
|
|
||||||
import net.minecraft.world.entity.Attackable;
|
|
||||||
import net.minecraft.world.entity.Entity;
|
|
||||||
import net.minecraft.world.entity.EntitySelector;
|
|
||||||
import net.minecraft.world.entity.EntityType;
|
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
|
||||||
import net.minecraft.world.entity.player.Player;
|
|
||||||
import net.minecraft.world.level.GameRules;
|
|
||||||
import net.minecraft.world.level.Level;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.Overwrite;
|
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
@Mixin(LivingEntity.class)
|
|
||||||
abstract class LivingEntityMixin extends Entity implements Attackable {
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
protected abstract void doPush(Entity entity);
|
|
||||||
|
|
||||||
public LivingEntityMixin(EntityType<?> entityType, Level level) {
|
|
||||||
super(entityType, level);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @reason Optimise this method
|
|
||||||
* @author Spottedleaf
|
|
||||||
*/
|
|
||||||
@Overwrite
|
|
||||||
public void pushEntities() {
|
|
||||||
if (this.level().isClientSide()) {
|
|
||||||
final List<Player> players = this.level().getEntitiesOfClass(Player.class, this.getBoundingBox(), EntitySelector.pushableBy(this));
|
|
||||||
for (int i = 0, len = players.size(); i < len; ++i) {
|
|
||||||
this.doPush(players.get(i));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
final List<Entity> nearby = this.level().getEntities(this, this.getBoundingBox(), EntitySelector.pushableBy(this));
|
|
||||||
|
|
||||||
// only iterate ONCE
|
|
||||||
int nonPassengers = 0;
|
|
||||||
for (int i = 0, len = nearby.size(); i < len; ++i) {
|
|
||||||
final Entity entity = nearby.get(i);
|
|
||||||
nonPassengers += (entity.isPassenger() ? 1 : 0);
|
|
||||||
this.doPush(entity);
|
|
||||||
}
|
|
||||||
|
|
||||||
int maxCramming;
|
|
||||||
if (nonPassengers != 0 && (maxCramming = this.level().getGameRules().getInt(GameRules.RULE_MAX_ENTITY_CRAMMING)) > 0
|
|
||||||
&& nonPassengers > (maxCramming - 1) && this.random.nextInt(4) == 0) {
|
|
||||||
this.hurt(this.damageSources().cramming(), 6.0F);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -79,8 +79,7 @@ abstract class ParticleMixin {
|
|||||||
final List<VoxelShape> voxels = new ArrayList<>();
|
final List<VoxelShape> voxels = new ArrayList<>();
|
||||||
final boolean collided = CollisionUtil.getCollisionsForBlocksOrWorldBorder(
|
final boolean collided = CollisionUtil.getCollisionsForBlocksOrWorldBorder(
|
||||||
world, entity, collisionBox, voxels, boxes,
|
world, entity, collisionBox, voxels, boxes,
|
||||||
0,
|
0, null
|
||||||
null
|
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!collided) {
|
if (!collided) {
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
package ca.spottedleaf.moonrise.mixin.collisions;
|
package ca.spottedleaf.moonrise.mixin.collisions;
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.PlatformHooks;
|
|
||||||
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
import ca.spottedleaf.moonrise.common.util.CoordinateUtils;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_getblock.GetBlockChunk;
|
import ca.spottedleaf.moonrise.patches.getblock.GetBlockChunk;
|
||||||
import ca.spottedleaf.moonrise.patches.collisions.CollisionUtil;
|
import ca.spottedleaf.moonrise.patches.collisions.CollisionUtil;
|
||||||
import ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState;
|
import ca.spottedleaf.moonrise.patches.collisions.block.CollisionBlockState;
|
||||||
import ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache;
|
import ca.spottedleaf.moonrise.patches.collisions.ExplosionBlockCache;
|
||||||
@@ -10,20 +9,15 @@ import it.unimi.dsi.fastutil.doubles.DoubleArrayList;
|
|||||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.util.Mth;
|
import net.minecraft.util.Mth;
|
||||||
import net.minecraft.world.damagesource.DamageSource;
|
|
||||||
import net.minecraft.world.entity.Entity;
|
import net.minecraft.world.entity.Entity;
|
||||||
import net.minecraft.world.entity.LivingEntity;
|
|
||||||
import net.minecraft.world.entity.ai.attributes.Attributes;
|
|
||||||
import net.minecraft.world.entity.item.PrimedTnt;
|
|
||||||
import net.minecraft.world.entity.player.Player;
|
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
import net.minecraft.world.level.Explosion;
|
import net.minecraft.world.level.Explosion;
|
||||||
import net.minecraft.world.level.ExplosionDamageCalculator;
|
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.block.state.BlockState;
|
||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
import net.minecraft.world.level.gameevent.GameEvent;
|
|
||||||
import net.minecraft.world.level.material.FluidState;
|
import net.minecraft.world.level.material.FluidState;
|
||||||
import net.minecraft.world.phys.AABB;
|
import net.minecraft.world.phys.AABB;
|
||||||
import net.minecraft.world.phys.Vec3;
|
import net.minecraft.world.phys.Vec3;
|
||||||
@@ -33,33 +27,20 @@ import org.spongepowered.asm.mixin.Mixin;
|
|||||||
import org.spongepowered.asm.mixin.Overwrite;
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
@Mixin(Explosion.class)
|
@Mixin(ServerExplosion.class)
|
||||||
abstract class ExplosionMixin {
|
abstract class ServerExplosionMixin {
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
@Final
|
@Final
|
||||||
private Level level;
|
private ServerLevel level;
|
||||||
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
private Entity source;
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
private double x;
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
private double y;
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
private double z;
|
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
@Final
|
@Final
|
||||||
@@ -69,21 +50,13 @@ abstract class ExplosionMixin {
|
|||||||
@Final
|
@Final
|
||||||
private float radius;
|
private float radius;
|
||||||
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
private ObjectArrayList<BlockPos> toBlow;
|
|
||||||
|
|
||||||
@Shadow
|
|
||||||
@Final
|
|
||||||
private Map<Player, Vec3> hitPlayers;
|
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
@Final
|
@Final
|
||||||
private boolean fire;
|
private boolean fire;
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
@Final
|
@Final
|
||||||
private DamageSource damageSource;
|
private Vec3 center;
|
||||||
|
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
@@ -142,6 +115,12 @@ abstract class ExplosionMixin {
|
|||||||
@Unique
|
@Unique
|
||||||
private LevelChunk[] chunkCache = null;
|
private LevelChunk[] chunkCache = null;
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private ExplosionBlockCache[] directMappedBlockCache;
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private BlockPos.MutableBlockPos mutablePos;
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private ExplosionBlockCache getOrCacheExplosionBlock(final int x, final int y, final int z,
|
private ExplosionBlockCache getOrCacheExplosionBlock(final int x, final int y, final int z,
|
||||||
final long key, final boolean calculateResistance) {
|
final long key, final boolean calculateResistance) {
|
||||||
@@ -343,29 +322,45 @@ abstract class ExplosionMixin {
|
|||||||
return (float)missedRays / (float)totalRays;
|
return (float)missedRays / (float)totalRays;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Rewrite ray casting and seen fraction calculation for performance
|
* @reason Init cache fields
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Inject(
|
||||||
|
method = "explode",
|
||||||
|
at = @At(
|
||||||
|
value = "HEAD"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private void initCacheFields(final CallbackInfo ci) {
|
||||||
|
this.blockCache = new Long2ObjectOpenHashMap<>();
|
||||||
|
this.chunkPosCache = new long[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH];
|
||||||
|
Arrays.fill(this.chunkPosCache, ChunkPos.INVALID_CHUNK_POS);
|
||||||
|
this.chunkCache = new LevelChunk[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH];
|
||||||
|
this.directMappedBlockCache = new ExplosionBlockCache[BLOCK_EXPLOSION_CACHE_WIDTH * BLOCK_EXPLOSION_CACHE_WIDTH * BLOCK_EXPLOSION_CACHE_WIDTH];
|
||||||
|
this.mutablePos = new BlockPos.MutableBlockPos();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Rewrite ray casting for performance
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public void explode() {
|
public List<BlockPos> calculateExplodedPositions() {
|
||||||
this.level.gameEvent(this.source, GameEvent.EXPLODE, new Vec3(this.x, this.y, this.z));
|
final ObjectArrayList<BlockPos> ret = new ObjectArrayList<>();
|
||||||
|
|
||||||
this.blockCache = new Long2ObjectOpenHashMap<>();
|
final Vec3 center = this.center;
|
||||||
|
|
||||||
this.chunkPosCache = new long[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH];
|
final ExplosionBlockCache[] blockCache = this.directMappedBlockCache;
|
||||||
Arrays.fill(this.chunkPosCache, ChunkPos.INVALID_CHUNK_POS);
|
|
||||||
|
|
||||||
this.chunkCache = new LevelChunk[CHUNK_CACHE_WIDTH * CHUNK_CACHE_WIDTH];
|
|
||||||
|
|
||||||
final ExplosionBlockCache[] blockCache = new ExplosionBlockCache[BLOCK_EXPLOSION_CACHE_WIDTH * BLOCK_EXPLOSION_CACHE_WIDTH * BLOCK_EXPLOSION_CACHE_WIDTH];
|
|
||||||
|
|
||||||
// use initial cache value that is most likely to be used: the source position
|
// use initial cache value that is most likely to be used: the source position
|
||||||
final ExplosionBlockCache initialCache;
|
final ExplosionBlockCache initialCache;
|
||||||
{
|
{
|
||||||
final int blockX = Mth.floor(this.x);
|
final int blockX = Mth.floor(center.x);
|
||||||
final int blockY = Mth.floor(this.y);
|
final int blockY = Mth.floor(center.y);
|
||||||
final int blockZ = Mth.floor(this.z);
|
final int blockZ = Mth.floor(center.z);
|
||||||
|
|
||||||
final long key = BlockPos.asLong(blockX, blockY, blockZ);
|
final long key = BlockPos.asLong(blockX, blockY, blockZ);
|
||||||
|
|
||||||
@@ -381,9 +376,9 @@ abstract class ExplosionMixin {
|
|||||||
for (int ray = 0, len = CACHED_RAYS.length; ray < len;) {
|
for (int ray = 0, len = CACHED_RAYS.length; ray < len;) {
|
||||||
ExplosionBlockCache cachedBlock = initialCache;
|
ExplosionBlockCache cachedBlock = initialCache;
|
||||||
|
|
||||||
double currX = this.x;
|
double currX = center.x;
|
||||||
double currY = this.y;
|
double currY = center.y;
|
||||||
double currZ = this.z;
|
double currZ = center.z;
|
||||||
|
|
||||||
final double incX = CACHED_RAYS[ray];
|
final double incX = CACHED_RAYS[ray];
|
||||||
final double incY = CACHED_RAYS[ray + 1];
|
final double incY = CACHED_RAYS[ray + 1];
|
||||||
@@ -424,7 +419,7 @@ abstract class ExplosionMixin {
|
|||||||
cachedBlock.shouldExplode = shouldExplode ? Boolean.TRUE : Boolean.FALSE;
|
cachedBlock.shouldExplode = shouldExplode ? Boolean.TRUE : Boolean.FALSE;
|
||||||
if (shouldExplode) {
|
if (shouldExplode) {
|
||||||
if (this.fire || !cachedBlock.blockState.isAir()) {
|
if (this.fire || !cachedBlock.blockState.isAir()) {
|
||||||
this.toBlow.add(cachedBlock.immutablePos);
|
ret.add(cachedBlock.immutablePos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -436,83 +431,39 @@ abstract class ExplosionMixin {
|
|||||||
} while (power > 0.0f);
|
} while (power > 0.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
final double diameter = (double)this.radius * 2.0;
|
return ret;
|
||||||
final List<Entity> entities = this.level.getEntities(this.source,
|
}
|
||||||
new AABB(
|
|
||||||
(double)Mth.floor(this.x - (diameter + 1.0)),
|
|
||||||
(double)Mth.floor(this.y - (diameter + 1.0)),
|
|
||||||
(double)Mth.floor(this.z - (diameter + 1.0)),
|
|
||||||
|
|
||||||
(double)Mth.floor(this.x + (diameter + 1.0)),
|
/**
|
||||||
(double)Mth.floor(this.y + (diameter + 1.0)),
|
* @reason Use optimised getSeenPercent implementation
|
||||||
(double)Mth.floor(this.z + (diameter + 1.0))
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Redirect(
|
||||||
|
method = "hurtEntities",
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "Lnet/minecraft/world/level/ServerExplosion;getSeenPercent(Lnet/minecraft/world/phys/Vec3;Lnet/minecraft/world/entity/Entity;)F"
|
||||||
)
|
)
|
||||||
);
|
)
|
||||||
final Vec3 center = new Vec3(this.x, this.y, this.z);
|
private float useBetterSeenPercent(final Vec3 center, final Entity target) {
|
||||||
|
return this.getSeenFraction(center, target, this.directMappedBlockCache, this.mutablePos);
|
||||||
final BlockPos.MutableBlockPos blockPos = new BlockPos.MutableBlockPos();
|
|
||||||
|
|
||||||
final PlatformHooks platformHooks = PlatformHooks.get();
|
|
||||||
|
|
||||||
platformHooks.onExplosion(this.level, (Explosion)(Object)this, entities, diameter);
|
|
||||||
for (int i = 0, len = entities.size(); i < len; ++i) {
|
|
||||||
final Entity entity = entities.get(i);
|
|
||||||
if (entity.ignoreExplosion((Explosion)(Object)this)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
final double normalizedDistanceToCenter = Math.sqrt(entity.distanceToSqr(center)) / diameter;
|
|
||||||
if (normalizedDistanceToCenter > 1.0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
double distX = entity.getX() - this.x;
|
|
||||||
double distY = (entity instanceof PrimedTnt ? entity.getY() : entity.getEyeY()) - this.y;
|
|
||||||
double distZ = entity.getZ() - this.z;
|
|
||||||
final double distMag = Math.sqrt(distX * distX + distY * distY + distZ * distZ);
|
|
||||||
|
|
||||||
if (distMag == 0.0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
distX /= distMag;
|
|
||||||
distY /= distMag;
|
|
||||||
distZ /= distMag;
|
|
||||||
|
|
||||||
// route to new visible fraction calculation, using the existing block cache
|
|
||||||
final double seenFraction = (double)this.getSeenFraction(center, entity, blockCache, blockPos);
|
|
||||||
if (this.damageCalculator.shouldDamageEntity((Explosion)(Object)this, entity)) {
|
|
||||||
// inline getEntityDamageAmount so that we can avoid double calling getSeenPercent, which is the MOST
|
|
||||||
// expensive part of this loop!!!!
|
|
||||||
final double factor = (1.0 - normalizedDistanceToCenter) * seenFraction;
|
|
||||||
entity.hurt(this.damageSource, (float)((factor * factor + factor) / 2.0 * 7.0 * diameter + 1.0));
|
|
||||||
}
|
|
||||||
|
|
||||||
final double intensityFraction = (1.0 - normalizedDistanceToCenter) * seenFraction * (double)this.damageCalculator.getKnockbackMultiplier(entity);
|
|
||||||
|
|
||||||
|
|
||||||
final double knockbackFraction;
|
|
||||||
if (entity instanceof LivingEntity livingEntity) {
|
|
||||||
knockbackFraction = intensityFraction * (1.0 - livingEntity.getAttributeValue(Attributes.EXPLOSION_KNOCKBACK_RESISTANCE));
|
|
||||||
} else {
|
|
||||||
knockbackFraction = intensityFraction;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vec3 knockback = new Vec3(distX * knockbackFraction, distY * knockbackFraction, distZ * knockbackFraction);
|
|
||||||
knockback = platformHooks.modifyExplosionKnockback(this.level, (Explosion)(Object)this, entity, knockback);
|
|
||||||
entity.setDeltaMovement(entity.getDeltaMovement().add(knockback));
|
|
||||||
|
|
||||||
if (entity instanceof Player player) {
|
|
||||||
if (!player.isSpectator() && (!player.isCreative() || !player.getAbilities().flying)) {
|
|
||||||
this.hitPlayers.put(player, knockback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
entity.onExplosionHit(this.source);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Destroy cache fields
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Inject(
|
||||||
|
method = "explode",
|
||||||
|
at = @At(
|
||||||
|
value = "RETURN"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private void destroyCacheFields(final CallbackInfo ci) {
|
||||||
this.blockCache = null;
|
this.blockCache = null;
|
||||||
this.chunkPosCache = null;
|
this.chunkPosCache = null;
|
||||||
this.chunkCache = null;
|
this.chunkCache = null;
|
||||||
|
this.directMappedBlockCache = null;
|
||||||
|
this.mutablePos = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -22,9 +22,11 @@ import org.spongepowered.asm.mixin.Overwrite;
|
|||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
@Mixin(Shapes.class)
|
@Mixin(Shapes.class)
|
||||||
abstract class ShapesMixin {
|
abstract class ShapesMixin {
|
||||||
@@ -168,13 +170,13 @@ abstract class ShapesMixin {
|
|||||||
final VoxelShape first = tmp[i];
|
final VoxelShape first = tmp[i];
|
||||||
final VoxelShape second = tmp[next];
|
final VoxelShape second = tmp[next];
|
||||||
|
|
||||||
tmp[newSize++] = Shapes.or(first, second);
|
tmp[newSize++] = Shapes.joinUnoptimized(first, second, BooleanOp.OR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
size = newSize;
|
size = newSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
return tmp[0];
|
return tmp[0].optimize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
@@ -219,11 +221,24 @@ abstract class ShapesMixin {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Use an inject instead of overwrite to avoid mixin conflicts - obviously this will still disregard any changes made by other
|
||||||
|
* mixins, but at least it won't conflict immediately. This is useful because some library mods mixin here when only the content
|
||||||
|
* mod actually needs the change.
|
||||||
|
*
|
||||||
* @reason Route to faster logic
|
* @reason Route to faster logic
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Inject(
|
||||||
public static VoxelShape joinUnoptimized(final VoxelShape first, final VoxelShape second, final BooleanOp mergeFunction) {
|
method = "joinUnoptimized",
|
||||||
|
at = @At("HEAD"),
|
||||||
|
cancellable = true
|
||||||
|
)
|
||||||
|
private static void injectJoinUnoptimized(final VoxelShape first, final VoxelShape second, final BooleanOp mergeFunction, final CallbackInfoReturnable<VoxelShape> cir) {
|
||||||
|
cir.setReturnValue(joinUnoptimized(first, second, mergeFunction));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private static VoxelShape joinUnoptimized(final VoxelShape first, final VoxelShape second, final BooleanOp mergeFunction) {
|
||||||
final VoxelShape ret = CollisionUtil.joinUnoptimized(first, second, mergeFunction);
|
final VoxelShape ret = CollisionUtil.joinUnoptimized(first, second, mergeFunction);
|
||||||
if (DEBUG_SHAPE_MERGING) {
|
if (DEBUG_SHAPE_MERGING) {
|
||||||
final VoxelShape vanilla = joinUnoptimizedVanilla(first, second, mergeFunction);
|
final VoxelShape vanilla = joinUnoptimizedVanilla(first, second, mergeFunction);
|
||||||
@@ -239,9 +254,19 @@ abstract class ShapesMixin {
|
|||||||
/**
|
/**
|
||||||
* @reason Route to faster logic
|
* @reason Route to faster logic
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
|
* @see #injectJoinUnoptimized(VoxelShape, VoxelShape, BooleanOp, CallbackInfoReturnable)
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Inject(
|
||||||
public static boolean joinIsNotEmpty(final VoxelShape first, final VoxelShape second, final BooleanOp mergeFunction) {
|
method = "joinIsNotEmpty(Lnet/minecraft/world/phys/shapes/VoxelShape;Lnet/minecraft/world/phys/shapes/VoxelShape;Lnet/minecraft/world/phys/shapes/BooleanOp;)Z",
|
||||||
|
at = @At("HEAD"),
|
||||||
|
cancellable = true
|
||||||
|
)
|
||||||
|
private static void injectJoinIsNotEmpty(final VoxelShape first, final VoxelShape second, final BooleanOp mergeFunction, final CallbackInfoReturnable<Boolean> cir) {
|
||||||
|
cir.setReturnValue(joinIsNotEmpty(first, second, mergeFunction));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private static boolean joinIsNotEmpty(final VoxelShape first, final VoxelShape second, final BooleanOp mergeFunction) {
|
||||||
final boolean ret = CollisionUtil.isJoinNonEmpty(first, second, mergeFunction);
|
final boolean ret = CollisionUtil.isJoinNonEmpty(first, second, mergeFunction);
|
||||||
if (DEBUG_SHAPE_MERGING) {
|
if (DEBUG_SHAPE_MERGING) {
|
||||||
if (ret != !joinUnoptimizedVanilla(first, second, mergeFunction).isEmpty()) {
|
if (ret != !joinUnoptimizedVanilla(first, second, mergeFunction).isEmpty()) {
|
||||||
@@ -253,15 +278,6 @@ abstract class ShapesMixin {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @reason Route to use cache
|
|
||||||
* @author Spottedleaf
|
|
||||||
*/
|
|
||||||
@Overwrite
|
|
||||||
public static VoxelShape getFaceShape(final VoxelShape shape, final Direction direction) {
|
|
||||||
return ((CollisionVoxelShape)shape).moonrise$getFaceShapeClamped(direction);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private static boolean mergedMayOccludeBlock(final VoxelShape shape1, final VoxelShape shape2) {
|
private static boolean mergedMayOccludeBlock(final VoxelShape shape1, final VoxelShape shape2) {
|
||||||
// if the combined bounds of the two shapes cannot occlude, then neither can the merged
|
// if the combined bounds of the two shapes cannot occlude, then neither can the merged
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
package ca.spottedleaf.moonrise.mixin.collisions;
|
package ca.spottedleaf.moonrise.mixin.collisions;
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape;
|
import ca.spottedleaf.moonrise.patches.collisions.shape.CollisionVoxelShape;
|
||||||
import net.minecraft.core.Direction;
|
|
||||||
import net.minecraft.world.phys.shapes.SliceShape;
|
import net.minecraft.world.phys.shapes.SliceShape;
|
||||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
@@ -22,7 +20,7 @@ abstract class SliceShapeMixin {
|
|||||||
value = "RETURN"
|
value = "RETURN"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
private void initState(final VoxelShape parent, final Direction.Axis forAxis, final int forIndex, final CallbackInfo ci) {
|
private void initState(final CallbackInfo ci) {
|
||||||
((CollisionVoxelShape)this).moonrise$initCache();
|
((CollisionVoxelShape)this).moonrise$initCache();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -687,13 +687,13 @@ abstract class VoxelShapeMixin implements CollisionVoxelShape {
|
|||||||
final AABB singleAABB = this.singleAABBRepresentation;
|
final AABB singleAABB = this.singleAABBRepresentation;
|
||||||
if (singleAABB != null) {
|
if (singleAABB != null) {
|
||||||
if (singleAABB.contains(fromBehindOffsetX, fromBehindOffsetY, fromBehindOffsetZ)) {
|
if (singleAABB.contains(fromBehindOffsetX, fromBehindOffsetY, fromBehindOffsetZ)) {
|
||||||
return new BlockHitResult(fromBehind, Direction.getNearest(directionOpposite.x, directionOpposite.y, directionOpposite.z).getOpposite(), offset, true);
|
return new BlockHitResult(fromBehind, Direction.getApproximateNearest(directionOpposite.x, directionOpposite.y, directionOpposite.z).getOpposite(), offset, true);
|
||||||
}
|
}
|
||||||
return clip(singleAABB, from, to, offset);
|
return clip(singleAABB, from, to, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CollisionUtil.strictlyContains((VoxelShape)(Object)this, fromBehindOffsetX, fromBehindOffsetY, fromBehindOffsetZ)) {
|
if (CollisionUtil.strictlyContains((VoxelShape)(Object)this, fromBehindOffsetX, fromBehindOffsetY, fromBehindOffsetZ)) {
|
||||||
return new BlockHitResult(fromBehind, Direction.getNearest(directionOpposite.x, directionOpposite.y, directionOpposite.z).getOpposite(), offset, true);
|
return new BlockHitResult(fromBehind, Direction.getApproximateNearest(directionOpposite.x, directionOpposite.y, directionOpposite.z).getOpposite(), offset, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return AABB.clip(((VoxelShape)(Object)this).toAabbs(), from, to, offset);
|
return AABB.clip(((VoxelShape)(Object)this).toAabbs(), from, to, offset);
|
||||||
|
|||||||
@@ -67,7 +67,6 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkHolder.PlayerP
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
private boolean newTrackerTick(final Iterator<?> iterator) {
|
private boolean newTrackerTick(final Iterator<?> iterator) {
|
||||||
final NearbyPlayers nearbyPlayers = ((ChunkSystemServerLevel)this.level).moonrise$getNearbyPlayers();
|
|
||||||
final ServerEntityLookup entityLookup = (ServerEntityLookup)((ChunkSystemServerLevel)this.level).moonrise$getEntityLookup();;
|
final ServerEntityLookup entityLookup = (ServerEntityLookup)((ChunkSystemServerLevel)this.level).moonrise$getEntityLookup();;
|
||||||
|
|
||||||
final ReferenceList<Entity> trackerEntities = entityLookup.trackerEntities;
|
final ReferenceList<Entity> trackerEntities = entityLookup.trackerEntities;
|
||||||
@@ -78,7 +77,7 @@ abstract class ChunkMapMixin extends ChunkStorage implements ChunkHolder.PlayerP
|
|||||||
if (tracker == null) {
|
if (tracker == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
((EntityTrackerTrackedEntity)tracker).moonrise$tick(nearbyPlayers.getChunk(entity.chunkPosition()));
|
((EntityTrackerTrackedEntity)tracker).moonrise$tick(((ChunkSystemEntity)entity).moonrise$getChunkData().nearbyPlayers);
|
||||||
if (((EntityTrackerTrackedEntity)tracker).moonrise$hasPlayers()
|
if (((EntityTrackerTrackedEntity)tracker).moonrise$hasPlayers()
|
||||||
|| ((ChunkSystemEntity)entity).moonrise$getChunkStatus().isOrAfter(FullChunkStatus.ENTITY_TICKING)) {
|
|| ((ChunkSystemEntity)entity).moonrise$getChunkStatus().isOrAfter(FullChunkStatus.ENTITY_TICKING)) {
|
||||||
tracker.serverEntity.sendChanges();
|
tracker.serverEntity.sendChanges();
|
||||||
|
|||||||
@@ -1,19 +1,20 @@
|
|||||||
package ca.spottedleaf.moonrise.mixin.entity_tracker;
|
package ca.spottedleaf.moonrise.mixin.entity_tracker;
|
||||||
|
|
||||||
|
import ca.spottedleaf.moonrise.common.PlatformHooks;
|
||||||
import ca.spottedleaf.moonrise.common.list.ReferenceList;
|
import ca.spottedleaf.moonrise.common.list.ReferenceList;
|
||||||
import ca.spottedleaf.moonrise.common.misc.NearbyPlayers;
|
import ca.spottedleaf.moonrise.common.misc.NearbyPlayers;
|
||||||
import ca.spottedleaf.moonrise.common.util.TickThread;
|
import ca.spottedleaf.moonrise.common.util.TickThread;
|
||||||
import ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerTrackedEntity;
|
import ca.spottedleaf.moonrise.patches.entity_tracker.EntityTrackerTrackedEntity;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
|
import it.unimi.dsi.fastutil.objects.ReferenceOpenHashSet;
|
||||||
import net.minecraft.server.level.ChunkMap;
|
import net.minecraft.server.level.ChunkMap;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.server.network.ServerPlayerConnection;
|
import net.minecraft.server.network.ServerPlayerConnection;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
import net.minecraft.world.entity.Entity;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.*;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
@Mixin(ChunkMap.TrackedEntity.class)
|
@Mixin(ChunkMap.TrackedEntity.class)
|
||||||
@@ -22,26 +23,22 @@ abstract class TrackedEntityMixin implements EntityTrackerTrackedEntity {
|
|||||||
@Final
|
@Final
|
||||||
private Set<ServerPlayerConnection> seenBy;
|
private Set<ServerPlayerConnection> seenBy;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
private int range;
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
public abstract void updatePlayer(ServerPlayer serverPlayer);
|
public abstract void updatePlayer(ServerPlayer serverPlayer);
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
public abstract void removePlayer(ServerPlayer serverPlayer);
|
public abstract void removePlayer(ServerPlayer serverPlayer);
|
||||||
|
|
||||||
/**
|
@Shadow
|
||||||
* @reason ReferenceOpenHashSet is a better choice than a wrapped IdentityHashMap
|
protected abstract int scaledRange(final int i);
|
||||||
* @author Spottedleaf
|
|
||||||
*/
|
@Shadow
|
||||||
@Redirect(
|
@Final
|
||||||
method = "<init>",
|
Entity entity;
|
||||||
at = @At(
|
|
||||||
value = "INVOKE",
|
|
||||||
target = "Lcom/google/common/collect/Sets;newIdentityHashSet()Ljava/util/Set;"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
private <E> Set<E> useBetterIdentitySet() {
|
|
||||||
return new ReferenceOpenHashSet<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private long lastChunkUpdate = -1L;
|
private long lastChunkUpdate = -1L;
|
||||||
@@ -126,4 +123,43 @@ abstract class TrackedEntityMixin implements EntityTrackerTrackedEntity {
|
|||||||
public final boolean moonrise$hasPlayers() {
|
public final boolean moonrise$hasPlayers() {
|
||||||
return !this.seenBy.isEmpty();
|
return !this.seenBy.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason ReferenceOpenHashSet is a better choice than a wrapped IdentityHashMap
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Redirect(
|
||||||
|
method = "<init>",
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "Lcom/google/common/collect/Sets;newIdentityHashSet()Ljava/util/Set;"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private <E> Set<E> useBetterIdentitySet() {
|
||||||
|
return new ReferenceOpenHashSet<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Optimise impl to not retrieve indirect passengers unless needed
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Overwrite
|
||||||
|
public int getEffectiveRange() {
|
||||||
|
final Entity entity = this.entity;
|
||||||
|
int range = PlatformHooks.get().modifyEntityTrackingRange(entity, this.range);
|
||||||
|
|
||||||
|
if (entity.getPassengers() == ImmutableList.<Entity>of()) {
|
||||||
|
return this.scaledRange(range);
|
||||||
|
}
|
||||||
|
|
||||||
|
// note: we change to List
|
||||||
|
final List<Entity> passengers = (List<Entity>)entity.getIndirectPassengers();
|
||||||
|
for (int i = 0, len = passengers.size(); i < len; ++i) {
|
||||||
|
final Entity passenger = passengers.get(i);
|
||||||
|
// note: max should be branchless
|
||||||
|
range = Math.max(range, PlatformHooks.get().modifyEntityTrackingRange(passenger, passenger.getType().clientTrackingRange() << 4));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.scaledRange(range);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ abstract class PalettedContainerMixin<T> implements PaletteResize<T>, PalettedCo
|
|||||||
private void updateData(final PalettedContainer.Data<T> data) {
|
private void updateData(final PalettedContainer.Data<T> data) {
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
((FastPaletteData<T>)(Object)data).moonrise$setPalette(
|
((FastPaletteData<T>)(Object)data).moonrise$setPalette(
|
||||||
((FastPalette<T>)data.palette).moonrise$getRawPalette((FastPaletteData<T>)(Object)data)
|
((FastPalette<T>)data.palette()).moonrise$getRawPalette((FastPaletteData<T>)(Object)data)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -35,40 +35,18 @@ abstract class PalettedContainerMixin<T> implements PaletteResize<T>, PalettedCo
|
|||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Inject(
|
@Inject(
|
||||||
method = "<init>(Lnet/minecraft/core/IdMap;Ljava/lang/Object;Lnet/minecraft/world/level/chunk/PalettedContainer$Strategy;)V",
|
// cannot use `<init>*` due to https://github.com/FabricMC/tiny-remapper/issues/137
|
||||||
|
method = {
|
||||||
|
"<init>(Lnet/minecraft/core/IdMap;Lnet/minecraft/world/level/chunk/PalettedContainer$Strategy;Lnet/minecraft/world/level/chunk/PalettedContainer$Configuration;Lnet/minecraft/util/BitStorage;Ljava/util/List;)V",
|
||||||
|
"<init>(Lnet/minecraft/core/IdMap;Lnet/minecraft/world/level/chunk/PalettedContainer$Strategy;Lnet/minecraft/world/level/chunk/PalettedContainer$Data;)V",
|
||||||
|
"<init>(Lnet/minecraft/core/IdMap;Ljava/lang/Object;Lnet/minecraft/world/level/chunk/PalettedContainer$Strategy;)V"
|
||||||
|
},
|
||||||
at = @At(
|
at = @At(
|
||||||
value = "RETURN"
|
value = "RETURN"
|
||||||
|
),
|
||||||
|
require = 3 // Require matching all 3 constructors
|
||||||
)
|
)
|
||||||
)
|
private void constructorHook(final CallbackInfo ci) {
|
||||||
private void constructorHook1(final CallbackInfo ci) {
|
|
||||||
this.updateData(this.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @reason Hook to update raw palette data on object construction
|
|
||||||
* @author Spottedleaf
|
|
||||||
*/
|
|
||||||
@Inject(
|
|
||||||
method = "<init>(Lnet/minecraft/core/IdMap;Lnet/minecraft/world/level/chunk/PalettedContainer$Strategy;Lnet/minecraft/world/level/chunk/PalettedContainer$Configuration;Lnet/minecraft/util/BitStorage;Ljava/util/List;)V",
|
|
||||||
at = @At(
|
|
||||||
value = "RETURN"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
private void constructorHook2(final CallbackInfo ci) {
|
|
||||||
this.updateData(this.data);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @reason Hook to update raw palette data on object construction
|
|
||||||
* @author Spottedleaf
|
|
||||||
*/
|
|
||||||
@Inject(
|
|
||||||
method = "<init>(Lnet/minecraft/core/IdMap;Lnet/minecraft/world/level/chunk/PalettedContainer$Strategy;Lnet/minecraft/world/level/chunk/PalettedContainer$Data;)V",
|
|
||||||
at = @At(
|
|
||||||
value = "RETURN"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
private void constructorHook3(final CallbackInfo ci) {
|
|
||||||
this.updateData(this.data);
|
this.updateData(this.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +80,7 @@ abstract class PalettedContainerMixin<T> implements PaletteResize<T>, PalettedCo
|
|||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private T readPaletteSlow(final PalettedContainer.Data<T> data, final int paletteIdx) {
|
private T readPaletteSlow(final PalettedContainer.Data<T> data, final int paletteIdx) {
|
||||||
return data.palette.valueFor(paletteIdx);
|
return data.palette().valueFor(paletteIdx);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
@@ -125,9 +103,9 @@ abstract class PalettedContainerMixin<T> implements PaletteResize<T>, PalettedCo
|
|||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public T getAndSet(final int index, final T value) {
|
public T getAndSet(final int index, final T value) {
|
||||||
final int paletteIdx = this.data.palette.idFor(value);
|
final int paletteIdx = this.data.palette().idFor(value);
|
||||||
final PalettedContainer.Data<T> data = this.data;
|
final PalettedContainer.Data<T> data = this.data;
|
||||||
final int prev = data.storage.getAndSet(index, paletteIdx);
|
final int prev = data.storage().getAndSet(index, paletteIdx);
|
||||||
return this.readPalette(data, prev);
|
return this.readPalette(data, prev);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,6 +116,6 @@ abstract class PalettedContainerMixin<T> implements PaletteResize<T>, PalettedCo
|
|||||||
@Overwrite
|
@Overwrite
|
||||||
public T get(final int index) {
|
public T get(final int index) {
|
||||||
final PalettedContainer.Data<T> data = this.data;
|
final PalettedContainer.Data<T> data = this.data;
|
||||||
return this.readPalette(data, data.storage.get(index));
|
return this.readPalette(data, data.storage().get(index));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,14 +114,14 @@ abstract class FlowingFluidMixin extends Fluid {
|
|||||||
private static final int COLLISION_OCCLUSION_CACHE_SIZE = 2048;
|
private static final int COLLISION_OCCLUSION_CACHE_SIZE = 2048;
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private static final FluidOcclusionCacheKey[] COLLISION_OCCLUSION_CACHE = new FluidOcclusionCacheKey[COLLISION_OCCLUSION_CACHE_SIZE];
|
private static final ThreadLocal<FluidOcclusionCacheKey[]> COLLISION_OCCLUSION_CACHE = ThreadLocal.withInitial(() -> new FluidOcclusionCacheKey[COLLISION_OCCLUSION_CACHE_SIZE]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Try to avoid going to the cache for simple cases; additionally use better caching strategy
|
* @reason Try to avoid going to the cache for simple cases; additionally use better caching strategy
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
private boolean canPassThroughWall(final Direction direction, final BlockGetter level,
|
public static boolean canPassThroughWall(final Direction direction, final BlockGetter level,
|
||||||
final BlockPos fromPos, final BlockState fromState,
|
final BlockPos fromPos, final BlockState fromState,
|
||||||
final BlockPos toPos, final BlockState toState) {
|
final BlockPos toPos, final BlockState toState) {
|
||||||
if (((CollisionBlockState)fromState).moonrise$emptyCollisionShape() & ((CollisionBlockState)toState).moonrise$emptyCollisionShape()) {
|
if (((CollisionBlockState)fromState).moonrise$emptyCollisionShape() & ((CollisionBlockState)toState).moonrise$emptyCollisionShape()) {
|
||||||
@@ -135,7 +135,7 @@ abstract class FlowingFluidMixin extends Fluid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final FluidOcclusionCacheKey[] cache = ((CollisionBlockState)fromState).moonrise$hasCache() & ((CollisionBlockState)toState).moonrise$hasCache() ?
|
final FluidOcclusionCacheKey[] cache = ((CollisionBlockState)fromState).moonrise$hasCache() & ((CollisionBlockState)toState).moonrise$hasCache() ?
|
||||||
COLLISION_OCCLUSION_CACHE : null;
|
COLLISION_OCCLUSION_CACHE.get() : null;
|
||||||
|
|
||||||
final int keyIndex
|
final int keyIndex
|
||||||
= (((CollisionBlockState)fromState).moonrise$uniqueId1() ^ ((CollisionBlockState)toState).moonrise$uniqueId2() ^ ((CollisionDirection)(Object)direction).moonrise$uniqueId())
|
= (((CollisionBlockState)fromState).moonrise$uniqueId1() ^ ((CollisionBlockState)toState).moonrise$uniqueId2() ^ ((CollisionDirection)(Object)direction).moonrise$uniqueId())
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package ca.spottedleaf.moonrise.mixin.fluid;
|
package ca.spottedleaf.moonrise.mixin.fluid;
|
||||||
|
|
||||||
|
import ca.spottedleaf.moonrise.patches.fluid.FluidFluidState;
|
||||||
import com.mojang.serialization.MapCodec;
|
import com.mojang.serialization.MapCodec;
|
||||||
import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap;
|
import it.unimi.dsi.fastutil.objects.Reference2ObjectArrayMap;
|
||||||
import net.minecraft.world.level.block.state.BlockState;
|
import net.minecraft.world.level.block.state.BlockState;
|
||||||
@@ -11,12 +12,9 @@ import org.spongepowered.asm.mixin.Mixin;
|
|||||||
import org.spongepowered.asm.mixin.Overwrite;
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|
||||||
|
|
||||||
@Mixin(FluidState.class)
|
@Mixin(FluidState.class)
|
||||||
abstract class FluidStateMixin extends StateHolder<Fluid, FluidState> {
|
abstract class FluidStateMixin extends StateHolder<Fluid, FluidState> implements FluidFluidState {
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
public abstract Fluid getType();
|
public abstract Fluid getType();
|
||||||
@@ -43,23 +41,9 @@ abstract class FluidStateMixin extends StateHolder<Fluid, FluidState> {
|
|||||||
@Unique
|
@Unique
|
||||||
private BlockState legacyBlock;
|
private BlockState legacyBlock;
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* @reason Initialise caches
|
public final void moonrise$initCaches() {
|
||||||
* @author Spottedleaf
|
|
||||||
*/
|
|
||||||
@Inject(
|
|
||||||
method = "<init>",
|
|
||||||
at = @At(
|
|
||||||
value = "RETURN"
|
|
||||||
)
|
|
||||||
)
|
|
||||||
private void init(final CallbackInfo ci) {
|
|
||||||
try {
|
|
||||||
this.amount = this.getType().getAmount((FluidState)(Object)this);
|
this.amount = this.getType().getAmount((FluidState)(Object)this);
|
||||||
} catch (final Exception ex) {
|
|
||||||
// https://github.com/JDKDigital/productivetrees/issues/16
|
|
||||||
new RuntimeException("Failed to retrieve fluid amount for " + this, ex).printStackTrace();
|
|
||||||
}
|
|
||||||
this.isEmpty = this.getType().isEmpty();
|
this.isEmpty = this.getType().isEmpty();
|
||||||
this.isSource = this.getType().isSource((FluidState)(Object)this);
|
this.isSource = this.getType().isSource((FluidState)(Object)this);
|
||||||
this.ownHeight = this.getType().getOwnHeight((FluidState)(Object)this);
|
this.ownHeight = this.getType().getOwnHeight((FluidState)(Object)this);
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package ca.spottedleaf.moonrise.mixin.fluid;
|
||||||
|
|
||||||
|
import ca.spottedleaf.moonrise.patches.fluid.FluidFluidState;
|
||||||
|
import net.minecraft.core.Holder;
|
||||||
|
import net.minecraft.core.MappedRegistry;
|
||||||
|
import net.minecraft.core.RegistrationInfo;
|
||||||
|
import net.minecraft.core.registries.Registries;
|
||||||
|
import net.minecraft.resources.ResourceKey;
|
||||||
|
import net.minecraft.world.level.material.Fluid;
|
||||||
|
import net.minecraft.world.level.material.FluidState;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
|
||||||
|
@Mixin(MappedRegistry.class)
|
||||||
|
abstract class MappedRegistryMixin<T> {
|
||||||
|
/**
|
||||||
|
* @reason Initialise caches
|
||||||
|
* @author jpenilla
|
||||||
|
*/
|
||||||
|
@Inject(
|
||||||
|
method = "register(Lnet/minecraft/resources/ResourceKey;Ljava/lang/Object;Lnet/minecraft/core/RegistrationInfo;)Lnet/minecraft/core/Holder$Reference;",
|
||||||
|
at = @At("RETURN")
|
||||||
|
)
|
||||||
|
private void injectFluidRegister(
|
||||||
|
final ResourceKey<?> resourceKey,
|
||||||
|
final T object,
|
||||||
|
final RegistrationInfo registrationInfo,
|
||||||
|
final CallbackInfoReturnable<Holder.Reference<T>> cir
|
||||||
|
) {
|
||||||
|
if (resourceKey.registryKey() == (Object)Registries.FLUID) {
|
||||||
|
for (final FluidState possibleState : ((Fluid)object).getStateDefinition().getPossibleStates()) {
|
||||||
|
((FluidFluidState)(Object)possibleState).moonrise$initCaches();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package ca.spottedleaf.moonrise.mixin.chunk_getblock;
|
package ca.spottedleaf.moonrise.mixin.getblock;
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.util.WorldUtil;
|
import ca.spottedleaf.moonrise.common.util.WorldUtil;
|
||||||
import net.minecraft.core.Holder;
|
import net.minecraft.core.Holder;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package ca.spottedleaf.moonrise.mixin.chunk_getblock;
|
package ca.spottedleaf.moonrise.mixin.getblock;
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.util.WorldUtil;
|
import ca.spottedleaf.moonrise.common.util.WorldUtil;
|
||||||
import ca.spottedleaf.moonrise.patches.chunk_getblock.GetBlockChunk;
|
import ca.spottedleaf.moonrise.patches.getblock.GetBlockChunk;
|
||||||
import net.minecraft.core.BlockPos;
|
import net.minecraft.core.BlockPos;
|
||||||
import net.minecraft.core.Registry;
|
import net.minecraft.core.Registry;
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
@@ -81,6 +81,7 @@ abstract class LevelChunkMixin extends ChunkAccess implements GetBlockChunk {
|
|||||||
* @reason Route to optimized getBlock
|
* @reason Route to optimized getBlock
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public BlockState getBlockState(final BlockPos pos) {
|
public BlockState getBlockState(final BlockPos pos) {
|
||||||
return this.moonrise$getBlock(pos.getX(), pos.getY(), pos.getZ());
|
return this.moonrise$getBlock(pos.getX(), pos.getY(), pos.getZ());
|
||||||
@@ -101,7 +102,7 @@ abstract class LevelChunkMixin extends ChunkAccess implements GetBlockChunk {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public BlockState moonrise$getBlock(final int x, final int y, final int z) {
|
public final BlockState moonrise$getBlock(final int x, final int y, final int z) {
|
||||||
if (this.debug) {
|
if (this.debug) {
|
||||||
return this.getBlockDebug(x, y, z);
|
return this.getBlockDebug(x, y, z);
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,117 @@
|
|||||||
|
package ca.spottedleaf.moonrise.mixin.getblock;
|
||||||
|
|
||||||
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.core.Holder;
|
||||||
|
import net.minecraft.world.level.Level;
|
||||||
|
import net.minecraft.world.level.LevelAccessor;
|
||||||
|
import net.minecraft.world.level.dimension.DimensionType;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
// Higher priority to apply after Lithium mixin.world.inline_height.WorldMixin
|
||||||
|
@Mixin(value = Level.class, priority = 1100)
|
||||||
|
abstract class LevelMixin implements LevelAccessor, AutoCloseable {
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private int minY;
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private int height;
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private int maxY;
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private int minSectionY;
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private int maxSectionY;
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private int sectionsCount;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Init min/max section
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Inject(
|
||||||
|
method = "<init>",
|
||||||
|
at = @At(
|
||||||
|
value = "CTOR_HEAD"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private void init(final CallbackInfo ci,
|
||||||
|
@Local(ordinal = 0, argsOnly = true) final Holder<DimensionType> dimensionTypeHolder) {
|
||||||
|
final DimensionType dimType = dimensionTypeHolder.value();
|
||||||
|
this.minY = dimType.minY();
|
||||||
|
this.height = dimType.height();
|
||||||
|
this.maxY = this.minY + this.height - 1;
|
||||||
|
this.minSectionY = this.minY >> 4;
|
||||||
|
this.maxSectionY = this.maxY >> 4;
|
||||||
|
this.sectionsCount = this.maxSectionY - this.minSectionY + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMinY() {
|
||||||
|
return this.minY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getHeight() {
|
||||||
|
return this.height;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxY() {
|
||||||
|
return this.maxY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSectionsCount() {
|
||||||
|
return this.sectionsCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMinSectionY() {
|
||||||
|
return this.minSectionY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getMaxSectionY() {
|
||||||
|
return this.maxSectionY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isInsideBuildHeight(final int blockY) {
|
||||||
|
return blockY >= this.minY && blockY <= this.maxY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOutsideBuildHeight(final BlockPos pos) {
|
||||||
|
return this.isOutsideBuildHeight(pos.getY());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isOutsideBuildHeight(final int blockY) {
|
||||||
|
return blockY < this.minY || blockY > this.maxY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSectionIndex(final int blockY) {
|
||||||
|
return (blockY >> 4) - this.minSectionY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSectionIndexFromSectionY(final int sectionY) {
|
||||||
|
return sectionY - this.minSectionY;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getSectionYFromSectionIndex(final int sectionIdx) {
|
||||||
|
return sectionIdx + this.minSectionY;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package ca.spottedleaf.moonrise.mixin.mob_spawning;
|
||||||
|
|
||||||
|
import ca.spottedleaf.moonrise.patches.mob_spawning.MobSpawningEntityType;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
|
||||||
|
@Mixin(EntityType.class)
|
||||||
|
abstract class EntityTypeMixin implements MobSpawningEntityType {
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private boolean hasBiomeCost = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final boolean moonrise$hasAnyBiomeCost() {
|
||||||
|
return this.hasBiomeCost;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void moonrise$setHasBiomeCost() {
|
||||||
|
this.hasBiomeCost = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
package ca.spottedleaf.moonrise.mixin.mob_spawning;
|
||||||
|
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2IntMap;
|
||||||
|
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
|
||||||
|
import net.minecraft.world.entity.MobCategory;
|
||||||
|
import net.minecraft.world.level.LocalMobCapCalculator;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Mutable;
|
||||||
|
import org.spongepowered.asm.mixin.Overwrite;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
|
@Mixin(LocalMobCapCalculator.MobCounts.class)
|
||||||
|
abstract class LocalMobCapCalculator$MobCountsMixin {
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Mutable
|
||||||
|
@Final
|
||||||
|
private Object2IntMap<MobCategory> counts;
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private static final MobCategory[] CATEGORIES = MobCategory.values();
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private static final Object2IntOpenHashMap<?> DUMMY = new Object2IntOpenHashMap<>();
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private final int[] newCounts = new int[CATEGORIES.length];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Ensure accesses of old field blow up
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Inject(
|
||||||
|
method = "<init>",
|
||||||
|
at = @At(
|
||||||
|
value = "RETURN"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private void destroyField(final CallbackInfo ci) {
|
||||||
|
this.counts = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Avoid allocating the map, we null it later
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Redirect(
|
||||||
|
method = "<init>",
|
||||||
|
at = @At(
|
||||||
|
value = "NEW",
|
||||||
|
target = "(I)Lit/unimi/dsi/fastutil/objects/Object2IntOpenHashMap;"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private <T> Object2IntOpenHashMap<T> avoidAllocation(final int expected) {
|
||||||
|
return (Object2IntOpenHashMap<T>)DUMMY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Do not allocate MobCategory[]
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Redirect(
|
||||||
|
method = "<init>",
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "Lnet/minecraft/world/entity/MobCategory;values()[Lnet/minecraft/world/entity/MobCategory;"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private MobCategory[] useCachedArray() {
|
||||||
|
return CATEGORIES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Use simple array instead of compute call
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Overwrite
|
||||||
|
public void add(final MobCategory category) {
|
||||||
|
++this.newCounts[category.ordinal()];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Use simple array instead of map get call
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Overwrite
|
||||||
|
public boolean canSpawn(final MobCategory category) {
|
||||||
|
return this.newCounts[category.ordinal()] < category.getMaxInstancesPerChunk();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package ca.spottedleaf.moonrise.mixin.mob_spawning;
|
||||||
|
|
||||||
|
import ca.spottedleaf.moonrise.patches.mob_spawning.MobSpawningEntityType;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.level.biome.MobSpawnSettings;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Mixin(MobSpawnSettings.class)
|
||||||
|
abstract class MobSpawnSettingsMixin {
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
private Map<EntityType<?>, MobSpawnSettings.MobSpawnCost> mobSpawnCosts;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Set biome cost flag for any EntityType which has a cost
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Inject(
|
||||||
|
method = "<init>",
|
||||||
|
at = @At(
|
||||||
|
value = "RETURN"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private void initBiomeCost(final CallbackInfo ci) {
|
||||||
|
for (final EntityType<?> type : this.mobSpawnCosts.keySet()) {
|
||||||
|
((MobSpawningEntityType)type).moonrise$setHasBiomeCost();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,77 @@
|
|||||||
|
package ca.spottedleaf.moonrise.mixin.mob_spawning;
|
||||||
|
|
||||||
|
import ca.spottedleaf.moonrise.patches.mob_spawning.MobSpawningEntityType;
|
||||||
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
|
import net.minecraft.core.BlockPos;
|
||||||
|
import net.minecraft.world.entity.EntityType;
|
||||||
|
import net.minecraft.world.level.NaturalSpawner;
|
||||||
|
import net.minecraft.world.level.biome.Biome;
|
||||||
|
import net.minecraft.world.level.biome.MobSpawnSettings;
|
||||||
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
|
||||||
|
@Mixin(NaturalSpawner.class)
|
||||||
|
abstract class NaturalSpawnerMixin {
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
static Biome getRoughBiome(final BlockPos arg, final ChunkAccess arg2) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Delay until we determine if the entity type even has a cost
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Redirect(
|
||||||
|
method = {"method_27819", "lambda$createState$2"}, // Fabric, NeoForge
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "Lnet/minecraft/world/level/NaturalSpawner;getRoughBiome(Lnet/minecraft/core/BlockPos;Lnet/minecraft/world/level/chunk/ChunkAccess;)Lnet/minecraft/world/level/biome/Biome;"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private static Biome delayRoughBiome(final BlockPos pos, final ChunkAccess chunk) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Delay until we determine if the entity type even has a cost
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Redirect(
|
||||||
|
method = {"method_27819", "lambda$createState$2"}, // Fabric, NeoForge
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "Lnet/minecraft/world/level/biome/Biome;getMobSettings()Lnet/minecraft/world/level/biome/MobSpawnSettings;"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private static MobSpawnSettings delayMobSpawnSettings(final Biome biome) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Avoid looking up biomes for mobs which have no cost
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Redirect(
|
||||||
|
method = {"method_27819", "lambda$createState$2"}, // Fabric, NeoForge
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "Lnet/minecraft/world/level/biome/MobSpawnSettings;getMobSpawnCost(Lnet/minecraft/world/entity/EntityType;)Lnet/minecraft/world/level/biome/MobSpawnSettings$MobSpawnCost;"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private static MobSpawnSettings.MobSpawnCost avoidBiomeLookupIfPossible(final MobSpawnSettings isNull,
|
||||||
|
final EntityType<?> type,
|
||||||
|
@Local(ordinal = 0, argsOnly = true) final BlockPos pos,
|
||||||
|
@Local(ordinal = 0, argsOnly = true) final LevelChunk chunk) {
|
||||||
|
if (!((MobSpawningEntityType)type).moonrise$hasAnyBiomeCost()) {
|
||||||
|
// if the type has no associated cost with any biome, then no point in looking
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return getRoughBiome(pos, chunk).getMobSettings().getMobSpawnCost(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -20,16 +20,17 @@ import org.spongepowered.asm.mixin.Overwrite;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
import java.util.function.BiPredicate;
|
import java.util.function.BiPredicate;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@Mixin(PoiManager.class)
|
@Mixin(PoiManager.class)
|
||||||
abstract class PoiManagerMixin extends SectionStorage<PoiSection> {
|
abstract class PoiManagerMixin extends SectionStorage<PoiSection, PoiSection.Packed> {
|
||||||
|
|
||||||
public PoiManagerMixin(SimpleRegionStorage simpleRegionStorage, Function<Runnable, Codec<PoiSection>> function, Function<Runnable, PoiSection> function2, RegistryAccess registryAccess, ChunkIOErrorReporter chunkIOErrorReporter, LevelHeightAccessor levelHeightAccessor) {
|
public PoiManagerMixin(final SimpleRegionStorage simpleRegionStorage, final Codec<PoiSection.Packed> codec, final Function<PoiSection, PoiSection.Packed> function, final BiFunction<PoiSection.Packed, Runnable, PoiSection> biFunction, final Function<Runnable, PoiSection> function2, final RegistryAccess registryAccess, final ChunkIOErrorReporter chunkIOErrorReporter, final LevelHeightAccessor levelHeightAccessor) {
|
||||||
super(simpleRegionStorage, function, function2, registryAccess, chunkIOErrorReporter, levelHeightAccessor);
|
super(simpleRegionStorage, codec, function, biFunction, function2, registryAccess, chunkIOErrorReporter, levelHeightAccessor);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ abstract class MinecraftMixin extends ReentrantBlockableEventLoop<Runnable> impl
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cir.setReturnValue(ret == null || ret == InactiveProfiler.INSTANCE ? this.leafProfiler : ProfilerFiller.tee(this.leafProfiler, ret));
|
cir.setReturnValue(ret == null || ret == InactiveProfiler.INSTANCE ? this.leafProfiler : ProfilerFiller.combine(this.leafProfiler, ret));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -10,14 +10,14 @@ import org.spongepowered.asm.mixin.Shadow;
|
|||||||
abstract class BiomeMixin {
|
abstract class BiomeMixin {
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
protected abstract float getHeightAdjustedTemperature(BlockPos blockPos);
|
protected abstract float getHeightAdjustedTemperature(BlockPos blockPos, int seaLevel);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @reason Cache appears ineffective
|
* @reason Cache appears ineffective
|
||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public float getTemperature(final BlockPos pos) {
|
public float getTemperature(final BlockPos pos, final int seaLevel) {
|
||||||
return this.getHeightAdjustedTemperature(pos);
|
return this.getHeightAdjustedTemperature(pos, seaLevel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package ca.spottedleaf.moonrise.mixin.random_ticking;
|
package ca.spottedleaf.moonrise.mixin.random_ticking;
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.common.PlatformHooks;
|
import ca.spottedleaf.moonrise.common.PlatformHooks;
|
||||||
import ca.spottedleaf.moonrise.common.list.IntList;
|
import ca.spottedleaf.moonrise.common.list.ShortList;
|
||||||
import ca.spottedleaf.moonrise.common.util.SimpleRandom;
|
import ca.spottedleaf.moonrise.common.util.SimpleRandom;
|
||||||
import ca.spottedleaf.moonrise.common.util.WorldUtil;
|
import ca.spottedleaf.moonrise.common.util.WorldUtil;
|
||||||
import ca.spottedleaf.moonrise.patches.block_counting.BlockCountingChunkSection;
|
import ca.spottedleaf.moonrise.patches.block_counting.BlockCountingChunkSection;
|
||||||
@@ -12,7 +12,6 @@ import net.minecraft.core.RegistryAccess;
|
|||||||
import net.minecraft.resources.ResourceKey;
|
import net.minecraft.resources.ResourceKey;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.util.RandomSource;
|
import net.minecraft.util.RandomSource;
|
||||||
import net.minecraft.util.profiling.ProfilerFiller;
|
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
import net.minecraft.world.level.Level;
|
import net.minecraft.world.level.Level;
|
||||||
import net.minecraft.world.level.WorldGenLevel;
|
import net.minecraft.world.level.WorldGenLevel;
|
||||||
@@ -27,13 +26,12 @@ import org.spongepowered.asm.mixin.Mixin;
|
|||||||
import org.spongepowered.asm.mixin.Unique;
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
import java.util.function.Supplier;
|
|
||||||
|
|
||||||
@Mixin(ServerLevel.class)
|
@Mixin(ServerLevel.class)
|
||||||
abstract class ServerLevelMixin extends Level implements WorldGenLevel {
|
abstract class ServerLevelMixin extends Level implements WorldGenLevel {
|
||||||
|
|
||||||
protected ServerLevelMixin(WritableLevelData writableLevelData, ResourceKey<Level> resourceKey, RegistryAccess registryAccess, Holder<DimensionType> holder, Supplier<ProfilerFiller> supplier, boolean bl, boolean bl2, long l, int i) {
|
protected ServerLevelMixin(final WritableLevelData writableLevelData, final ResourceKey<Level> resourceKey, final RegistryAccess registryAccess, final Holder<DimensionType> holder, final boolean bl, final boolean bl2, final long l, final int i) {
|
||||||
super(writableLevelData, resourceKey, registryAccess, holder, supplier, bl, bl2, l, i);
|
super(writableLevelData, resourceKey, registryAccess, holder, bl, bl2, l, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
@@ -85,11 +83,11 @@ abstract class ServerLevelMixin extends Level implements WorldGenLevel {
|
|||||||
final int offsetY = (sectionIndex + minSection) << 4;
|
final int offsetY = (sectionIndex + minSection) << 4;
|
||||||
final LevelChunkSection section = sections[sectionIndex];
|
final LevelChunkSection section = sections[sectionIndex];
|
||||||
final PalettedContainer<BlockState> states = section.states;
|
final PalettedContainer<BlockState> states = section.states;
|
||||||
if (section == null || !section.isRandomlyTickingBlocks()) {
|
if (!section.isRandomlyTickingBlocks()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
final IntList tickList = ((BlockCountingChunkSection)section).moonrise$getTickingBlockList();
|
final ShortList tickList = ((BlockCountingChunkSection)section).moonrise$getTickingBlockList();
|
||||||
|
|
||||||
for (int i = 0; i < tickSpeed; ++i) {
|
for (int i = 0; i < tickSpeed; ++i) {
|
||||||
final int tickingBlocks = tickList.size();
|
final int tickingBlocks = tickList.size();
|
||||||
@@ -100,7 +98,7 @@ abstract class ServerLevelMixin extends Level implements WorldGenLevel {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
final int location = tickList.getRaw(index);
|
final int location = (int)tickList.getRaw(index) & 0xFFFF;
|
||||||
final BlockState state = states.get(location);
|
final BlockState state = states.get(location);
|
||||||
|
|
||||||
// do not use a mutable pos, as some random tick implementations store the input without calling immutable()!
|
// do not use a mutable pos, as some random tick implementations store the input without calling immutable()!
|
||||||
|
|||||||
@@ -19,6 +19,10 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
|||||||
@Mixin(BlockBehaviour.BlockStateBase.class)
|
@Mixin(BlockBehaviour.BlockStateBase.class)
|
||||||
abstract class BlockStateBaseMixin extends StateHolder<Block, BlockState> implements StarlightAbstractBlockState {
|
abstract class BlockStateBaseMixin extends StateHolder<Block, BlockState> implements StarlightAbstractBlockState {
|
||||||
|
|
||||||
|
protected BlockStateBaseMixin(Block object, Reference2ObjectArrayMap<Property<?>, Comparable<?>> reference2ObjectArrayMap, MapCodec<BlockState> mapCodec) {
|
||||||
|
super(object, reference2ObjectArrayMap, mapCodec);
|
||||||
|
}
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
@Final
|
@Final
|
||||||
private boolean useShapeForLightOcclusion;
|
private boolean useShapeForLightOcclusion;
|
||||||
@@ -27,29 +31,26 @@ abstract class BlockStateBaseMixin extends StateHolder<Block, BlockState> implem
|
|||||||
@Final
|
@Final
|
||||||
private boolean canOcclude;
|
private boolean canOcclude;
|
||||||
|
|
||||||
@Shadow
|
|
||||||
protected BlockBehaviour.BlockStateBase.Cache cache;
|
|
||||||
|
|
||||||
@Unique
|
@Unique
|
||||||
private boolean isConditionallyFullOpaque;
|
private boolean isConditionallyFullOpaque;
|
||||||
|
|
||||||
protected BlockStateBaseMixin(Block object, Reference2ObjectArrayMap<Property<?>, Comparable<?>> reference2ObjectArrayMap, MapCodec<BlockState> mapCodec) {
|
|
||||||
super(object, reference2ObjectArrayMap, mapCodec);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Initialises our light state for this block.
|
|
||||||
*/
|
|
||||||
@Inject(
|
|
||||||
method = "initCache",
|
|
||||||
at = @At("RETURN")
|
|
||||||
)
|
|
||||||
public void initLightAccessState(final CallbackInfo ci) {
|
|
||||||
this.isConditionallyFullOpaque = this.canOcclude & this.useShapeForLightOcclusion;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public final boolean starlight$isConditionallyFullOpaque() {
|
public final boolean starlight$isConditionallyFullOpaque() {
|
||||||
return this.isConditionallyFullOpaque;
|
return this.isConditionallyFullOpaque;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Initialises our light state for this block.
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Inject(
|
||||||
|
method = "initCache",
|
||||||
|
at = @At(
|
||||||
|
value = "RETURN"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
public void initLightAccessState(final CallbackInfo ci) {
|
||||||
|
this.isConditionallyFullOpaque = this.canOcclude & this.useShapeForLightOcclusion;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,11 +2,16 @@ package ca.spottedleaf.moonrise.mixin.starlight.chunk;
|
|||||||
|
|
||||||
import ca.spottedleaf.moonrise.patches.starlight.chunk.StarlightChunk;
|
import ca.spottedleaf.moonrise.patches.starlight.chunk.StarlightChunk;
|
||||||
import ca.spottedleaf.moonrise.patches.starlight.light.SWMRNibbleArray;
|
import ca.spottedleaf.moonrise.patches.starlight.light.SWMRNibbleArray;
|
||||||
import net.minecraft.core.registries.Registries;
|
import net.minecraft.core.Registry;
|
||||||
|
import net.minecraft.world.level.ChunkPos;
|
||||||
|
import net.minecraft.world.level.LevelHeightAccessor;
|
||||||
|
import net.minecraft.world.level.biome.Biome;
|
||||||
import net.minecraft.world.level.chunk.ImposterProtoChunk;
|
import net.minecraft.world.level.chunk.ImposterProtoChunk;
|
||||||
import net.minecraft.world.level.chunk.LevelChunk;
|
import net.minecraft.world.level.chunk.LevelChunk;
|
||||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||||
import net.minecraft.world.level.chunk.UpgradeData;
|
import net.minecraft.world.level.chunk.UpgradeData;
|
||||||
|
import net.minecraft.world.level.levelgen.blending.BlendingData;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
import org.spongepowered.asm.mixin.Final;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
@@ -18,8 +23,8 @@ abstract class ImposterProtoChunkMixin extends ProtoChunk implements StarlightCh
|
|||||||
@Shadow
|
@Shadow
|
||||||
private LevelChunk wrapped;
|
private LevelChunk wrapped;
|
||||||
|
|
||||||
public ImposterProtoChunkMixin(final LevelChunk levelChunk, final boolean bl) {
|
public ImposterProtoChunkMixin(final ChunkPos chunkPos, final UpgradeData upgradeData, final LevelHeightAccessor levelHeightAccessor, final Registry<Biome> registry, @Nullable final BlendingData blendingData) {
|
||||||
super(levelChunk.getPos(), UpgradeData.EMPTY, levelChunk, levelChunk.getLevel().registryAccess().registryOrThrow(Registries.BIOME), levelChunk.getBlendingData());
|
super(chunkPos, upgradeData, levelHeightAccessor, registry, blendingData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -54,7 +54,24 @@ abstract class LevelLightEngineMixin implements LightEventListener, StarLightLig
|
|||||||
* TODO since this is a constructor inject, check on update for new constructors
|
* TODO since this is a constructor inject, check on update for new constructors
|
||||||
*/
|
*/
|
||||||
@Inject(
|
@Inject(
|
||||||
method = "<init>", at = @At("TAIL")
|
method = "<init>()V",
|
||||||
|
at = @At(
|
||||||
|
value = "TAIL"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
public void constructEmpty(final CallbackInfo ci) {
|
||||||
|
this.lightEngine = new StarLightInterface(null, false, false, (LevelLightEngine)(Object)this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* TODO since this is a constructor inject, check on update for new constructors
|
||||||
|
*/
|
||||||
|
@Inject(
|
||||||
|
method = "<init>(Lnet/minecraft/world/level/chunk/LightChunkGetter;ZZ)V",
|
||||||
|
at = @At(
|
||||||
|
value = "TAIL"
|
||||||
|
)
|
||||||
)
|
)
|
||||||
public void construct(final LightChunkGetter chunkProvider, final boolean hasBlockLight, final boolean hasSkyLight,
|
public void construct(final LightChunkGetter chunkProvider, final boolean hasBlockLight, final boolean hasSkyLight,
|
||||||
final CallbackInfo ci) {
|
final CallbackInfo ci) {
|
||||||
@@ -179,8 +196,10 @@ abstract class LevelLightEngineMixin implements LightEventListener, StarLightLig
|
|||||||
* @author Spottedleaf
|
* @author Spottedleaf
|
||||||
*/
|
*/
|
||||||
@Overwrite
|
@Overwrite
|
||||||
public boolean lightOnInSection(final SectionPos pos) {
|
public boolean lightOnInColumn(final long pos) {
|
||||||
final long key = CoordinateUtils.getChunkKey(pos.getX(), pos.getZ());
|
final long key = CoordinateUtils.getChunkKey(
|
||||||
|
CoordinateUtils.getChunkSectionX(pos), CoordinateUtils.getChunkSectionZ(pos)
|
||||||
|
);
|
||||||
return (!this.lightEngine.hasBlockLight() || this.blockLightMap.get(key) != null) && (!this.lightEngine.hasSkyLight() || this.skyLightMap.get(key) != null);
|
return (!this.lightEngine.hasBlockLight() || this.blockLightMap.get(key) != null) && (!this.lightEngine.hasSkyLight() || this.skyLightMap.get(key) != null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,13 +10,12 @@ import net.minecraft.core.BlockPos;
|
|||||||
import net.minecraft.core.SectionPos;
|
import net.minecraft.core.SectionPos;
|
||||||
import net.minecraft.network.protocol.Packet;
|
import net.minecraft.network.protocol.Packet;
|
||||||
import net.minecraft.network.protocol.game.ClientboundLightUpdatePacket;
|
import net.minecraft.network.protocol.game.ClientboundLightUpdatePacket;
|
||||||
import net.minecraft.server.level.ChunkTaskPriorityQueueSorter;
|
import net.minecraft.server.level.ChunkTaskDispatcher;
|
||||||
import net.minecraft.server.level.ServerLevel;
|
import net.minecraft.server.level.ServerLevel;
|
||||||
import net.minecraft.server.level.ServerPlayer;
|
import net.minecraft.server.level.ServerPlayer;
|
||||||
import net.minecraft.server.level.ThreadedLevelLightEngine;
|
import net.minecraft.server.level.ThreadedLevelLightEngine;
|
||||||
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
||||||
import net.minecraft.util.thread.ProcessorHandle;
|
import net.minecraft.util.thread.ConsecutiveExecutor;
|
||||||
import net.minecraft.util.thread.ProcessorMailbox;
|
|
||||||
import net.minecraft.world.level.ChunkPos;
|
import net.minecraft.world.level.ChunkPos;
|
||||||
import net.minecraft.world.level.LightLayer;
|
import net.minecraft.world.level.LightLayer;
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
@@ -50,10 +49,10 @@ import java.util.function.Supplier;
|
|||||||
abstract class ThreadedLevelLightEngineMixin extends LevelLightEngine implements StarLightLightingProvider {
|
abstract class ThreadedLevelLightEngineMixin extends LevelLightEngine implements StarLightLightingProvider {
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
private ProcessorMailbox<Runnable> taskMailbox;
|
private ConsecutiveExecutor consecutiveExecutor;
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
private ProcessorHandle<ChunkTaskPriorityQueueSorter.Message<Runnable>> sorterMailbox;
|
private ChunkTaskDispatcher taskDispatcher;
|
||||||
|
|
||||||
public ThreadedLevelLightEngineMixin(final LightChunkGetter chunkProvider, final boolean hasBlockLight, final boolean hasSkyLight) {
|
public ThreadedLevelLightEngineMixin(final LightChunkGetter chunkProvider, final boolean hasBlockLight, final boolean hasSkyLight) {
|
||||||
super(chunkProvider, hasBlockLight, hasSkyLight);
|
super(chunkProvider, hasBlockLight, hasSkyLight);
|
||||||
@@ -184,8 +183,8 @@ abstract class ThreadedLevelLightEngineMixin extends LevelLightEngine implements
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
private void initHook(final CallbackInfo ci) {
|
private void initHook(final CallbackInfo ci) {
|
||||||
this.taskMailbox = null;
|
this.consecutiveExecutor = null;
|
||||||
this.sorterMailbox = null;
|
this.taskDispatcher = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -40,7 +40,8 @@ abstract class ClientPacketListenerMixin implements ClientGamePacketListener {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
protected abstract void applyLightData(final int chunkX, final int chunkZ, final ClientboundLightUpdatePacketData clientboundLightUpdatePacketData);
|
protected abstract void applyLightData(final int chunkX, final int chunkZ, final ClientboundLightUpdatePacketData clientboundLightUpdatePacketData,
|
||||||
|
final boolean markDirty);
|
||||||
|
|
||||||
@Shadow
|
@Shadow
|
||||||
protected abstract void enableChunkLight(final LevelChunk levelChunk, final int chunkX, final int chunkZ);
|
protected abstract void enableChunkLight(final LevelChunk levelChunk, final int chunkX, final int chunkZ);
|
||||||
@@ -127,7 +128,7 @@ abstract class ClientPacketListenerMixin implements ClientGamePacketListener {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// load in light data from packet immediately
|
// load in light data from packet immediately
|
||||||
this.applyLightData(chunkX, chunkZ, clientboundLevelChunkWithLightPacket.getLightData());
|
this.applyLightData(chunkX, chunkZ, clientboundLevelChunkWithLightPacket.getLightData(), false);
|
||||||
((StarLightLightingProvider)this.level.getChunkSource().getLightEngine()).starlight$clientChunkLoad(new ChunkPos(chunkX, chunkZ), chunk);
|
((StarLightLightingProvider)this.level.getChunkSource().getLightEngine()).starlight$clientChunkLoad(new ChunkPos(chunkX, chunkZ), chunk);
|
||||||
|
|
||||||
// we need this for the update chunk status call, so that it can tell starlight what sections are empty and such
|
// we need this for the update chunk status call, so that it can tell starlight what sections are empty and such
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
package ca.spottedleaf.moonrise.mixin.starlight.world;
|
|
||||||
|
|
||||||
import ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil;
|
|
||||||
import net.minecraft.nbt.CompoundTag;
|
|
||||||
import net.minecraft.server.level.ServerLevel;
|
|
||||||
import net.minecraft.world.entity.ai.village.poi.PoiManager;
|
|
||||||
import net.minecraft.world.level.ChunkPos;
|
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
|
||||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
|
||||||
import net.minecraft.world.level.chunk.storage.ChunkSerializer;
|
|
||||||
import net.minecraft.world.level.chunk.storage.RegionStorageInfo;
|
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
|
||||||
|
|
||||||
@Mixin(ChunkSerializer.class)
|
|
||||||
abstract class ChunkSerializerMixin {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Overwrites vanilla's light data with our own.
|
|
||||||
* TODO this needs to be checked on update to account for format changes
|
|
||||||
*/
|
|
||||||
@Inject(
|
|
||||||
method = "write",
|
|
||||||
at = @At("RETURN")
|
|
||||||
)
|
|
||||||
private static void saveLightHook(final ServerLevel world, final ChunkAccess chunk, final CallbackInfoReturnable<CompoundTag> cir) {
|
|
||||||
SaveUtil.saveLightHook(world, chunk, cir.getReturnValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads our light data into the returned chunk object from the tag.
|
|
||||||
* TODO this needs to be checked on update to account for format changes
|
|
||||||
*/
|
|
||||||
@Inject(
|
|
||||||
method = "read",
|
|
||||||
at = @At("RETURN")
|
|
||||||
)
|
|
||||||
private static void loadLightHook(final ServerLevel serverLevel, final PoiManager poiManager,
|
|
||||||
final RegionStorageInfo regionStorageInfo, final ChunkPos chunkPos,
|
|
||||||
final CompoundTag compoundTag, final CallbackInfoReturnable<ProtoChunk> cir) {
|
|
||||||
SaveUtil.loadLightHook(serverLevel, chunkPos, compoundTag, cir.getReturnValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package ca.spottedleaf.moonrise.mixin.starlight.world;
|
||||||
|
|
||||||
|
import ca.spottedleaf.moonrise.patches.starlight.storage.StarlightSectionData;
|
||||||
|
import net.minecraft.world.level.chunk.storage.SerializableChunkData;
|
||||||
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
|
|
||||||
|
@Mixin(SerializableChunkData.SectionData.class)
|
||||||
|
abstract class SerializableChunkData$SectionData implements StarlightSectionData {
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private int blockLightState = -1;
|
||||||
|
|
||||||
|
@Unique
|
||||||
|
private int skyLightState = -1;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int starlight$getBlockLightState() {
|
||||||
|
return this.blockLightState;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void starlight$setBlockLightState(final int state) {
|
||||||
|
this.blockLightState = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final int starlight$getSkyLightState() {
|
||||||
|
return this.skyLightState;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public final void starlight$setSkyLightState(final int state) {
|
||||||
|
this.skyLightState = state;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,272 @@
|
|||||||
|
package ca.spottedleaf.moonrise.mixin.starlight.world;
|
||||||
|
|
||||||
|
import ca.spottedleaf.moonrise.common.util.MixinWorkarounds;
|
||||||
|
import ca.spottedleaf.moonrise.common.util.WorldUtil;
|
||||||
|
import ca.spottedleaf.moonrise.patches.starlight.chunk.StarlightChunk;
|
||||||
|
import ca.spottedleaf.moonrise.patches.starlight.light.SWMRNibbleArray;
|
||||||
|
import ca.spottedleaf.moonrise.patches.starlight.light.StarLightEngine;
|
||||||
|
import ca.spottedleaf.moonrise.patches.starlight.storage.StarlightSectionData;
|
||||||
|
import ca.spottedleaf.moonrise.patches.starlight.util.SaveUtil;
|
||||||
|
import com.llamalad7.mixinextras.sugar.Local;
|
||||||
|
import net.minecraft.nbt.CompoundTag;
|
||||||
|
import net.minecraft.nbt.Tag;
|
||||||
|
import net.minecraft.server.level.ServerLevel;
|
||||||
|
import net.minecraft.world.entity.ai.village.poi.PoiManager;
|
||||||
|
import net.minecraft.world.level.ChunkPos;
|
||||||
|
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||||
|
import net.minecraft.world.level.chunk.DataLayer;
|
||||||
|
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||||
|
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||||
|
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;
|
||||||
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
|
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||||
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
// note: keep in-sync with SaveUtil
|
||||||
|
@Mixin(SerializableChunkData.class)
|
||||||
|
abstract class SerializableChunkDataMixin {
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
private ChunkStatus chunkStatus;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@Final
|
||||||
|
private boolean lightCorrect;
|
||||||
|
|
||||||
|
@Shadow
|
||||||
|
@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
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Redirect(
|
||||||
|
method = "parse",
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "Lnet/minecraft/nbt/CompoundTag;getBoolean(Ljava/lang/String;)Z",
|
||||||
|
ordinal = 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private static boolean setLightCorrect(final CompoundTag instance, final String string,
|
||||||
|
@Local(ordinal = 0, argsOnly = false) final ChunkStatus status) {
|
||||||
|
final boolean starlightCorrect = instance.get("isLightOn") != null && instance.getInt(SaveUtil.STARLIGHT_VERSION_TAG) == SaveUtil.STARLIGHT_LIGHT_VERSION;
|
||||||
|
return status.isOrAfter(ChunkStatus.LIGHT) && starlightCorrect;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Add starlight block/sky state to SectionData
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Redirect(
|
||||||
|
method = "parse",
|
||||||
|
at = @At(
|
||||||
|
value = "NEW",
|
||||||
|
target = "(ILnet/minecraft/world/level/chunk/LevelChunkSection;Lnet/minecraft/world/level/chunk/DataLayer;Lnet/minecraft/world/level/chunk/DataLayer;)Lnet/minecraft/world/level/chunk/storage/SerializableChunkData$SectionData;",
|
||||||
|
ordinal = 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private static SerializableChunkData.SectionData readStarlightState(final int y, final LevelChunkSection chunkSection,
|
||||||
|
final DataLayer blockLight, final DataLayer skyLight,
|
||||||
|
@Local(ordinal = 3, argsOnly = false) final CompoundTag sectionData) {
|
||||||
|
final SerializableChunkData.SectionData ret = new SerializableChunkData.SectionData(
|
||||||
|
y, chunkSection, blockLight, skyLight
|
||||||
|
);
|
||||||
|
|
||||||
|
if (sectionData.contains(SaveUtil.BLOCKLIGHT_STATE_TAG, Tag.TAG_ANY_NUMERIC)) {
|
||||||
|
((StarlightSectionData)(Object)ret).starlight$setBlockLightState(sectionData.getInt(SaveUtil.BLOCKLIGHT_STATE_TAG));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sectionData.contains(SaveUtil.SKYLIGHT_STATE_TAG, Tag.TAG_ANY_NUMERIC)) {
|
||||||
|
((StarlightSectionData)(Object)ret).starlight$setSkyLightState(sectionData.getInt(SaveUtil.SKYLIGHT_STATE_TAG));
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Load light data from the section data and store them in the returned value's SWMRNibbleArrays
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Inject(
|
||||||
|
method = "read",
|
||||||
|
at = @At(
|
||||||
|
value = "RETURN"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private void loadStarlightLightData(final ServerLevel world, final PoiManager poiManager,
|
||||||
|
final RegionStorageInfo regionStorageInfo, final ChunkPos pos,
|
||||||
|
final CallbackInfoReturnable<ProtoChunk> cir) {
|
||||||
|
final ProtoChunk ret = cir.getReturnValue();
|
||||||
|
|
||||||
|
final boolean hasSkyLight = world.dimensionType().hasSkyLight();
|
||||||
|
final int minSection = WorldUtil.getMinLightSection(world);
|
||||||
|
|
||||||
|
final SWMRNibbleArray[] blockNibbles = StarLightEngine.getFilledEmptyLight(world);
|
||||||
|
final SWMRNibbleArray[] skyNibbles = StarLightEngine.getFilledEmptyLight(world);
|
||||||
|
|
||||||
|
if (!this.lightCorrect) {
|
||||||
|
((StarlightChunk)ret).starlight$setBlockNibbles(blockNibbles);
|
||||||
|
((StarlightChunk)ret).starlight$setSkyNibbles(skyNibbles);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Rewrite the section copying so that we can store Starlight's data
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Redirect(
|
||||||
|
method = "copyOf",
|
||||||
|
at = @At(
|
||||||
|
value = "INVOKE",
|
||||||
|
target = "Lnet/minecraft/world/level/lighting/LevelLightEngine;getMinLightSection()I",
|
||||||
|
ordinal = 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private static int rewriteSectionCopy(final LevelLightEngine instance,
|
||||||
|
@Local(ordinal = 0, argsOnly = true) final ServerLevel world,
|
||||||
|
@Local(ordinal = 0, argsOnly = true) final ChunkAccess chunk,
|
||||||
|
@Local(ordinal = 0, argsOnly = false) final List<SerializableChunkData.SectionData> sections) {
|
||||||
|
|
||||||
|
final int minLightSection = WorldUtil.getMinLightSection(world);
|
||||||
|
final int maxLightSection = WorldUtil.getMaxLightSection(world);
|
||||||
|
final int minBlockSection = WorldUtil.getMinSection(world);
|
||||||
|
|
||||||
|
final LevelChunkSection[] chunkSections = chunk.getSections();
|
||||||
|
final SWMRNibbleArray[] blockNibbles = ((StarlightChunk)chunk).starlight$getBlockNibbles();
|
||||||
|
final SWMRNibbleArray[] skyNibbles = ((StarlightChunk)chunk).starlight$getSkyNibbles();
|
||||||
|
|
||||||
|
for (int lightSection = minLightSection; lightSection <= maxLightSection; ++lightSection) {
|
||||||
|
final int lightSectionIdx = lightSection - minLightSection;
|
||||||
|
final int blockSectionIdx = lightSection - minBlockSection;
|
||||||
|
|
||||||
|
final LevelChunkSection chunkSection = (blockSectionIdx >= 0 && blockSectionIdx < chunkSections.length) ? chunkSections[blockSectionIdx].copy() : null;
|
||||||
|
final SWMRNibbleArray.SaveState blockNibble = blockNibbles[lightSectionIdx].getSaveState();
|
||||||
|
final SWMRNibbleArray.SaveState skyNibble = skyNibbles[lightSectionIdx].getSaveState();
|
||||||
|
|
||||||
|
if (chunkSection == null && blockNibble == null && skyNibble == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
final SerializableChunkData.SectionData sectionData = new SerializableChunkData.SectionData(
|
||||||
|
lightSection, chunkSection,
|
||||||
|
blockNibble == null ? null : (blockNibble.data == null ? null : new DataLayer(blockNibble.data)),
|
||||||
|
skyNibble == null ? null : (skyNibble.data == null ? null : new DataLayer(skyNibble.data))
|
||||||
|
);
|
||||||
|
|
||||||
|
if (blockNibble != null) {
|
||||||
|
((StarlightSectionData)(Object)sectionData).starlight$setBlockLightState(blockNibble.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skyNibble != null) {
|
||||||
|
((StarlightSectionData)(Object)sectionData).starlight$setSkyLightState(skyNibble.state);
|
||||||
|
}
|
||||||
|
|
||||||
|
sections.add(sectionData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// force the Vanilla loop to never run
|
||||||
|
return Integer.MAX_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Store the per-section block/sky state from Starlight
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Inject(
|
||||||
|
method = "write",
|
||||||
|
at = @At(
|
||||||
|
value = "FIELD",
|
||||||
|
target = "Lnet/minecraft/world/level/chunk/storage/SerializableChunkData$SectionData;chunkSection:Lnet/minecraft/world/level/chunk/LevelChunkSection;",
|
||||||
|
ordinal = 0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private void storeStarlightState(final CallbackInfoReturnable<CompoundTag> cir,
|
||||||
|
@Local(ordinal = 0, argsOnly = false) final SerializableChunkData.SectionData sectionData,
|
||||||
|
@Local(ordinal = 1, argsOnly = false) final CompoundTag sectionNBT) {
|
||||||
|
final int blockState = ((StarlightSectionData)(Object)sectionData).starlight$getBlockLightState();
|
||||||
|
final int skyState = ((StarlightSectionData)(Object)sectionData).starlight$getSkyLightState();
|
||||||
|
|
||||||
|
if (blockState > 0) {
|
||||||
|
sectionNBT.putInt(SaveUtil.BLOCKLIGHT_STATE_TAG, blockState);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skyState > 0) {
|
||||||
|
sectionNBT.putInt(SaveUtil.SKYLIGHT_STATE_TAG, skyState);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @reason Store Starlight's light version
|
||||||
|
* @author Spottedleaf
|
||||||
|
*/
|
||||||
|
@Inject(
|
||||||
|
method = "write",
|
||||||
|
at = @At(
|
||||||
|
value = "RETURN"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
private void writeStarlightCorrectLight(final CallbackInfoReturnable<CompoundTag> cir) {
|
||||||
|
if (this.chunkStatus.isBefore(ChunkStatus.LIGHT) || !this.lightCorrect) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final CompoundTag ret = cir.getReturnValue();
|
||||||
|
|
||||||
|
// clobber vanilla value to force vanilla to relight
|
||||||
|
ret.putBoolean("isLightOn", false);
|
||||||
|
// store our light version
|
||||||
|
ret.putInt(SaveUtil.STARLIGHT_VERSION_TAG, SaveUtil.STARLIGHT_LIGHT_VERSION);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -17,11 +17,17 @@ abstract class PalettedContainerMixin {
|
|||||||
* @author jpenilla
|
* @author jpenilla
|
||||||
*/
|
*/
|
||||||
@Redirect(
|
@Redirect(
|
||||||
method = "<init>*",
|
// cannot use `<init>*` due to https://github.com/FabricMC/tiny-remapper/issues/137
|
||||||
|
method = {
|
||||||
|
"<init>(Lnet/minecraft/core/IdMap;Lnet/minecraft/world/level/chunk/PalettedContainer$Strategy;Lnet/minecraft/world/level/chunk/PalettedContainer$Configuration;Lnet/minecraft/util/BitStorage;Ljava/util/List;)V",
|
||||||
|
"<init>(Lnet/minecraft/core/IdMap;Lnet/minecraft/world/level/chunk/PalettedContainer$Strategy;Lnet/minecraft/world/level/chunk/PalettedContainer$Data;)V",
|
||||||
|
"<init>(Lnet/minecraft/core/IdMap;Ljava/lang/Object;Lnet/minecraft/world/level/chunk/PalettedContainer$Strategy;)V"
|
||||||
|
},
|
||||||
at = @At(
|
at = @At(
|
||||||
value = "NEW",
|
value = "NEW",
|
||||||
target = "Lnet/minecraft/util/ThreadingDetector;"
|
target = "Lnet/minecraft/util/ThreadingDetector;"
|
||||||
)
|
),
|
||||||
|
require = 3 // Require matching all 3 constructors
|
||||||
)
|
)
|
||||||
private static ThreadingDetector threadingDetector(final String name) {
|
private static ThreadingDetector threadingDetector(final String name) {
|
||||||
return THREADING_DETECTOR;
|
return THREADING_DETECTOR;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user