Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improvement: Berberis Helper Rework #3147

Open
wants to merge 21 commits into
base: beta
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@
import at.hannibal2.skyhanni.config.FeatureToggle;
import com.google.gson.annotations.Expose;
import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorBoolean;
import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorColour;
import io.github.notenoughupdates.moulconfig.annotations.ConfigEditorSlider;
import io.github.notenoughupdates.moulconfig.annotations.ConfigOption;

import java.awt.Color;

public class WiltedBerberisConfig {

@Expose
Expand All @@ -27,4 +31,14 @@ public class WiltedBerberisConfig {
@ConfigOption(name = "Mute Others Sounds", desc = "Mute nearby Wilted Berberis sounds while not holding a Wand of Farming or not standing on Farmland blocks.")
@ConfigEditorBoolean
public boolean muteOthersSounds = true;

@Expose
@ConfigOption(name = "Future Preview Count", desc = "How many future Wilted Berberis locations to preview.")
@ConfigEditorSlider(minValue = 0, maxValue = 8, minStep = 1)
public int previewCount = 2;

@Expose
@ConfigOption(name = "Highlight Color", desc = "What color to highlight the next Wilted Berberis to break.")
@ConfigEditorColour
public String highlightColor = "0:255:255:255:0";
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import at.hannibal2.skyhanni.utils.RenderUtils.drawFilledBoundingBoxNea
import at.hannibal2.skyhanni.utils.RenderUtils.expandBlock
import at.hannibal2.skyhanni.utils.SimpleTimeMark
import at.hannibal2.skyhanni.utils.SpecialColor.toSpecialColor
import at.hannibal2.skyhanni.utils.toLorenzVec
import net.minecraft.client.Minecraft
import net.minecraft.init.Blocks
Expand All @@ -31,19 +32,16 @@

@SkyHanniModule
object RiftWiltedBerberisHelper {
// not a great programmer, but it's better than nothing :p -maj

private val config get() = RiftAPI.config.area.dreadfarm.wiltedBerberis
private var isOnFarmland = false
private var hasFarmingToolInHand = false

// list of berberis in the current plot, in the order they appeared in
private var berberisList = listOf<LorenzVec>()
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

give this list below better names to differentiate

private var lastSpawn = SimpleTimeMark.now()
private var lastSyncedAt = SimpleTimeMark.now()
private var lastUpdated = SimpleTimeMark.now()

// array of the bounds of each berberis plot
// the bounds of each berberis plot
private val plots = arrayOf(
Plot(LorenzVec(-54, 71, -128), LorenzVec(-41, 70, -117)),
Plot(LorenzVec(-77, 72, -143), LorenzVec(-59, 71, -125)),
Expand All @@ -53,17 +51,12 @@
Plot(LorenzVec(-42, 72, -155), LorenzVec(-22, 70, -126)),
)

// the closest plot to the player
private var closestPlot = 0

// the closest plot to the player last tick
private var oldClosest = 0
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

change those two variable sto be of type Plot?


data class Plot(var c1: LorenzVec, var c2: LorenzVec)

private var fallback = false

// original system stuff:
data class Plot(var a: LorenzVec, var b: LorenzVec)

private var list = listOf<WiltedBerberis>()

data class WiltedBerberis(var currentParticles: LorenzVec) {
Expand All @@ -73,82 +66,22 @@
var lastTime = SimpleTimeMark.now()
}

private fun nearestBerberis(location: LorenzVec): WiltedBerberis? =
list.filter { it.currentParticles.distanceSq(location) < 8 }
.minByOrNull { it.currentParticles.distanceSq(location) }

private fun LorenzVec.fixLocation(wiltedBerberis: WiltedBerberis): LorenzVec {
val x = x - 0.5
val y = wiltedBerberis.y
val z = z - 0.5
return LorenzVec(x, y, z)
}
// end original system stuff

@SubscribeEvent
fun onTick(event: LorenzTickEvent) {
RevengeLordOfMaj marked this conversation as resolved.
Show resolved Hide resolved
if (!isEnabled()) return
if (!event.isMod(5)) return

// calculates the player's distance to the center of each plot, then sets closestPlot to the smallest
val plotDistances = arrayListOf(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
for (i in 0..5) plotDistances[i] = LocationUtils.playerLocation().distance(plots[i].c1.middle(plots[i].c2))
for (i in 0..5) if (plotDistances[i] < plotDistances[closestPlot]) closestPlot = i

// if the player enters a new plot, clear the list of berberis locations
if (closestPlot != oldClosest) berberisList = berberisList.editCopy { clear() }
oldClosest = closestPlot

// when a berberis grows in the current plot, add its location to the end of the list
for (block in BlockPos.getAllInBox(plots[closestPlot].c1.toBlockPos(), plots[closestPlot].c2.toBlockPos())) {
if (block.toLorenzVec().getBlockAt() == Blocks.deadbush && !berberisList.contains(block.toLorenzVec())) {
berberisList = berberisList.editCopy { add(block.toLorenzVec()) }
lastSpawn = SimpleTimeMark.now()
lastUpdated = SimpleTimeMark.now()
}
}
getClosestPlot()
updateBerberisList()
sync()

// remove first berberis from list if broken and no berberis have grown in the last 1/4 seccond
// (to stop you from breaking it before they all spawn in)
while (berberisList.isNotEmpty() && berberisList[0].getBlockAt() != Blocks.deadbush && lastSpawn.passedSince() > 250.milliseconds) {
berberisList = berberisList.editCopy { removeFirst() }
lastUpdated = SimpleTimeMark.now()
}

// check if the new system is right about which bush to break. If the particle is still moving, assume it's right for now
for (berberis in list) {
with(berberis) {
// if there is a particle in the same place as where the new helper thinks the next bush is,
if (berberisList.isNotEmpty() && (currentParticles.distance(berberisList[0])) < 1.3 &&
currentParticles.distanceToPlayer() <= 20 && y != 0.0
) {
lastSyncedAt = SimpleTimeMark.now()
}
// or if there is a moving particle
if (moving) {
lastSyncedAt = SimpleTimeMark.now()
}
}
}

// if we've been desynced (new system wrong) for more than 2 secconds and the list hasn't updated in that time,
// switch to fallback mode. switch off of fallback once the plot is cleared
if (lastSyncedAt.passedSince() > 1000.milliseconds && lastUpdated.passedSince() > 1000.milliseconds) fallback = true
if (berberisList.isEmpty()) fallback = false

// get if player holding farming wand
hasFarmingToolInHand = InventoryUtils.getItemInHand()?.getInternalName() == RiftAPI.farmingTool

// get if player is on farmland
if (Minecraft.getMinecraft().thePlayer.onGround) {
val block = LorenzVec.getBlockBelowPlayer().getBlockAt()
val currentY = LocationUtils.playerLocation().y
isOnFarmland = block == Blocks.farmland && (currentY % 1 == 0.0)
}

// original system stuff:
list = list.editCopy { removeIf { it.lastTime.passedSince() > 500.milliseconds } }

}

@SubscribeEvent
Expand All @@ -166,12 +99,11 @@
}
return
}
// the firework sparks in the center just get cancelled, but the below code runs on them
// the firework sparks in the center may get cancelled, but the below code runs on them
if (config.hideParticles) {
event.cancel()
}

// original system stuff:
if (berberis == null) {
list = list.editCopy { add(WiltedBerberis(location)) }
return
Expand All @@ -195,7 +127,6 @@
moving = isMoving
currentParticles = location
lastTime = SimpleTimeMark.now()
// end original system stuff
}
}

Expand All @@ -216,58 +147,132 @@
if (!hasFarmingToolInHand) return
if (config.onlyOnFarmland && !isOnFarmland) return

// original system:
if (fallback) {
for (berberis in list) {
with(berberis) {
if (currentParticles.distanceToPlayer() > 20) continue
if (y == 0.0) continue

val location = currentParticles.fixLocation(berberis)
if (!moving) {
event.drawFilledBoundingBoxNea(axisAlignedBB(location), Color.YELLOW, 0.7f)
event.drawDynamicText(location.up(), "§eWilted Berberis", 1.5, ignoreBlocks = false)
} else {
event.drawFilledBoundingBoxNea(axisAlignedBB(location), Color.WHITE, 0.5f)
previous?.fixLocation(berberis)?.let {
event.drawFilledBoundingBoxNea(axisAlignedBB(it), Color.LIGHT_GRAY, 0.2f)
event.draw3DLine(it.add(0.5, 0.0, 0.5), location.add(0.5, 0.0, 0.5), Color.WHITE, 3, false)
}
}
if (fallback) fallbackRender(event)
else primaryRender(event)
}

@HandleEvent
fun onConfigFix(event: ConfigUpdaterMigrator.ConfigFixEvent) {
event.move(60, "rift.area.dreadfarm.wiltedBerberis.hideparticles", "rift.area.dreadfarm.wiltedBerberis.hideParticles")
jani270 marked this conversation as resolved.
Show resolved Hide resolved
}

private fun getClosestPlot() {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

instead of this approach with array list, two for loops and manual comparing each entry against the prevous losetest plot, you can use lamda functions on a map like .minBy() to get the clostest plot. i think of something like cloestPlot = plots.map{ it to it.middle.distanceToPlayer() }.minBy{it.second}.first. then you can store the instance inseatd of the index in the closestPlot value.

// calculates the player's distance to the center of each plot, then sets closestPlot to the smallest
val plotDistances = arrayListOf(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)
for (i in 0..5) {
val plotCenter = plots[i].a.middle(plots[i].b)
Copy link
Owner

@hannibal002 hannibal002 Jan 7, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please only calculate the middle location once, then reuse the same value

plotDistances[i] = LocationUtils.playerLocation().distance(plotCenter)
}
for (i in 0..5) if (plotDistances[i] < plotDistances[closestPlot]) closestPlot = i
}

private fun updateBerberisList() {
// if the player enters a new plot, clear the list of berberis locations
if (closestPlot != oldClosest) berberisList = berberisList.editCopy { clear() }
oldClosest = closestPlot

// when a berberis grows in the current plot, add its location to the end of the list
val plotCornerA = plots[closestPlot].a.toBlockPos()
val plotCornerB = plots[closestPlot].b.toBlockPos()
for (block in BlockPos.getAllInBox(plotCornerA, plotCornerB)) {
if (block.toLorenzVec().getBlockAt() == Blocks.deadbush && !berberisList.contains(block.toLorenzVec())) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

merge all usages of block.toLorenzVec() into one variable

berberisList = berberisList.editCopy { add(block.toLorenzVec()) }
lastSpawn = SimpleTimeMark.now()
lastUpdated = SimpleTimeMark.now()
}
}

// remove first berberis from list if broken and no berberis have grown in the last 1/4 seccond
// (to stop you from breaking it before they all spawn in)
while (berberisList.isNotEmpty() && berberisList[0].getBlockAt() != Blocks.deadbush && lastSpawn.passedSince() > 250.milliseconds) {
berberisList = berberisList.editCopy { removeFirst() }
lastUpdated = SimpleTimeMark.now()
}

// update the berberis list for the original system
list = list.editCopy { removeIf { it.lastTime.passedSince() > 500.milliseconds } }
}

private fun sync() {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

give this function a better name

// check if the new system is right about which bush to break. If the particle is still moving, assume it's right for now
for (berberis in list) {
with(berberis) {
// if there is a particle in the same place as where the new helper thinks the next bush is,
if (berberisList.isNotEmpty() && (currentParticles.distance(berberisList[0])) < 1.3 &&
currentParticles.distanceToPlayer() <= 20 && y != 0.0
) {
lastSyncedAt = SimpleTimeMark.now()
}
// or if there is a moving particle
if (moving) {
lastSyncedAt = SimpleTimeMark.now()
}
}
} else {
// new system
if (berberisList.isEmpty()) return
var alpha = 0.8f
var previousBerberis: LorenzVec? = null
event.drawDynamicText(berberisList[0].up(), "§eWilted Berberis", 1.5, ignoreBlocks = false)

berberisList.take(3).forEachIndexed { i, loc ->
// box it with half the opacity of the previous box, first in list is yellow
if (i == 0) event.drawFilledBoundingBoxNea(axisAlignedBB(loc), Color.YELLOW, alpha)
else event.drawFilledBoundingBoxNea(axisAlignedBB(loc), Color.WHITE, alpha)
alpha /= 2f

// if there's a previous berberis, draw a line to it. The line from the 2nd to the 1st should be yellow
if (i == 1) {
previousBerberis?.let {
event.draw3DLine(loc.add(0.5, 0.5, 0.5), it.add(0.5, 0.5, 0.5), Color.YELLOW, 4, false)
}
}

// if we've been desynced (new system wrong) for more than 2 secconds and the list hasn't updated in that time,
// switch to fallback mode. switch off of fallback once the plot is cleared
if (lastSyncedAt.passedSince() > 1000.milliseconds && lastUpdated.passedSince() > 1000.milliseconds) fallback = true
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use 1.seconds instead of 1k ms

if (berberisList.isEmpty()) fallback = false
}

private fun fallbackRender(event: LorenzRenderWorldEvent) {
for (berberis in list) {
with(berberis) {
if (currentParticles.distanceToPlayer() > 20) continue
if (y == 0.0) continue

val location = currentParticles.fixLocation(berberis)
if (!moving) {
event.drawFilledBoundingBoxNea(axisAlignedBB(location), config.highlightColor.toSpecialColor(), 0.7f)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toSpecialColor is a heavy logic, please move it outside of the for loop

event.drawDynamicText(location.up(), "§eWilted Berberis", 1.5, ignoreBlocks = false)
} else {
previousBerberis?.let {
event.draw3DLine(loc.add(0.5, 0.5, 0.5), it.add(0.5, 0.5, 0.5), Color.WHITE, 2, false)
event.drawFilledBoundingBoxNea(axisAlignedBB(location), Color.WHITE, 0.5f)
previous?.fixLocation(berberis)?.let {
event.drawFilledBoundingBoxNea(axisAlignedBB(it), Color.LIGHT_GRAY, 0.2f)
event.draw3DLine(it.add(0.5, 0.0, 0.5), location.add(0.5, 0.0, 0.5), Color.WHITE, 3, false)
}
}
}
}
}

previousBerberis = loc
private fun primaryRender(event: LorenzRenderWorldEvent) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

better name

if (berberisList.isEmpty()) return
var alpha = 0.8f
var previousBerberis: LorenzVec? = null
event.drawDynamicText(berberisList[0].up(), "§eWilted Berberis", 1.5, ignoreBlocks = false)

berberisList.take(config.previewCount+1).forEachIndexed { i, loc ->

Check warning on line 246 in src/main/java/at/hannibal2/skyhanni/features/rift/area/dreadfarm/RiftWiltedBerberisHelper.kt

View workflow job for this annotation

GitHub Actions / Run detekt

detekt.formatting.SpacingAroundOperators

Missing spacing around "+"
// box it with half the opacity of the previous box, first in list is highlighted
if (i == 0) event.drawFilledBoundingBoxNea(axisAlignedBB(loc), config.highlightColor.toSpecialColor(), alpha)
else event.drawFilledBoundingBoxNea(axisAlignedBB(loc), Color.WHITE, alpha)
alpha *= 0.6f

// if there's a previous berberis, draw a line to it. The line from the 2nd to the 1st should be highlighted
if (i == 1) {
previousBerberis?.let {
event.draw3DLine(loc.add(0.5, 0.5, 0.5), it.add(0.5, 0.5, 0.5), config.highlightColor.toSpecialColor(), 4, false)
}
} else {
previousBerberis?.let {
event.draw3DLine(loc.add(0.5, 0.5, 0.5), it.add(0.5, 0.5, 0.5), Color.WHITE, 2, false)
}
}

previousBerberis = loc
}
}

@HandleEvent
fun onConfigFix(event: ConfigUpdaterMigrator.ConfigFixEvent) {
event.move(60, "rift.area.dreadfarm.wiltedBerberis.hideparticles", "rift.area.dreadfarm.wiltedBerberis.hideParticles")
private fun nearestBerberis(location: LorenzVec): WiltedBerberis? =
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try to change the logic so that the distance is only getting calculated once per entry, not twice

list.filter { it.currentParticles.distanceSq(location) < 8 }
.minByOrNull { it.currentParticles.distanceSq(location) }

private fun LorenzVec.fixLocation(wiltedBerberis: WiltedBerberis): LorenzVec {
val x = x - 0.5
val y = wiltedBerberis.y
val z = z - 0.5
return LorenzVec(x, y, z)
}

private fun axisAlignedBB(loc: LorenzVec) = loc.add(0.1, -0.1, 0.1).boundingToOffset(0.8, 1.0, 0.8).expandBlock()
Expand Down
Loading