aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/java/moe/nea/firmament/mixins/SoundReceiveEventPatch.java35
-rw-r--r--src/main/kotlin/moe/nea/firmament/events/SoundReceiveEvent.kt23
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt2
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/diana/AncestralSpadeSolver.kt93
-rw-r--r--src/main/kotlin/moe/nea/firmament/features/diana/DianaWaypoints.kt32
-rw-r--r--src/main/kotlin/moe/nea/firmament/util/render/RenderInWorldContext.kt8
6 files changed, 191 insertions, 2 deletions
diff --git a/src/main/java/moe/nea/firmament/mixins/SoundReceiveEventPatch.java b/src/main/java/moe/nea/firmament/mixins/SoundReceiveEventPatch.java
new file mode 100644
index 0000000..64f8765
--- /dev/null
+++ b/src/main/java/moe/nea/firmament/mixins/SoundReceiveEventPatch.java
@@ -0,0 +1,35 @@
+/*
+ * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package moe.nea.firmament.mixins;
+
+import moe.nea.firmament.events.SoundReceiveEvent;
+import net.minecraft.client.network.ClientPlayNetworkHandler;
+import net.minecraft.network.packet.s2c.play.PlaySoundS2CPacket;
+import net.minecraft.util.math.Vec3d;
+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.CallbackInfo;
+
+@Mixin(ClientPlayNetworkHandler.class)
+public class SoundReceiveEventPatch {
+ @Inject(method = "onPlaySound", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/world/ClientWorld;playSound(Lnet/minecraft/entity/player/PlayerEntity;DDDLnet/minecraft/registry/entry/RegistryEntry;Lnet/minecraft/sound/SoundCategory;FFJ)V"), cancellable = true)
+ private void postEventWhenSoundIsPlayed(PlaySoundS2CPacket packet, CallbackInfo ci) {
+ var event = new SoundReceiveEvent(
+ packet.getSound(),
+ packet.getCategory(),
+ new Vec3d(packet.getX(), packet.getY(), packet.getZ()),
+ packet.getPitch(),
+ packet.getVolume(),
+ packet.getSeed()
+ );
+ SoundReceiveEvent.Companion.publish(event);
+ if (event.getCancelled()) {
+ ci.cancel();
+ }
+ }
+}
diff --git a/src/main/kotlin/moe/nea/firmament/events/SoundReceiveEvent.kt b/src/main/kotlin/moe/nea/firmament/events/SoundReceiveEvent.kt
new file mode 100644
index 0000000..45b3982
--- /dev/null
+++ b/src/main/kotlin/moe/nea/firmament/events/SoundReceiveEvent.kt
@@ -0,0 +1,23 @@
+/*
+ * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package moe.nea.firmament.events
+
+import net.minecraft.registry.entry.RegistryEntry
+import net.minecraft.sound.SoundCategory
+import net.minecraft.sound.SoundEvent
+import net.minecraft.util.math.Vec3d
+
+data class SoundReceiveEvent(
+ val sound: RegistryEntry<SoundEvent>,
+ val category: SoundCategory,
+ val position: Vec3d,
+ val pitch: Float,
+ val volume: Float,
+ val seed: Long
+) : FirmamentEvent.Cancellable() {
+ companion object : FirmamentEventBus<SoundReceiveEvent>()
+}
diff --git a/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt b/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt
index 3c5ac62..99f84e6 100644
--- a/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt
+++ b/src/main/kotlin/moe/nea/firmament/features/FeatureManager.kt
@@ -16,6 +16,7 @@ import moe.nea.firmament.features.debug.DebugView
import moe.nea.firmament.features.debug.DeveloperFeatures
import moe.nea.firmament.features.debug.MinorTrolling
import moe.nea.firmament.features.debug.PowerUserTools
+import moe.nea.firmament.features.diana.DianaWaypoints
import moe.nea.firmament.features.fixes.CompatibliltyFeatures
import moe.nea.firmament.features.fixes.Fixes
import moe.nea.firmament.features.inventory.CraftingOverlay
@@ -68,6 +69,7 @@ object FeatureManager : DataHolder<FeatureManager.Config>(serializer(), "feature
loadFeature(CustomSkyBlockTextures)
loadFeature(PriceData)
loadFeature(Fixes)
+ loadFeature(DianaWaypoints)
loadFeature(ItemRarityCosmetics)
if (Firmament.DEBUG) {
loadFeature(DeveloperFeatures)
diff --git a/src/main/kotlin/moe/nea/firmament/features/diana/AncestralSpadeSolver.kt b/src/main/kotlin/moe/nea/firmament/features/diana/AncestralSpadeSolver.kt
new file mode 100644
index 0000000..c34e68e
--- /dev/null
+++ b/src/main/kotlin/moe/nea/firmament/features/diana/AncestralSpadeSolver.kt
@@ -0,0 +1,93 @@
+/*
+ * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package moe.nea.firmament.features.diana
+
+import org.joml.Vector3f
+import kotlin.time.Duration.Companion.seconds
+import net.minecraft.particle.ParticleTypes
+import net.minecraft.sound.SoundEvents
+import net.minecraft.util.math.Vec3d
+import moe.nea.firmament.events.ParticleSpawnEvent
+import moe.nea.firmament.events.SoundReceiveEvent
+import moe.nea.firmament.events.WorldRenderLastEvent
+import moe.nea.firmament.util.TimeMark
+import moe.nea.firmament.util.render.RenderInWorldContext
+
+object AncestralSpadeSolver {
+ var lastDing = TimeMark.farPast()
+ private set
+ private val pitches = mutableListOf<Float>()
+ val particlePositions = mutableListOf<Vec3d>()
+ var nextGuess: Vec3d? = null
+ private set
+
+ fun onParticleSpawn(event: ParticleSpawnEvent) {
+ if (!DianaWaypoints.TConfig.ancestralSpadeSolver) return
+ if (event.particleEffect != ParticleTypes.DRIPPING_LAVA) return
+ particlePositions.add(event.position)
+ if (particlePositions.size > 20) {
+ particlePositions.removeFirst()
+ }
+ }
+
+ fun onPlaySound(event: SoundReceiveEvent) {
+ if (!DianaWaypoints.TConfig.ancestralSpadeSolver) return
+ if (!SoundEvents.BLOCK_NOTE_BLOCK_HARP.matchesId(event.sound.value().id)) return
+
+ if (lastDing.passedTime() > 1.seconds) {
+ particlePositions.clear()
+ pitches.clear()
+ }
+ lastDing = TimeMark.now()
+
+ pitches.add(event.pitch)
+ if (pitches.size > 20) {
+ pitches.removeFirst()
+ }
+
+ if (particlePositions.size < 3) {
+ return
+ }
+
+ val averagePitchDelta =
+ if (pitches.isEmpty()) 0.0
+ else pitches
+ .zipWithNext { a, b -> b - a }
+ .average()
+
+ val soundDistanceEstimate = (Math.E / averagePitchDelta) - particlePositions.first().distanceTo(event.position)
+
+ if (soundDistanceEstimate > 1000) {
+ return
+ }
+
+ val lastParticleDirection = particlePositions
+ .takeLast(3)
+ .let { (a, _, b) -> b.subtract(a) }
+ .normalize()
+
+ nextGuess = event.position.add(lastParticleDirection.multiply(soundDistanceEstimate))
+ }
+
+ fun onWorldRender(event: WorldRenderLastEvent) {
+ if (!DianaWaypoints.TConfig.ancestralSpadeSolver) return
+ RenderInWorldContext.renderInWorld(event) {
+ nextGuess?.let {
+ color(1f, 1f, 0f, 0.5f)
+ tinyBlock(it, 1f)
+ color(1f, 1f, 0f, 1f)
+ val cameraForward = Vector3f(0f, 0f, 1f).rotate(event.camera.rotation)
+ line(event.camera.pos.add(Vec3d(cameraForward)), it, lineWidth = 3f)
+ }
+ if (particlePositions.size > 2 && lastDing.passedTime() < 10.seconds) {
+ color(0f, 1f, 0f, 0.7f)
+ line(*particlePositions.toTypedArray())
+ }
+ }
+ }
+
+}
diff --git a/src/main/kotlin/moe/nea/firmament/features/diana/DianaWaypoints.kt b/src/main/kotlin/moe/nea/firmament/features/diana/DianaWaypoints.kt
new file mode 100644
index 0000000..eb20852
--- /dev/null
+++ b/src/main/kotlin/moe/nea/firmament/features/diana/DianaWaypoints.kt
@@ -0,0 +1,32 @@
+/*
+ * SPDX-FileCopyrightText: 2024 Linnea Gräf <nea@nea.moe>
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+package moe.nea.firmament.features.diana
+
+import moe.nea.firmament.events.ParticleSpawnEvent
+import moe.nea.firmament.events.SoundReceiveEvent
+import moe.nea.firmament.events.WorldRenderLastEvent
+import moe.nea.firmament.features.FirmamentFeature
+import moe.nea.firmament.gui.config.ManagedConfig
+
+object DianaWaypoints : FirmamentFeature {
+ override val identifier: String
+ get() = "diana-waypoints"
+ override val config: ManagedConfig?
+ get() = TConfig
+
+ object TConfig : ManagedConfig(identifier) {
+ val ancestralSpadeSolver by toggle("ancestral-spade") { false }
+ }
+
+ override fun onLoad() {
+ ParticleSpawnEvent.subscribe(AncestralSpadeSolver::onParticleSpawn)
+ SoundReceiveEvent.subscribe(AncestralSpadeSolver::onPlaySound)
+ WorldRenderLastEvent.subscribe(AncestralSpadeSolver::onWorldRender)
+ }
+}
+
+
diff --git a/src/main/kotlin/moe/nea/firmament/util/render/RenderInWorldContext.kt b/src/main/kotlin/moe/nea/firmament/util/render/RenderInWorldContext.kt
index aa54979..20f9de8 100644
--- a/src/main/kotlin/moe/nea/firmament/util/render/RenderInWorldContext.kt
+++ b/src/main/kotlin/moe/nea/firmament/util/render/RenderInWorldContext.kt
@@ -147,12 +147,16 @@ class RenderInWorldContext private constructor(
}
fun line(vararg points: Vec3d, lineWidth: Float = 10F) {
+ line(points.toList(), lineWidth)
+ }
+
+ fun line(points: List<Vec3d>, lineWidth: Float = 10F) {
RenderSystem.setShader(GameRenderer::getRenderTypeLinesProgram)
RenderSystem.lineWidth(lineWidth / pow(camera.pos.squaredDistanceTo(points.first()), 0.25).toFloat())
buffer.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES)
buffer.fixedColor(255, 255, 255, 255)
- points.toList().zipWithNext().forEach { (a, b) ->
+ points.zipWithNext().forEach { (a, b) ->
doLine(matrixStack.peek(), buffer, a.x, a.y, a.z, b.x, b.y, b.z)
}
buffer.unfixColor()
@@ -173,7 +177,7 @@ class RenderInWorldContext private constructor(
) {
val normal = Vector3f(x.toFloat(), y.toFloat(), z.toFloat())
.sub(i.toFloat(), j.toFloat(), k.toFloat())
- .mul(-1F)
+ .normalize()
buf.vertex(matrix.positionMatrix, i.toFloat(), j.toFloat(), k.toFloat())
.normal(matrix.normalMatrix, normal.x, normal.y, normal.z).next()
buf.vertex(matrix.positionMatrix, x.toFloat(), y.toFloat(), z.toFloat())