Add Ancestral Spade solver
This commit is contained in:
@@ -67,7 +67,6 @@ repositories {
|
|||||||
maven("https://server.bbkr.space/artifactory/libs-release")
|
maven("https://server.bbkr.space/artifactory/libs-release")
|
||||||
maven("https://repo.nea.moe/releases")
|
maven("https://repo.nea.moe/releases")
|
||||||
maven("https://maven.notenoughupdates.org/releases")
|
maven("https://maven.notenoughupdates.org/releases")
|
||||||
mavenLocal()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
val shadowMe by configurations.creating {
|
val shadowMe by configurations.creating {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ mixinextras = "0.2.0-rc.5"
|
|||||||
jarvis = "1.1.1"
|
jarvis = "1.1.1"
|
||||||
nealisp = "1.0.0"
|
nealisp = "1.0.0"
|
||||||
explosiveenhancement = "1.2.1-1.20.x"
|
explosiveenhancement = "1.2.1-1.20.x"
|
||||||
moulconfig = "9999.9999.9999"
|
moulconfig = "3.0.0-beta.2"
|
||||||
|
|
||||||
|
|
||||||
[libraries]
|
[libraries]
|
||||||
|
|||||||
@@ -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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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>()
|
||||||
|
}
|
||||||
@@ -16,6 +16,7 @@ import moe.nea.firmament.features.debug.DebugView
|
|||||||
import moe.nea.firmament.features.debug.DeveloperFeatures
|
import moe.nea.firmament.features.debug.DeveloperFeatures
|
||||||
import moe.nea.firmament.features.debug.MinorTrolling
|
import moe.nea.firmament.features.debug.MinorTrolling
|
||||||
import moe.nea.firmament.features.debug.PowerUserTools
|
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.CompatibliltyFeatures
|
||||||
import moe.nea.firmament.features.fixes.Fixes
|
import moe.nea.firmament.features.fixes.Fixes
|
||||||
import moe.nea.firmament.features.inventory.CraftingOverlay
|
import moe.nea.firmament.features.inventory.CraftingOverlay
|
||||||
@@ -68,6 +69,7 @@ object FeatureManager : DataHolder<FeatureManager.Config>(serializer(), "feature
|
|||||||
loadFeature(CustomSkyBlockTextures)
|
loadFeature(CustomSkyBlockTextures)
|
||||||
loadFeature(PriceData)
|
loadFeature(PriceData)
|
||||||
loadFeature(Fixes)
|
loadFeature(Fixes)
|
||||||
|
loadFeature(DianaWaypoints)
|
||||||
loadFeature(ItemRarityCosmetics)
|
loadFeature(ItemRarityCosmetics)
|
||||||
if (Firmament.DEBUG) {
|
if (Firmament.DEBUG) {
|
||||||
loadFeature(DeveloperFeatures)
|
loadFeature(DeveloperFeatures)
|
||||||
|
|||||||
@@ -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())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -147,12 +147,16 @@ class RenderInWorldContext private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun line(vararg points: Vec3d, lineWidth: Float = 10F) {
|
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.setShader(GameRenderer::getRenderTypeLinesProgram)
|
||||||
RenderSystem.lineWidth(lineWidth / pow(camera.pos.squaredDistanceTo(points.first()), 0.25).toFloat())
|
RenderSystem.lineWidth(lineWidth / pow(camera.pos.squaredDistanceTo(points.first()), 0.25).toFloat())
|
||||||
buffer.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES)
|
buffer.begin(VertexFormat.DrawMode.LINES, VertexFormats.LINES)
|
||||||
buffer.fixedColor(255, 255, 255, 255)
|
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)
|
doLine(matrixStack.peek(), buffer, a.x, a.y, a.z, b.x, b.y, b.z)
|
||||||
}
|
}
|
||||||
buffer.unfixColor()
|
buffer.unfixColor()
|
||||||
@@ -173,7 +177,7 @@ class RenderInWorldContext private constructor(
|
|||||||
) {
|
) {
|
||||||
val normal = Vector3f(x.toFloat(), y.toFloat(), z.toFloat())
|
val normal = Vector3f(x.toFloat(), y.toFloat(), z.toFloat())
|
||||||
.sub(i.toFloat(), j.toFloat(), k.toFloat())
|
.sub(i.toFloat(), j.toFloat(), k.toFloat())
|
||||||
.mul(-1F)
|
.normalize()
|
||||||
buf.vertex(matrix.positionMatrix, i.toFloat(), j.toFloat(), k.toFloat())
|
buf.vertex(matrix.positionMatrix, i.toFloat(), j.toFloat(), k.toFloat())
|
||||||
.normal(matrix.normalMatrix, normal.x, normal.y, normal.z).next()
|
.normal(matrix.normalMatrix, normal.x, normal.y, normal.z).next()
|
||||||
buf.vertex(matrix.positionMatrix, x.toFloat(), y.toFloat(), z.toFloat())
|
buf.vertex(matrix.positionMatrix, x.toFloat(), y.toFloat(), z.toFloat())
|
||||||
|
|||||||
Reference in New Issue
Block a user