diff options
author | J10a1n15 <45315647+j10a1n15@users.noreply.github.com> | 2024-10-02 16:45:32 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-10-02 16:45:32 +0200 |
commit | 140219f75b361fce1d9dec265f78b70202d06d3b (patch) | |
tree | ea8dd8ae2427ebb6a74e42d6267dd7847ad858d6 | |
parent | ab7b3269eb8a5b3869331fa94663b1ddfebe80b2 (diff) | |
download | skyhanni-140219f75b361fce1d9dec265f78b70202d06d3b.tar.gz skyhanni-140219f75b361fce1d9dec265f78b70202d06d3b.tar.bz2 skyhanni-140219f75b361fce1d9dec265f78b70202d06d3b.zip |
Backend: Alert Clock Offsets (#2623)
Co-authored-by: hannibal2 <24389977+hannibal00212@users.noreply.github.com>
Co-authored-by: CalMWolfs <cwolfson58@gmail.com>
4 files changed, 147 insertions, 1 deletions
diff --git a/build.gradle.kts b/build.gradle.kts index 71a882ac9..3e3b002ff 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -171,6 +171,9 @@ dependencies { implementation("net.hypixel:mod-api:0.3.1") + // getting clock offset + shadowImpl("commons-net:commons-net:3.8.0") + detektPlugins("org.notenoughupdates:detektrules:1.0.0") detektPlugins(project(":detekt")) detektPlugins("io.gitlab.arturbosch.detekt:detekt-formatting:1.23.7") @@ -279,6 +282,7 @@ tasks.shadowJar { relocate("io.github.notenoughupdates.moulconfig", "at.hannibal2.skyhanni.deps.moulconfig") relocate("moe.nea.libautoupdate", "at.hannibal2.skyhanni.deps.libautoupdate") relocate("com.jagrosh.discordipc", "at.hannibal2.skyhanni.deps.discordipc") + relocate("org.apache.commons.net", "at.hannibal2.skyhanni.deps.commons.net") } tasks.jar { archiveClassifier.set("nodeps") diff --git a/src/main/java/at/hannibal2/skyhanni/config/features/misc/MiscConfig.java b/src/main/java/at/hannibal2/skyhanni/config/features/misc/MiscConfig.java index 9d503c398..df1ae1da5 100644 --- a/src/main/java/at/hannibal2/skyhanni/config/features/misc/MiscConfig.java +++ b/src/main/java/at/hannibal2/skyhanni/config/features/misc/MiscConfig.java @@ -334,4 +334,13 @@ public class MiscConfig { @ConfigEditorBoolean @FeatureToggle public boolean userluckEnabled = true; + + @Expose + @ConfigOption(name = "Computer Time Offset Warning", + desc = "Sends a Chat Warning if your computer time is not synchronized with the actual time.\n" + + "§cMaking sure your computer time is correct is important for SkyHanni to display times correctly." + ) + @ConfigEditorBoolean + @FeatureToggle + public boolean warnAboutPcTimeOffset = true; } diff --git a/src/main/java/at/hannibal2/skyhanni/utils/ComputerTimeOffset.kt b/src/main/java/at/hannibal2/skyhanni/utils/ComputerTimeOffset.kt new file mode 100644 index 000000000..83ea15ecc --- /dev/null +++ b/src/main/java/at/hannibal2/skyhanni/utils/ComputerTimeOffset.kt @@ -0,0 +1,122 @@ +package at.hannibal2.skyhanni.utils + +import at.hannibal2.skyhanni.SkyHanniMod +import at.hannibal2.skyhanni.events.DebugDataCollectEvent +import at.hannibal2.skyhanni.events.ProfileJoinEvent +import at.hannibal2.skyhanni.skyhannimodule.SkyHanniModule +import at.hannibal2.skyhanni.test.command.ErrorManager +import at.hannibal2.skyhanni.utils.TimeUtils.format +import kotlinx.coroutines.launch +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent +import org.apache.commons.net.ntp.NTPUDPClient +import java.net.InetAddress +import kotlin.concurrent.thread +import kotlin.time.Duration +import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.seconds + +@SkyHanniModule +object ComputerTimeOffset { + private var offsetMillis: Duration? = null + + private val config get() = SkyHanniMod.feature.misc.warnAboutPcTimeOffset + + private val offsetFixLinks by lazy { + when { + OSUtils.isWindows -> { + "https://support.microsoft.com/en-us/windows/how-to-set-your-time-and-time-zone-dfaa7122-479f-5b98-2a7b-fa0b6e01b261" + } + + OSUtils.isLinux -> "https://unix.stackexchange.com/a/79116" + OSUtils.isMac -> "https://support.apple.com/guide/mac-help/set-the-date-and-time-automatically-mchlp2996/mac" + else -> null + } + } + + init { + thread { + while (true) { + Thread.sleep(1000) + detectTimeChange() + } + } + } + + private fun checkOffset() { + val wasOffsetBefore = (offsetMillis?.absoluteValue ?: 0.seconds) > 5.seconds + SkyHanniMod.coroutineScope.launch { + offsetMillis = getNtpOffset("time.google.com") + offsetMillis?.let { + tryDisplayOffset(wasOffsetBefore) + } + } + } + + private fun getNtpOffset(ntpServer: String): Duration? = try { + val client = NTPUDPClient() + val address = InetAddress.getByName(ntpServer) + val timeInfo = client.getTime(address) + + timeInfo.computeDetails() + timeInfo.offset.milliseconds + } catch (e: Exception) { + if (LorenzUtils.inSkyBlock && config) ErrorManager.logErrorWithData( + e, "Failed to get NTP offset", + "server" to ntpServer, + ) + else e.printStackTrace() + null + } + + private var lastSystemTime = System.currentTimeMillis() + + private fun detectTimeChange() { + val currentSystemTime = System.currentTimeMillis() + val timeDifference = (currentSystemTime - lastSystemTime).milliseconds + lastSystemTime = currentSystemTime + + val expectedDuration = 1.seconds + val deviation = timeDifference - expectedDuration + + if (deviation.absoluteValue > 1.seconds) { + checkOffset() + } + } + + @SubscribeEvent + fun onProfileJoin(event: ProfileJoinEvent) { + DelayedRun.runDelayed(5.seconds) { + checkOffset() + } + } + + private fun tryDisplayOffset(wasOffsetBefore: Boolean) { + if (!config || !LorenzUtils.onHypixel) return + val offsetMillis = offsetMillis ?: return + if (offsetMillis.absoluteValue < 5.seconds) { + if (wasOffsetBefore) { + ChatUtils.chat("Congratulations! Your computer's clock is now accurate.") + } + return + } + + ChatUtils.clickableLinkChat( + "Your computer's clock is off by ${offsetMillis.absoluteValue.format()}.\n" + + "§ePlease update your time settings. Many features may not function correctly until you do.\n" + + "§eClick here for instructions on how to fix your clock.", + offsetFixLinks ?: return, + prefixColor = "§c", + ) + } + + @SubscribeEvent + fun onDebugCollect(event: DebugDataCollectEvent) { + event.title("Time Offset") + val relevant = offsetMillis?.absoluteValue?.let { it < 100.milliseconds } ?: true + if (relevant) { + event.addData(offsetMillis.toString()) + } else { + event.addIrrelevant(offsetMillis.toString()) + } + } +} diff --git a/src/main/java/at/hannibal2/skyhanni/utils/OSUtils.kt b/src/main/java/at/hannibal2/skyhanni/utils/OSUtils.kt index e209e0ce9..5b42c5dc6 100644 --- a/src/main/java/at/hannibal2/skyhanni/utils/OSUtils.kt +++ b/src/main/java/at/hannibal2/skyhanni/utils/OSUtils.kt @@ -7,6 +7,17 @@ import java.net.URI object OSUtils { + val isWindows: Boolean + val isMac: Boolean + val isLinux: Boolean + + init { + val os = System.getProperty("os.name") + isWindows = os.contains("win", ignoreCase = true) + isMac = os.contains("mac", ignoreCase = true) + isLinux = os.contains("linux", ignoreCase = true) + } + @JvmStatic fun openBrowser(url: String) { val desktopSupported = Desktop.isDesktopSupported() @@ -17,7 +28,7 @@ object OSUtils { } catch (e: IOException) { ErrorManager.logErrorWithData( e, "Error while opening website.", - "url" to url + "url" to url, ) } } else { |