Skip to content

Commit

Permalink
fix: attempt to make predict clicks for alignment solver more accurate
Browse files Browse the repository at this point in the history
  • Loading branch information
My-Name-Is-Jeff committed Jan 19, 2024
1 parent d595899 commit fd694e4
Showing 1 changed file with 90 additions and 61 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,13 @@ import gg.skytils.skytilsmod.utils.RenderUtil
import gg.skytils.skytilsmod.utils.SuperSecretSettings
import gg.skytils.skytilsmod.utils.Utils
import gg.skytils.skytilsmod.utils.middleVec
import net.minecraft.entity.DataWatcher.WatchableObject
import net.minecraft.entity.item.EntityItemFrame
import net.minecraft.init.Blocks
import net.minecraft.init.Items
import net.minecraft.item.Item
import net.minecraft.network.play.client.C02PacketUseEntity
import net.minecraft.network.play.server.S1CPacketEntityMetadata
import net.minecraft.util.BlockPos
import net.minecraft.util.EnumFacing
import net.minecraftforge.client.event.RenderWorldLastEvent
Expand All @@ -42,6 +44,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import java.awt.Color
import java.awt.Point
import java.util.*
import kotlin.collections.HashMap
import kotlin.random.Random

object AlignmentTaskSolver {
Expand All @@ -60,86 +63,107 @@ object AlignmentTaskSolver {
private val grid = LinkedHashSet<MazeSpace>()
private val directionSet = HashMap<Point, Int>()
private val clicks = HashMap<BlockPos, Int>()
private val pendingClicks = HashMap<BlockPos, Int>()

init {
tickTimer(20, repeats = true) {
if (!Skytils.config.alignmentTerminalSolver || !Utils.inDungeons || mc.thePlayer == null || (!SuperSecretSettings.azooPuzzoo && (DungeonTimer.phase2ClearTime == -1L || DungeonTimer.phase3ClearTime != -1L) || !Utils.equalsOneOf(
DungeonFeatures.dungeonFloor,
"F7", "M7"
))
) return@tickTimer
if (mc.thePlayer.getDistanceSqToCenter(topLeft) <= 25 * 25) {
if (grid.size < 25) {
@Suppress("UNCHECKED_CAST")
val frames = mc.theWorld.loadedEntityList.filter {
it is EntityItemFrame && box.contains(it.position) && it.displayedItem != null && Utils.equalsOneOf(
it.displayedItem.item,
Items.arrow,
Item.getItemFromBlock(Blocks.wool)
)
} as List<EntityItemFrame>
if (frames.isNotEmpty()) {
for ((i, pos) in box.withIndex()) {
val coords = Point(i % 5, i / 5)
val frame = frames.find { it.position == pos }
val type = frame?.displayedItem?.let {
when (it.item) {
Items.arrow -> SpaceType.PATH
Item.getItemFromBlock(Blocks.wool) -> when (it.itemDamage) {
5 -> SpaceType.STARTER
14 -> SpaceType.END
else -> SpaceType.PATH
}
else -> SpaceType.EMPTY
computeLayout()
}
tickTimer(1, repeats = true) {
computeTurns()
}
}

fun computeLayout() {
if (!Skytils.config.alignmentTerminalSolver || !Utils.inDungeons || mc.thePlayer == null || (!SuperSecretSettings.azooPuzzoo && (DungeonTimer.phase2ClearTime == -1L || DungeonTimer.phase3ClearTime != -1L) || !Utils.equalsOneOf(
DungeonFeatures.dungeonFloor,
"F7", "M7"
))
) return
if (mc.thePlayer.getDistanceSqToCenter(topLeft) <= 25 * 25) {
if (grid.size < 25) {
@Suppress("UNCHECKED_CAST")
val frames = mc.theWorld.loadedEntityList.filter {
it is EntityItemFrame && box.contains(it.position) && it.displayedItem != null && Utils.equalsOneOf(
it.displayedItem.item,
Items.arrow,
Item.getItemFromBlock(Blocks.wool)
)
} as List<EntityItemFrame>
if (frames.isNotEmpty()) {
for ((i, pos) in box.withIndex()) {
val coords = Point(i % 5, i / 5)
val frame = frames.find { it.position == pos }
val type = frame?.displayedItem?.let {
when (it.item) {
Items.arrow -> SpaceType.PATH
Item.getItemFromBlock(Blocks.wool) -> when (it.itemDamage) {
5 -> SpaceType.STARTER
14 -> SpaceType.END
else -> SpaceType.PATH
}
} ?: SpaceType.EMPTY
grid.add(MazeSpace(frame?.hangingPosition, type, coords))
}
else -> SpaceType.EMPTY
}
} ?: SpaceType.EMPTY
grid.add(MazeSpace(frame?.hangingPosition, type, coords))
}
} else if (directionSet.isEmpty()) {
val startPositions = grid.filter { it.type == SpaceType.STARTER }
val endPositions = grid.filter { it.type == SpaceType.END }
val layout = layout
}
} else if (directionSet.isEmpty()) {
val startPositions = grid.filter { it.type == SpaceType.STARTER }
val endPositions = grid.filter { it.type == SpaceType.END }
val layout = layout

for (start in startPositions) {
for (end in endPositions) {
val pointMap = solve(layout, start.coords, end.coords)
for (move in convertPointMapToMoves(pointMap)) {
directionSet[move.point] = move.directionNum
}
for (start in startPositions) {
for (end in endPositions) {
val pointMap = solve(layout, start.coords, end.coords)
for (move in convertPointMapToMoves(pointMap)) {
directionSet[move.point] = move.directionNum
}
}
}
}
}
tickTimer(5, repeats = true) {
if (mc.theWorld == null) return@tickTimer
for (space in grid) {
if (space.type != SpaceType.PATH || space.framePos == null) continue
val frame =
(mc.theWorld.loadedEntityList.find { it is EntityItemFrame && it.hangingPosition == space.framePos }
?: continue) as EntityItemFrame
val neededClicks = if (!SuperSecretSettings.bennettArthur) (directionSet.getOrElse(space.coords) { 0 } - frame.rotation + 8) % 8 else Random.nextInt(8)
clicks[space.framePos] = neededClicks
}
}

fun computeTurns() {
if (mc.theWorld == null || directionSet.isEmpty()) return
for (space in grid) {
if (space.type != SpaceType.PATH || space.framePos == null) continue
val frame =
(mc.theWorld.loadedEntityList.find { it is EntityItemFrame && it.hangingPosition == space.framePos }
?: continue) as EntityItemFrame
val neededClicks = if (!SuperSecretSettings.bennettArthur) (directionSet.getOrElse(space.coords) { 0 } - frame.rotation + 8) % 8 else Random.nextInt(8)
clicks[space.framePos] = neededClicks
}
}

@SubscribeEvent
fun onPacket(event: PacketEvent) {
if (directionSet.isNotEmpty() && Skytils.config.alignmentTerminalSolver && Skytils.config.blockIncorrectTerminalClicks) {
if (event.packet is C02PacketUseEntity && event.packet.action == C02PacketUseEntity.Action.INTERACT) {
if (directionSet.isNotEmpty() && Skytils.config.alignmentTerminalSolver) {
if ((Skytils.config.blockIncorrectTerminalClicks || Skytils.config.predictAlignmentClicks) && event.packet is C02PacketUseEntity && event.packet.action == C02PacketUseEntity.Action.INTERACT) {
val entity = event.packet.getEntityFromWorld(mc.theWorld) ?: return
if (entity !is EntityItemFrame) return
val needed = clicks[entity.hangingPosition] ?: return
if (needed == 0) event.isCanceled = true
else {
val blockBehind = mc.theWorld.getBlockState(entity.hangingPosition.offset(entity.facingDirection.opposite))
if (blockBehind.block == Blocks.sea_lantern) event.isCanceled = true
val pos = entity.hangingPosition
val clicks = clicks[pos]
val pending = pendingClicks[pos] ?: 0

if (Skytils.config.blockIncorrectTerminalClicks) {
if (clicks == null || clicks - pending != 0) {
val blockBehind = mc.theWorld.getBlockState(pos.offset(entity.facingDirection.opposite))
if (blockBehind.block == Blocks.sea_lantern) event.isCanceled = true
} else event.isCanceled = true
}

if (!event.isCanceled && Skytils.config.predictAlignmentClicks) {
clicks[entity.hangingPosition] = (needed - 1 + 8) % 8
pendingClicks.compute(pos) { _, v -> v?.inc() ?: 1 }
}
} else if (Skytils.config.predictAlignmentClicks && event.packet is S1CPacketEntityMetadata) {
val entity = mc.theWorld?.getEntityByID(event.packet.entityId) ?: return
if (entity is EntityItemFrame && entity.hangingPosition in pendingClicks) {
val newRot = event.packet.func_149376_c().find { it.dataValueId == 9 && it.objectType == 0 }?.`object` as? Byte ?: return
val currentRot = entity.rotation
val delta = getTurnsNeeded(currentRot, newRot.toInt())
pendingClicks.computeIfPresent(entity.hangingPosition) { _, v -> getTurnsNeeded(v, delta) }
}
}
}
Expand All @@ -152,17 +176,22 @@ object AlignmentTaskSolver {
if (space.type != SpaceType.PATH || space.framePos == null) continue
val neededClicks = clicks[space.framePos] ?: continue
if (neededClicks == 0) continue
val pending = pendingClicks[space.framePos] ?: 0

RenderUtil.drawLabel(
space.framePos.middleVec(),
neededClicks.toString(),
Color.RED,
if (pending > 0) "${neededClicks - pending} (${neededClicks})" else "$neededClicks",
if (pending > 0 && neededClicks - pending == 0) Color.GREEN else Color.RED,
event.partialTicks,
matrixStack
)
}
}

fun getTurnsNeeded(current: Int, needed: Int): Int {
return (needed - current + 8) % 8
}

@SubscribeEvent
fun onWorldLoad(event: WorldEvent.Load) {
grid.clear()
Expand Down

0 comments on commit fd694e4

Please sign in to comment.