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

Feature: Block Opening /cf Without Hot Chocolate Mixin #3024

Open
wants to merge 23 commits into
base: beta
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
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 @@ -200,6 +200,12 @@ public class ChocolateFactoryConfig {
@FeatureToggle
public boolean boosterCookieRequirement = false;

@Expose
@ConfigOption(name = "Hot Chocolate Mixin", desc = "Blocks running /cf without §9Hot Chocolate Mixin §7active.")
@ConfigEditorBoolean
@FeatureToggle
public boolean hotChocolateMixinRequirement = false;

@Expose
@ConfigOption(name = "Stray Tracker", desc = "Track stray rabbits found in the Chocolate Factory menu.")
@ConfigEditorBoolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,9 @@ public static class HitmanStatsStorage {

@Expose
public HitmanStatsStorage hitmanStats = new HitmanStatsStorage();

@Expose
public SimpleTimeMark hotChocolateMixinExpiry = SimpleTimeMarkFarPast();
}

@Expose
Expand Down Expand Up @@ -303,6 +306,9 @@ public static class BitsStorage {
public SimpleTimeMark boosterCookieExpiryTime = null;
}

@Expose
public SimpleTimeMark godPotExpiryTime = SimpleTimeMarkFarPast();
Copy link
Owner

Choose a reason for hiding this comment

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

this doesnt look right

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Could you elaborate more please

Copy link
Owner

Choose a reason for hiding this comment

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

Have not looked at this in IntelliJ. But this doesn't look like a valid java line. What is the default value of this variable?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

image

Copy link
Owner

Choose a reason for hiding this comment

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

Method naming does not follow Java convention. Methods typically start with a lowercase letter, e.g. simpleTimeMarkFarPast().

The method name is not very descriptive. Consider something like getFarPastSimpleTimeMark() to clarify its intent.

If GenericWrapper and getIt() are needed, consider renaming getIt() to something more meaningful.

Copy link
Owner

Choose a reason for hiding this comment

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

Also why is this wrapper needed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is not a new thing, this has existed since June.
image

I'm fine with changing it if you really want me to but this is not a new thing. And the wrapper is needed because you can't assign a Kotlin class value to a Java object unless it's got a static definition, which SimpleTimeMark.farPast() is not. It's the same reason that right below that, we have a wrapper for Duration - they're composed types that simplify to long, making them easy to use in the storage, but initial values have to be wrapped.

Copy link
Owner

Choose a reason for hiding this comment

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

can we use new SimpleTimeMark(0) instead then? really not a fan of this wrapping, and the function name breaks java conversations. so sad i have not noticed this before

Copy link
Contributor Author

Choose a reason for hiding this comment

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

image

No we cannot.


@Expose
public Map<LorenzVec, MinionConfig> minions = new HashMap<>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,30 @@ import at.hannibal2.skyhanni.data.IslandGraphs
import at.hannibal2.skyhanni.data.IslandType
import at.hannibal2.skyhanni.data.ProfileStorageData
import at.hannibal2.skyhanni.events.GuiContainerEvent
import at.hannibal2.skyhanni.events.InventoryUpdatedEvent
import at.hannibal2.skyhanni.events.LorenzChatEvent
import at.hannibal2.skyhanni.events.MessageSendToServerEvent
import at.hannibal2.skyhanni.events.TablistFooterUpdateEvent
import at.hannibal2.skyhanni.features.event.hoppity.MythicRabbitPetWarning
import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule
import at.hannibal2.skyhanni.utils.ChatUtils
import at.hannibal2.skyhanni.utils.HypixelCommands
import at.hannibal2.skyhanni.utils.ItemUtils.getLore
import at.hannibal2.skyhanni.utils.LorenzUtils
import at.hannibal2.skyhanni.utils.LorenzVec
import at.hannibal2.skyhanni.utils.RegexUtils.firstMatcher
import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher
import at.hannibal2.skyhanni.utils.RegexUtils.matches
import at.hannibal2.skyhanni.utils.SimpleTimeMark
import at.hannibal2.skyhanni.utils.TimeUtils
import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import kotlin.time.Duration.Companion.seconds

@SkyHanniModule
object ChocolateFactoryBlockOpen {
DavidArthurCole marked this conversation as resolved.
Show resolved Hide resolved
private val config get() = SkyHanniMod.feature.inventory.chocolateFactory
private val profileStorage get() = ProfileStorageData.profileSpecific?.bits
private val profileStorage get() = ProfileStorageData.profileSpecific

/**
* REGEX-TEST: /cf
Expand All @@ -45,6 +52,65 @@ object ChocolateFactoryBlockOpen {
"§6(?:Open )?Chocolate Factory",
)

/**
* REGEX-TEST: §a§lSCHLURP! §r§eThe effects of the §r§9Hot Chocolate Mixin §r§ehave been extended by §r§986h 24m§r§e!
* They will pause if your §r§cGod Potion §r§eexpires.
*/
private val hotChocolateMixinConsumePattern by RepoPattern.pattern(
"stats.chatpatterns.hotchocolatemixinconsume",
"(?:§.)+.*(?:§.)+Hot Chocolate Mixin ?(?:§.)+.*extended by (?:§.)+(?<time>[dhms0-9 ]*)(?:§.)+!.*",
)

/**
* REGEX-TEST: §a§lGULP! §r§eThe §r§cGod Potion §r§egrants you powers for §r§928h 48m§r§e!
* REGEX-TEST: §a§lSIP! §r§eThe §r§cGod Potion §r§egrants you powers for §r§928h 48m§r§e!
* REGEX-TEST: §a§lSLURP! §r§eThe §r§cGod Potion §r§egrants you powers for §r§928h 48m§r§e!
*/
private val godPotConsumePattern by RepoPattern.pattern(
"stats.chatpatterns.godpotconsume",
"(?:§.)+.*(?:§.)+God Potion ?(?:§.)+.*grants you powers for (?:§.)+(?<time>[dhms0-9 ]*)(?:§.)+!.*",
)

/**
* REGEX-TEST: §cGod Potion§f: 4d
*/
private val godPotTabPattern by RepoPattern.pattern(
"stats.tabpatterns.godpot",
"(?:§.)*God Potion(?:§.)*: (?:§.)*(?<time>[dhms0-9 ]+)(?:§.)*",
)

/**
* REGEX-TEST: (1/2) Active Effects
*/
private val effectsInventoryPattern by RepoPattern.pattern(
"inventory.effects",
"(?:§.)?(?:[(\\d\\/)]* )?Active Effects",
)

/**
* REGEX-TEST: §aFilter
*/
private val filterPattern by RepoPattern.pattern(
"inventory.effects.filter",
"§aFilter",
)

/**
* REGEX-TEST: §b▶ God Potion Effects
*/
private val godPotEffectsFilterSelectPattern by RepoPattern.pattern(
"inventory.effects.filtergodpotselect",
"§b▶ God Potion Effects",
)

/**
* REGEX-TEST: §7Remaining: §f105:01:34
*/
private val potionRemainingLoreTimerPattern by RepoPattern.pattern(
"inventory.effects.effecttimeleft",
"§7Remaining: §f(?<time>[\\d:]+)",
)

private var commandSentTimer = SimpleTimeMark.farPast()

@SubscribeEvent
Expand All @@ -56,6 +122,61 @@ object ChocolateFactoryBlockOpen {
if (checkIsBlocked()) event.cancel()
}

@SubscribeEvent
fun onChat(event: LorenzChatEvent) {
if (!LorenzUtils.inSkyBlock) return
hotChocolateMixinConsumePattern.matchMatcher(event.message) {
val durationAdded = TimeUtils.getDuration(group("time"))
val asTimeMark = SimpleTimeMark.now().plus(durationAdded)
val existingValue = profileStorage?.chocolateFactory?.hotChocolateMixinExpiry
profileStorage?.chocolateFactory?.hotChocolateMixinExpiry =
existingValue?.let { it + durationAdded } ?: asTimeMark
}
godPotConsumePattern.matchMatcher(event.message) {
val durationAdded = TimeUtils.getDuration(group("time"))
val asTimeMark = SimpleTimeMark.now().plus(durationAdded)
val existingValue = profileStorage?.godPotExpiryTime
profileStorage?.godPotExpiryTime = existingValue?.let { it + durationAdded } ?: asTimeMark
}
}

@SubscribeEvent
fun onTabUpdate(event: TablistFooterUpdateEvent) {
if (!LorenzUtils.inSkyBlock) return
for (line in event.footer.split("\n")) {
godPotTabPattern.matchMatcher(line) {
val expiryDuration = TimeUtils.getDuration(group("time"))
val expiryTime = SimpleTimeMark.now().plus(expiryDuration)
profileStorage?.godPotExpiryTime = expiryTime
}
}
}

@SubscribeEvent
fun onInventoryUpdated(event: InventoryUpdatedEvent) {
if (!LorenzUtils.inSkyBlock || !event.isGodPotEffectsFilterSelect()) return

val potionLore = event.inventoryItems[10]?.getLore() ?: run {
// No active god pot effects found, reset the expiry time
profileStorage?.godPotExpiryTime = SimpleTimeMark.farPast()
return
}

val expiryDuration = potionRemainingLoreTimerPattern.firstMatcher(potionLore) {
TimeUtils.getDuration(group("time"))
} ?: return

profileStorage?.godPotExpiryTime = SimpleTimeMark.now() + expiryDuration
}

private fun InventoryUpdatedEvent.isGodPotEffectsFilterSelect(): Boolean =
effectsInventoryPattern.matches(this.inventoryName) &&
this.inventoryItems.values.firstOrNull {
filterPattern.matches(it.displayName)
}?.getLore()?.any {
godPotEffectsFilterSelectPattern.matches(it)
} ?: false

@SubscribeEvent
fun onCommandSend(event: MessageSendToServerEvent) {
if (!LorenzUtils.inSkyBlock) return
Expand All @@ -75,19 +196,20 @@ object ChocolateFactoryBlockOpen {
SUCCESS,
FAIL_NO_RABBIT,
FAIL_NO_BOOSTER_COOKIE,
FAIL_NO_MIXIN,
}

private fun tryBlock(): TryBlockResult {
if (config.mythicRabbitRequirement && !MythicRabbitPetWarning.correctPet()) {
return if (config.mythicRabbitRequirement && !MythicRabbitPetWarning.correctPet()) {
ChatUtils.clickToActionOrDisable(
"§cBlocked opening the Chocolate Factory without a §dMythic Rabbit Pet §cequipped!",
config::mythicRabbitRequirement,
actionName = "open pets menu",
action = { HypixelCommands.pet() },
)
return TryBlockResult.FAIL_NO_RABBIT
TryBlockResult.FAIL_NO_RABBIT
} else if (config.boosterCookieRequirement) {
profileStorage?.boosterCookieExpiryTime?.let {
profileStorage?.bits?.boosterCookieExpiryTime?.let {
if (it.timeUntil() > 0.seconds) return TryBlockResult.SUCCESS
ChatUtils.clickToActionOrDisable(
"§cBlocked opening the Chocolate Factory without a §dBooster Cookie §cactive!",
Expand All @@ -100,9 +222,30 @@ object ChocolateFactoryBlockOpen {
}
},
)
return TryBlockResult.FAIL_NO_BOOSTER_COOKIE
}
}
return TryBlockResult.SUCCESS
TryBlockResult.FAIL_NO_BOOSTER_COOKIE
} ?: TryBlockResult.SUCCESS
} else if (config.hotChocolateMixinRequirement) {
val mixinExpiryTime = profileStorage?.chocolateFactory?.hotChocolateMixinExpiry ?: SimpleTimeMark.farPast()
val godPotExpiryTime = profileStorage?.godPotExpiryTime ?: SimpleTimeMark.farPast()
if (mixinExpiryTime.isInPast()) {
ChatUtils.clickToActionOrDisable(
"§cBlocked opening the Chocolate Factory without a §dHot Chocolate Mix §cactive! " +
"§7You may need to open §c/effects §7to refresh mixin status.",
config::hotChocolateMixinRequirement,
actionName = "search AH for mixin",
action = { HypixelCommands.auctionSearch("hot chocolate mixin") },
)
TryBlockResult.FAIL_NO_MIXIN
} else if (godPotExpiryTime.isInPast()) {
ChatUtils.clickToActionOrDisable(
"§cBlocked opening the Chocolate Factory without a §dGod Potion §cactive! " +
"§7You may need to open §c/effects §7and cycle the §aFilter §7to §bGod Potion Effects §7to refresh potion status.",
config::hotChocolateMixinRequirement,
actionName = "search AH for god potion",
action = { HypixelCommands.auctionSearch("god potion") },
)
TryBlockResult.FAIL_NO_MIXIN
} else TryBlockResult.SUCCESS
} else TryBlockResult.SUCCESS
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import at.hannibal2.skyhanni.utils.ItemUtils.name
import at.hannibal2.skyhanni.utils.LorenzUtils
import at.hannibal2.skyhanni.utils.RegexUtils.matchMatcher
import at.hannibal2.skyhanni.utils.RenderUtils.renderStrings
import at.hannibal2.skyhanni.utils.SimpleTimeMark
import at.hannibal2.skyhanni.utils.SoundUtils.playPlingSound
import at.hannibal2.skyhanni.utils.TimeUnit
import at.hannibal2.skyhanni.utils.TimeUtils
Expand All @@ -31,6 +32,7 @@ import at.hannibal2.skyhanni.utils.Timer
import at.hannibal2.skyhanni.utils.repopatterns.RepoPattern
import net.minecraft.network.play.server.S47PacketPlayerListHeaderFooter
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent
import kotlin.time.Duration
import kotlin.time.Duration.Companion.hours
import kotlin.time.Duration.Companion.minutes
import kotlin.time.Duration.Companion.seconds
Expand Down Expand Up @@ -229,11 +231,19 @@ object NonGodPotEffectDisplay {
}
effectDuration[effect] = Timer(duration)
update()
effect.updateCfBlock(duration)
}
}
}
}

private fun NonGodPotEffect.updateCfBlock(duration: Duration) {
DavidArthurCole marked this conversation as resolved.
Show resolved Hide resolved
if (this != NonGodPotEffect.HOT_CHOCOLATE) return

val chocolateFactory = ProfileStorageData.profileSpecific?.chocolateFactory ?: return
chocolateFactory.hotChocolateMixinExpiry = SimpleTimeMark.now() + duration
}

// TODO use TablistFooterUpdateEvent instead
@HandleEvent(onlyOnSkyblock = true, priority = HandleEvent.LOW, receiveCancelled = true)
fun onPacketReceive(event: PacketReceivedEvent) {
Expand All @@ -256,6 +266,7 @@ object NonGodPotEffectDisplay {
val duration = TimeUtils.getDuration(string.split("§f")[1])
effectDuration[effect] = Timer(duration)
update()
effect.updateCfBlock(duration)
} catch (e: IndexOutOfBoundsException) {
ChatUtils.debug("Error while reading non god pot effects from tab list! line: '$line'")
}
Expand Down
Loading