Turn timer macro functions + minor editor/permissions QoL#5963
Turn timer macro functions + minor editor/permissions QoL#5963magnus-ISU wants to merge 1 commit into
Conversation
|
Disclaimer, I'm not a reviewer but... I suspect these should be split into separate PRs each using the PR template and with a reference to the open GitHub issue they are implementing/fixing/etc. For no. 2, I think this would break existing macro editor command usage, for example URI accessed CSS which may have a # id selector as the first line in the macro command, to perhaps unconventional usage for storing raw markdown with # as headings. Maybe a new Preferences checkbox enabling this would be acceptable (with default being off to preserve existing behavior)? |
|
Here is an example of what Aliasmask's lib:rpEdit uses in the header of its macro export/import: Perhaps having the editor use that "standard" would work to serve the same purpose? |
|
That is a good idea, FullBleed. I was unaware that existed. I will change it to work that way. I'll also split this into two PRs, implementing the first two things. |
|
@magnus-ISU Thanks for the contributions. Would you mind creating separate PRs? The automated change log generation will lump these together if it is not done that way, and we won't get a clear change log. Thanks Number 1: When you resubmit, can you also put in a note (for the benifit of anyone who adds it to the wiki), that a timer of x seconds will run sometime x seconds or later, not exactly x, I know its pedantic, but I just want people to know that timers when set of will wait until AFTER the current macro has completed, so if you set off a timer for 5 seconds and immediately run a macro that takes 20 seconds, the code in the timer will be run after 20 seconds not 5. This is also the case if you set a timer for 5 seconds at the start of a macro that takes 20 seconds to run. Number 2: probably the best approach is to use HTML comment <! -- !MacroLabel: My Macro --> or something similar. As HTML comments don't produce output so as long as the text !MacroLabel: is selected carefully there is no danger people will suddely find their macro buttons renamed and output missing. It could even be taken a step further if you want and allow setting of many properties Number 3: Is contentious, I am inclined to include it, but I want some time to think about it first :) |
Summary
Three independent changes bundled into one PR for convenience. Happy to split into three PRs if reviewers prefer — particularly because feature 3 is a deliberate security-bypass and may be unwelcome upstream as-is.
1. Turn-timer macro functions (the main change)
Adds
TurnTimerFunction, registered inMapToolExpressionParser, exposing:startTimer(name, seconds, [callback], [args])seconds. Non-blocking — the calling macro returns immediately. Implements the long-missing "sleep" primitive without freezing the parser.stopTimer(name)getTimerRemaining(name)getTimerStatus(name)runningornone.getTimerNames()setInitiativeTimer(seconds, [callback], [args])__initiative__. Pass0to disable.clearInitiativeTimer()Backed by a single dedicated
ScheduledExecutorService(named threads, daemon — same idiom asDebounceExecutor). Callbacks are bounced onto the EDT viaEventQueue.invokeLaterand dispatched throughMapTool.getParser().runMacro(...)— same patternCallFunction's deferred path uses. Write operations require trusted-macro context.Hooked into
InitiativeList.handleInitiativeChangeCommitMacroEventfor the auto-restart, and intoMapTool.setCampaignto cancel pending timers on campaign change. Timers are non-persistent (deliberate; mirrors howHTMLFrame/HTMLOverlayPanelregistries behave).Covered by
TurnTimerFunctionTest(lifecycle: register, cancel, replace, decay-to-zero, invalid-duration, cancelAll).Example usage:
Or layered (warning + expiry) by starting two named timers from an
onInitiativeChangelib-token macro:2.
# Namemacro-editor directive (small QoL)When saving in
MacroEditorDialog, if the command's first line is# something, that line is consumed andsomethingbecomes the macro's label. Plain regex match inapplyNameDirective(), called from the existingsave()entry point. Useful when bulk-pasting macros from disk where the filename has been embedded as a hint at the top. Caveat: people who deliberately output a literal# Textline at the top of a macro will be surprised — in practice, almost all macros start with[…].3.
Trust All Players (insecure)preference (likely contentious)New
AppPreferences.trustAllPlayerscheckbox in Preferences → Application → Macro Permissions. When on,MapToolLineParser.isMacroTrusted()andLibraryTokenmacro-trust both short-circuit totrue, making every macro trusted regardless of token ownership or per-button "Allow Player Edits". The label includes(insecure)and the tooltip warns it's intended for solo development/testing only.Why include it: Because at 99% of tables, the DM can trust all the players to not destroy the game if given power to write their own complex macros. It's a massive annoyance for my group that we can't do this.
Test plan
./gradlew test—TurnTimerFunctionTestgreen; nothing else regresses../gradlew spotlessCheck— clean.setInitiativeTimer(10, "ping@Lib:Combat")arms timer; Next/Previous re-arm; setting0disables; campaign load cancels pending timers; macro-editor directive lifts label and strips line; trust-all preference is opt-in and persists across restart.This change is