diff --git a/src/main/java/com/denizenscript/denizencore/DenizenCore.java b/src/main/java/com/denizenscript/denizencore/DenizenCore.java index d154ec1e..212167ef 100644 --- a/src/main/java/com/denizenscript/denizencore/DenizenCore.java +++ b/src/main/java/com/denizenscript/denizencore/DenizenCore.java @@ -15,6 +15,7 @@ import com.denizenscript.denizencore.tags.Attribute; import com.denizenscript.denizencore.tags.ReplaceableTagEvent; import com.denizenscript.denizencore.tags.TagManager; +import com.denizenscript.denizencore.utilities.CoreUtilities; import com.denizenscript.denizencore.utilities.debugging.LogInterceptor; import com.denizenscript.denizencore.utilities.debugging.Debug; import com.denizenscript.denizencore.utilities.scheduling.Schedulable; @@ -46,9 +47,9 @@ public class DenizenCore { public static ScriptEngine scriptEngine; /** - * Time (System.currentTimeMillis) that the engine first loaded. + * Monotonic time (CoreUtilities.monotonicMillis) that the engine first loaded. */ - public final static long startTime = System.currentTimeMillis(); + public final static long startTime = CoreUtilities.monotonicMillis(); /** * Server flags, for the 'flag' command and 'server.flag[...]' tags. @@ -56,7 +57,7 @@ public class DenizenCore { public static SavableMapFlagTracker serverFlagMap; /** - * Last time (System.currentTimeMillis) that scripts wre reloaded. + * Last monotonic time (CoreUtilities.monotonicMillis) that scripts wre reloaded. */ public static long lastReloadTime; @@ -81,6 +82,12 @@ public class DenizenCore { */ public static long currentTimeMillis = System.currentTimeMillis(); + /** + * Current monotonic time (System.nanoTime), updated per-tick. + * Used to avoid multiple checks in the same tick having different time values. + */ + public static long currentTimeMonotonicMillis = CoreUtilities.monotonicMillis(); + /** * Duration of time, in milliseconds, since the server started. */ @@ -128,6 +135,7 @@ public class DenizenCore { */ public static void init(DenizenImplementation implementation) { currentTimeMillis = System.currentTimeMillis(); + currentTimeMonotonicMillis = CoreUtilities.monotonicMillis(); DenizenCore.implementation = implementation; MAIN_THREAD = Thread.currentThread(); Debug.log("Initializing Denizen Core v" + VERSION + @@ -194,7 +202,7 @@ public static void postLoadScripts() { OldEventManager.scanWorldEvents(); ScriptEvent.reload(); implementation.onScriptReload(); - lastReloadTime = System.currentTimeMillis(); + lastReloadTime = CoreUtilities.monotonicMillis(); } catch (Exception ex) { implementation.debugMessage("Error loading scripts:"); @@ -243,6 +251,7 @@ static void oncePerSecond() { public static void tick(int ms_elapsed) { serverTimeMillis += ms_elapsed; currentTimeMillis = System.currentTimeMillis(); + currentTimeMonotonicMillis = CoreUtilities.monotonicMillis(); TickScriptEvent.instance.ticks++; if (TickScriptEvent.instance.enabled) { TickScriptEvent.instance.fire(); diff --git a/src/main/java/com/denizenscript/denizencore/objects/core/QueueTag.java b/src/main/java/com/denizenscript/denizencore/objects/core/QueueTag.java index 1da73a1f..980696a6 100644 --- a/src/main/java/com/denizenscript/denizencore/objects/core/QueueTag.java +++ b/src/main/java/com/denizenscript/denizencore/objects/core/QueueTag.java @@ -181,11 +181,11 @@ public static void registerTags() { // Returns the time this queue started as a duration. // --> tagProcessor.registerTag(TimeTag.class, "started_time", (attribute, object) -> { - return new TimeTag(object.getQueue().startTimeMilli); + return new TimeTag(CoreUtilities.monotonicMillisToReal(object.getQueue().startTimeMilli)); }); tagProcessor.registerTag(DurationTag.class, "start_time", (attribute, object) -> { Deprecations.timeTagRewrite.warn(attribute.context); - return new DurationTag(object.getQueue().startTimeMilli / 50); + return new DurationTag(CoreUtilities.monotonicMillisToReal(object.getQueue().startTimeMilli) / 50); }); // <--[tag] diff --git a/src/main/java/com/denizenscript/denizencore/objects/core/TimeTag.java b/src/main/java/com/denizenscript/denizencore/objects/core/TimeTag.java index 922720f2..99264842 100644 --- a/src/main/java/com/denizenscript/denizencore/objects/core/TimeTag.java +++ b/src/main/java/com/denizenscript/denizencore/objects/core/TimeTag.java @@ -48,7 +48,7 @@ public class TimeTag implements ObjectTag, Adjustable, FlaggableObject { // --> public static TimeTag now() { - return new TimeTag(ZonedDateTime.now()); + return new TimeTag(DenizenCore.currentTimeMillis, ZoneId.systemDefault()); } @Fetchable("time") diff --git a/src/main/java/com/denizenscript/denizencore/scripts/commands/core/WebGetCommand.java b/src/main/java/com/denizenscript/denizencore/scripts/commands/core/WebGetCommand.java index f8786f86..b44b1f53 100644 --- a/src/main/java/com/denizenscript/denizencore/scripts/commands/core/WebGetCommand.java +++ b/src/main/java/com/denizenscript/denizencore/scripts/commands/core/WebGetCommand.java @@ -242,7 +242,7 @@ public void webGet(final ScriptEntry scriptEntry, final ElementTag data, Element BufferedReader buffIn = null; HttpURLConnection uc = null; try { - long timeStart = System.currentTimeMillis(); + long timeStart = CoreUtilities.monotonicMillis(); URL url = new URL(urlText.replace(" ", "%20")); uc = (HttpURLConnection) url.openConnection(); uc.setDoInput(true); @@ -292,7 +292,7 @@ else if (data != null) { } resultHeaders.putObject(key, new ListTag(header.getValue())); } - final long timeDone = System.currentTimeMillis(); + final long timeDone = CoreUtilities.monotonicMillis(); DenizenCore.schedule(new Schedulable() { @Override public boolean tick(float seconds) { diff --git a/src/main/java/com/denizenscript/denizencore/scripts/commands/queue/WaitCommand.java b/src/main/java/com/denizenscript/denizencore/scripts/commands/queue/WaitCommand.java index 98cb06cc..6660de81 100644 --- a/src/main/java/com/denizenscript/denizencore/scripts/commands/queue/WaitCommand.java +++ b/src/main/java/com/denizenscript/denizencore/scripts/commands/queue/WaitCommand.java @@ -4,6 +4,7 @@ import com.denizenscript.denizencore.objects.Argument; import com.denizenscript.denizencore.objects.core.QueueTag; import com.denizenscript.denizencore.scripts.queues.core.TimedQueue; +import com.denizenscript.denizencore.utilities.CoreUtilities; import com.denizenscript.denizencore.utilities.debugging.Debug; import com.denizenscript.denizencore.objects.core.DurationTag; import com.denizenscript.denizencore.scripts.ScriptEntry; @@ -69,12 +70,12 @@ public static class SystemTimeDelayTracker implements TimedQueue.DelayTracker { public long systemTimeEnd; public SystemTimeDelayTracker(long millis) { - systemTimeEnd = System.currentTimeMillis() + millis; + systemTimeEnd = CoreUtilities.monotonicMillis() + millis; } @Override public boolean isDelayed() { - return systemTimeEnd > System.currentTimeMillis(); + return systemTimeEnd > CoreUtilities.monotonicMillis(); } } diff --git a/src/main/java/com/denizenscript/denizencore/scripts/commands/queue/WhileCommand.java b/src/main/java/com/denizenscript/denizencore/scripts/commands/queue/WhileCommand.java index d538958c..d90e2914 100644 --- a/src/main/java/com/denizenscript/denizencore/scripts/commands/queue/WhileCommand.java +++ b/src/main/java/com/denizenscript/denizencore/scripts/commands/queue/WhileCommand.java @@ -158,7 +158,7 @@ else if (callback != null && callback.asBoolean()) { scriptEntry.getBracedSet().get(0).value.get(scriptEntry.getBracedSet().get(0).value.size() - 1) != scriptEntry)) { WhileData data = (WhileData) scriptEntry.getOwner().getData(); data.index++; - if (System.currentTimeMillis() - data.LastChecked < 50) { + if (CoreUtilities.monotonicMillis() - data.LastChecked < 50) { data.instaTicks++; if (data.instaTicks > CoreConfiguration.whileMaxLoops && CoreConfiguration.whileMaxLoops != 0) { return; @@ -167,7 +167,7 @@ else if (callback != null && callback.asBoolean()) { else { data.instaTicks = 0; } - data.LastChecked = System.currentTimeMillis(); + data.LastChecked = CoreUtilities.monotonicMillis(); boolean run = new IfCommand.ArgComparer().compare(new ArrayList(data.value), scriptEntry); if (run) { if (scriptEntry.dbCallShouldDebug()) { @@ -207,7 +207,7 @@ else if (callback != null && callback.asBoolean()) { WhileData datum = new WhileData(); datum.index = 1; datum.value = comparisons; - datum.LastChecked = System.currentTimeMillis(); + datum.LastChecked = CoreUtilities.monotonicMillis(); datum.instaTicks = 1; scriptEntry.setData(datum); ScriptEntry callbackEntry = new ScriptEntry("WHILE", new String[] {"\0CALLBACK"}, diff --git a/src/main/java/com/denizenscript/denizencore/scripts/queues/ScriptQueue.java b/src/main/java/com/denizenscript/denizencore/scripts/queues/ScriptQueue.java index c2207c64..718f718d 100644 --- a/src/main/java/com/denizenscript/denizencore/scripts/queues/ScriptQueue.java +++ b/src/main/java/com/denizenscript/denizencore/scripts/queues/ScriptQueue.java @@ -323,7 +323,7 @@ public final void start(boolean doBasicConfig) { if (doBasicConfig) { script = script_entries.get(0).getScript(); startTime = System.nanoTime(); - startTimeMilli = System.currentTimeMillis(); + startTimeMilli = CoreUtilities.monotonicMillis(); } String name = getName(); if (queueNeedsToDebug()) { diff --git a/src/main/java/com/denizenscript/denizencore/tags/core/UtilTagBase.java b/src/main/java/com/denizenscript/denizencore/tags/core/UtilTagBase.java index e17c0e3a..d7ae979d 100644 --- a/src/main/java/com/denizenscript/denizencore/tags/core/UtilTagBase.java +++ b/src/main/java/com/denizenscript/denizencore/tags/core/UtilTagBase.java @@ -435,6 +435,8 @@ else if (attribute.matches("time_at") && attribute.hasParam()) { // @returns TimeTag // @description // Returns the current system date/time. + // This value may be wrong if a server is currently heavily lagging, as it only updates once each tick. + // Use <@link tag server.current_time_millis> if you need sub-tick precision. // --> else if (attribute.startsWith("time_now")) { event.setReplacedObject(TimeTag.now().getObjectAttribute(attribute.fulfill(1))); diff --git a/src/main/java/com/denizenscript/denizencore/utilities/CoreUtilities.java b/src/main/java/com/denizenscript/denizencore/utilities/CoreUtilities.java index 84db4797..62e9dfe7 100644 --- a/src/main/java/com/denizenscript/denizencore/utilities/CoreUtilities.java +++ b/src/main/java/com/denizenscript/denizencore/utilities/CoreUtilities.java @@ -898,4 +898,12 @@ else if (list instanceof ListTag) { return ListTag.valueOf(raw, context).objectForms; } } + + public static long monotonicMillis() { + return System.nanoTime() / 1000000; + } + + public static long monotonicMillisToReal(long monotonic) { + return System.currentTimeMillis() + (monotonic - monotonicMillis()); + } } diff --git a/src/main/java/com/denizenscript/denizencore/utilities/debugging/SlowWarning.java b/src/main/java/com/denizenscript/denizencore/utilities/debugging/SlowWarning.java index ac751804..df0a63b1 100644 --- a/src/main/java/com/denizenscript/denizencore/utilities/debugging/SlowWarning.java +++ b/src/main/java/com/denizenscript/denizencore/utilities/debugging/SlowWarning.java @@ -1,6 +1,7 @@ package com.denizenscript.denizencore.utilities.debugging; import com.denizenscript.denizencore.utilities.CoreConfiguration; +import com.denizenscript.denizencore.utilities.CoreUtilities; public class SlowWarning extends Warning { @@ -12,7 +13,7 @@ public SlowWarning(String message) { @Override public boolean testShouldWarn() { - long cTime = System.currentTimeMillis(); + long cTime = CoreUtilities.monotonicMillis(); if (lastWarning + CoreConfiguration.deprecationWarningRate > cTime) { return false; }