@@ -30,7 +30,6 @@ import com.lambda.graphics.renderer.gui.font.FontRenderer
3030import com.lambda.graphics.renderer.gui.font.LambdaEmoji
3131import com.lambda.graphics.renderer.gui.font.LambdaFont
3232import com.lambda.interaction.RotationManager.rotate
33- import com.lambda.interaction.rotation.Rotation.Companion.rotationTo
3433import com.lambda.interaction.rotation.RotationRequest
3534import com.lambda.module.Module
3635import com.lambda.module.tag.ModuleTag
@@ -43,14 +42,14 @@ import com.lambda.util.math.*
4342import com.lambda.util.math.MathUtils.ceilToInt
4443import com.lambda.util.math.MathUtils.roundToStep
4544import com.lambda.util.world.fastEntitySearch
46- import com.lambda.util.world.raycast.RayCastMask
47- import com.lambda.util.world.raycast.RayCastUtils.blockResult
4845import net.minecraft.block.Blocks
4946import net.minecraft.entity.Entity
5047import net.minecraft.entity.LivingEntity
5148import net.minecraft.entity.decoration.EndCrystalEntity
49+ import net.minecraft.network.packet.c2s.play.PlayerInteractBlockC2SPacket
5250import net.minecraft.network.packet.c2s.play.PlayerInteractEntityC2SPacket
5351import net.minecraft.util.Hand
52+ import net.minecraft.util.hit.BlockHitResult
5453import net.minecraft.util.math.*
5554import kotlin.concurrent.fixedRateTimer
5655import kotlin.math.max
@@ -83,7 +82,6 @@ object CrystalAura : Module(
8382 /* Prediction */
8483 private val prediction by setting(" Prediction" , PredictionMode .None ) { page == Page .Prediction }
8584 private val predictionPackets by setting(" Prediction Packets" , 1 , 1 .. 20 ) { page == Page .Prediction && prediction.isActive }
86- private val postPlace by setting(" Post Place" , false ) { page == Page .Prediction && prediction.isActive && predictionPackets > 1 }
8785 private val packetLifetime by setting(" Packet Lifetime" , 300L , 50L .. 1000L ) { page == Page .Prediction && prediction.onPlace }
8886
8987 /* Targeting */
@@ -105,7 +103,6 @@ object CrystalAura : Module(
105103 private val placeTimer = SimpleTimer ()
106104 private val explodeTimer = SimpleTimer ()
107105
108- // ToDo: pending prediction decay queue (crystalId s)
109106 private val predictionTimer = SimpleTimer ()
110107 private var lastEntityId = 0
111108
@@ -171,10 +168,10 @@ object CrystalAura : Module(
171168 if (getBestOpportunity() != opportunity) return @listen
172169
173170 repeat(predictionPackets) {
174- val offset = if (postPlace) 0 else it
171+ val offset = if (prediction. postPlace) 0 else it
175172 explodeInternal(lastEntityId + offset)
176173
177- if (postPlace) {
174+ if (prediction. postPlace) {
178175 placeInternal(pos, Hand .MAIN_HAND )
179176 lastEntityId++
180177 placeTimer.reset()
@@ -187,7 +184,6 @@ object CrystalAura : Module(
187184 val pos = crystal.baseBlockPos
188185
189186 blueprint[pos]?.crystal = null
190- // pendingExplosions.remove(blockPos)
191187 }
192188
193189 onEnable {
@@ -211,26 +207,7 @@ object CrystalAura : Module(
211207 // Choosing and running the best opportunity
212208 val best = getBestOpportunity() ? : return
213209
214- if (! best.blocked) {
215- best.explode()
216- best.place()
217- return
218- }
219-
220- val mutableBlockPos = BlockPos .Mutable ()
221-
222- // Break crystals nearby if the best crystal placement is blocked by other crystals
223- collidingOffsets.mapNotNull {
224- mutableBlockPos.set(
225- best.blockPos.x + it.x,
226- best.blockPos.y + it.y,
227- best.blockPos.z + it.z
228- )
229-
230- blueprint[mutableBlockPos]
231- }.filter { it.hasCrystal }.maxByOrNull { it.priority }?.explode()
232-
233- best.place()
210+ tickInteraction(best)
234211 }
235212
236213 private fun SafeContext.buildBlueprint (target : LivingEntity ) = updateTimer.runIfPassed(updateDelay) {
@@ -335,8 +312,6 @@ object CrystalAura : Module(
335312 blueprint[it.blockPos] = it
336313 }
337314
338- // ToDo: force place
339-
340315 // Associate by actions
341316 blueprint.values.forEach { opportunity ->
342317 actionMap.getOrPut(opportunity.actionType, ::mutableListOf) + = opportunity
@@ -347,6 +322,54 @@ object CrystalAura : Module(
347322 }
348323 }
349324
325+ private fun tickInteraction (best : Opportunity ) {
326+ if (! best.blocked) {
327+ best.explode()
328+ best.place()
329+ return
330+ }
331+
332+ val mutableBlockPos = BlockPos .Mutable ()
333+
334+ // Break crystals nearby if the best crystal placement is blocked by other crystals
335+ collidingOffsets.mapNotNull {
336+ mutableBlockPos.set(
337+ best.blockPos.x + it.x,
338+ best.blockPos.y + it.y,
339+ best.blockPos.z + it.z
340+ )
341+
342+ blueprint[mutableBlockPos]
343+ }.filter { it.hasCrystal }.maxByOrNull { it.priority }?.explode()
344+
345+ best.place()
346+ }
347+
348+ private fun getBestOpportunity () =
349+ actionMap[actionType]?.maxByOrNull {
350+ it.priority
351+ }
352+
353+ private fun SafeContext.placeInternal (blockPos : BlockPos , hand : Hand ) {
354+ connection.sendPacket(
355+ PlayerInteractBlockC2SPacket (
356+ hand, BlockHitResult (blockPos.crystalPosition, Direction .UP , blockPos, false ), 0
357+ )
358+ )
359+
360+ player.swingHand(hand)
361+ }
362+
363+ private fun SafeContext.explodeInternal (id : Int ) {
364+ connection.sendPacket(
365+ PlayerInteractEntityC2SPacket (
366+ id, player.isSneaking, PlayerInteractEntityC2SPacket .ATTACK
367+ )
368+ )
369+
370+ player.swingHand(Hand .MAIN_HAND )
371+ }
372+
350373 /* *
351374 * Represents the damage information resulting from placing an end crystal on a given [blockPos]
352375 * and causing an explosion that targets current target entity.
@@ -366,7 +389,7 @@ object CrystalAura : Module(
366389 ) {
367390 var actionType = ActionType .Normal
368391 val priority = priorityMode.factor(target, self)
369- val hasCrystal = crystal != null
392+ val hasCrystal get() = crystal != null
370393
371394 /* *
372395 * Places the crystal on [blockPos]
@@ -382,10 +405,19 @@ object CrystalAura : Module(
382405 run {
383406 if (! prediction.onPlace || predictionTimer.timePassed(packetLifetime)) return @run
384407
408+ val last = lastEntityId
409+
385410 repeat(predictionPackets) {
386- if (it != 0 ) placeInternal(blockPos, Hand .MAIN_HAND )
411+ if (it != 0 && prediction.postPlace) {
412+ placeInternal(blockPos, Hand .MAIN_HAND )
413+ }
387414 explodeInternal(++ lastEntityId)
388415 }
416+
417+ if (prediction == PredictionMode .StepDeferred ) {
418+ lastEntityId = last + 1
419+ crystal = null
420+ }
389421 }
390422
391423 placeTimer.reset()
@@ -434,33 +466,6 @@ object CrystalAura : Module(
434466 }
435467 }
436468
437- private fun getBestOpportunity () =
438- actionMap[actionType]?.maxByOrNull {
439- it.priority
440- }
441-
442- private fun SafeContext.placeInternal (blockPos : BlockPos , hand : Hand ): Boolean {
443- val angles = player.eyePos.rotationTo(blockPos.crystalPosition)
444- val cast = angles.rayCast(placeRange, mask = RayCastMask .BLOCK )?.blockResult ? : return false
445- if (cast.blockPos != blockPos) return false
446-
447- val actionResult = interaction.interactBlock(player, hand, cast)
448- if (! actionResult.isAccepted || ! actionResult.shouldSwingHand()) return false
449-
450- player.swingHand(hand)
451- return true
452- }
453-
454- private fun SafeContext.explodeInternal (id : Int ) {
455- connection.sendPacket(
456- PlayerInteractEntityC2SPacket (
457- id, player.isSneaking, PlayerInteractEntityC2SPacket .ATTACK
458- )
459- )
460-
461- player.swingHand(Hand .MAIN_HAND )
462- }
463-
464469 private val EndCrystalEntity .baseBlockPos get() =
465470 (pos - Vec3d (0.0 , 0.5 , 0.0 )).flooredBlockPos
466471
@@ -495,10 +500,18 @@ object CrystalAura : Module(
495500 Ticked
496501 }
497502
498- private enum class PredictionMode (val onPacket : Boolean , val onPlace : Boolean ) {
499- None (false , false ),
500- Packet (true , false ),
501- Deferred (false , true );
503+ private enum class PredictionMode (val onPacket : Boolean , val onPlace : Boolean , val postPlace : Boolean ) {
504+ // Prediction disable
505+ None (false , false , false ),
506+
507+ // Predict on packet receive
508+ SemiPacket (true , false , false ),
509+ Packet (true , false , true ),
510+
511+ // Predict on place
512+ SemiDeferred (false , true , false ),
513+ Deferred (false , true , true ),
514+ StepDeferred (false , true , false ); // the best method
502515
503516 val isActive = onPacket || onPlace
504517 }
@@ -512,6 +525,7 @@ object CrystalAura : Module(
512525 })
513526 }
514527
528+ // ToDo: implement actions
515529 private enum class ActionType (val priority : Int ) {
516530 Normal (0 ),
517531 ForcePlace (1 ),
0 commit comments