• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

[GUI-friendly] Wayback (Time Travel/Rewind System)

[GUI-Friendly] Wayback v1.1.0

System Requirements

This system allows you to make units "go back in time" by periodically saving snapshots of their current states in a Linked List created with GLL. When you want to make the unit return to another point in time, the system simply reads the saved data and restores the unit to that point, including (by default) life, mana and position.

You can also make the unit slowly rewind through time, going through each position it had previosuly been in.

For vJASS users, there exists a similar system made by the ever-awesome Bribe: Retro.

Snapshots:

Wayback periodically saves the current state of a unit in a "snapshot", which is identified by a unique ID generated with GMUI (using the generic Recycle Key: 1). Because of the way snapshots are saved, advanced users can save their own data in a snapshot, allowing for more than just unit life, mana and position to be saved and restored.

Hashtable:

Unit Handle ID
0 -> timer
1 -> GLL List
2 -> snapshot counter
3 -> maximum snapshots (determines max rewind time = period * maximum snapshots)

Timer Handle ID
0 -> unit

(negative) Snapshot ID
0 -> unit HP
1 -> unit MP
2 -> unit X
3 -> unit Y


How to Import:

  1. Open World Editor. File -> Preferences -> Tick box for "Automatically create unknown variables (...)"
  2. Copy the "GUI MUI Engine" category into your map.
  3. Open the "GMUI Header" trigger and copy its contents into your map header.
  4. Copy the "GUI Linked Lists" category into your map.
  5. Open the "GLL Header" trigger and copy its contents into your map header, below GMUI.
  6. Copy the trigger category "Wayback System" into your map.
  7. Delete all disabled triggers with "Import" in their name
  8. Done!
Using the System:

Register Unit

Unregister Unit

Return in Time

Rewind Time

Configuration

JASS API


Since the system needs to save snapshots periodically, it will require more processing power for each unit you want to be able to go back in time. Therefore, you need to manually specify when you want a unit to be able to go back through time.

Variables before execution:

Wayback_Unit

The unit we wish to register in the system.

Wayback_Time

The maximum time the unit will be able to return in time.

Wayback_Precision

How precise the system will be (time between each snapshot)

GUI-only method:
  • Actions
    • Set Wayback_Unit = YourUnit
    • Set Wayback_Time = YourMaxTime
    • Set Wayback_Precision = YourDesiredPrecision
    • Trigger - Run Wayback Main <gen> (ignoring conditions)

The system saves a lot of data in hashtables, so if you are not gonna have a unit go back through time anymore, you should unregister it. It is especially important to unregister a unit before it is removed from play (to avoid memory leaks). Unregistering a unit also stops the periodic timer that takes snapshots.

Variables before execution:

Wayback_Unit

The unit we wish to unregister from the system.

Wayback_Time

We set this to a negative number when we want to unregister a unit.

GUI-only method:
  • Actions
    • Set Wayback_Unit = YourUnit
    • Set Wayback_Time = -1
    • Trigger - Run Wayback Main <gen> (ignoring conditions)

This is the main feature of wayback. Using this function, the unit is instantly transported back in time, appearing on the position it had been in at the specified time.

Variables before execution:

Wayback_Unit

The unit we want to take back through time.

Wayback_Time

The amount of time (in seconds) the unit will go back (0 for maximum). Use a non-negative number.

GUI-only method:
  • Actions
    • Set Wayback_Unit = YourUnit
    • Set Wayback_Time = YourTime (non-negative, 0 for max)
    • Trigger - Run Wayback Main <gen> (checking conditions)

This is another cool feature that allows you to make units slowly go back in time over a specified duration.

Variables before execution:

Wayback_Unit

The unit we want to take back through time.

Wayback_Time

The amount of time (in seconds) the unit will go back. Use a negative number.

Wayback_Precision

How much time the rewind should take.

GUI-only method:
  • Actions
    • Set Wayback_Unit = YourUnit
    • Set Wayback_Time = YourTime (negative number)
    • Set Wayback_Precision = YourDuration
    • Trigger - Run Wayback Main <gen> (checking conditions)


At the very top of the Wayback Main trigger, you will find this code that allows you to easily configure Wayback to store any value that you want, instead of only the values that the system would normally store!

JASS:
//===========================================================================
// Easy Configuration
//===========================================================================

// Use the functions/textmacros defined here to change the behaviour of the system by changing
// what data is stored in a snapshot. You could, for example, store the unit's flying height as
// well by simply adding the commented out lines at the end of each function.

//! novjass
function StoreSnapshotData takes integer snapshot, unit whichUnit returns nothing
//! endnovjass
//! textmacro StoreSnapshotData
    //Whenever a new snapshot of a unit is created, this code is run to store data.
    //You can alter this function(JASS)/textmacro(vJASS) to store whatever values you need.
 
    call SaveReal(udg_Wayback_Hashtable, snapshot, 0, GetUnitState(whichUnit, UNIT_STATE_LIFE))
    call SaveReal(udg_Wayback_Hashtable, snapshot, 1, GetUnitState(whichUnit, UNIT_STATE_MANA))
    call SaveReal(udg_Wayback_Hashtable, snapshot, 2, GetUnitX(whichUnit))
    call SaveReal(udg_Wayback_Hashtable, snapshot, 3, GetUnitY(whichUnit))
    // Example of user-defined data:
    //call SaveReal(udg_Wayback_Hashtable, snapshot, 4, GetUnitFlyHeight(whichUnit))
//! endtextmacro
//! novjass
endfunction
//! endnovjass

//! novjass
function UnitLoadSnapshot takes integer snapshot, unit whichUnit returns nothing
//! endnovjass
//! textmacro UnitLoadSnapshot
    //Whenever a new snapshot of a unit is created, this code is to restore the unit.
    //You can alter this function(JASS)/textmacro(vJASS) to use any custom data you have added.
 
    call SetUnitState(whichUnit, UNIT_STATE_LIFE, LoadReal(udg_Wayback_Hashtable, snapshot, 0))
    call SetUnitState(whichUnit, UNIT_STATE_MANA, LoadReal(udg_Wayback_Hashtable, snapshot, 1))
    call SetUnitX(whichUnit, LoadReal(udg_Wayback_Hashtable, snapshot, 2))
    call SetUnitY(whichUnit, LoadReal(udg_Wayback_Hashtable, snapshot, 3))
    // Example of user-defined data:
    //call SetUnitFlyHeight(whichUnit, LoadReal(udg_Wayback_Hashtable, snapshot, 4))
//! endtextmacro
//! novjass
endfunction
//! endnovjass

JASS:
//===========================================================================
// Code and API
//===========================================================================

//=======
//Register Unit functions
//=======

//Registers a unit in the System, allowing you to specify a function for the periodic timer
function Wayback_RegisterUnitEx takes unit whichUnit, real period, integer maxSnapshots, code timerFunc returns nothing
endfunction

//Register unit with default timer function
function Wayback_RegisterUnit takes unit whichUnit, real period, integer maxSnapshots returns nothing
endfunction

//Register unit using a duration instead of maximum snapshots and using default timer function
function Wayback_RegisterUnitDuration takes unit whichUnit, real period, real duration, real period2 returns nothing
endfunction

//Register unit using a duration instead of maximum snapshots
function Wayback_RegisterUnitDurationEx takes unit whichUnit, real period, real duration, real period2, code timerFunc returns nothing
endfunction

//Unregisters a unit from the system, deleting all snapshot data and the timer
function Wayback_UnregisterUnit takes unit whichUnit returns nothing
endfunction

//=======
//Restoring and Rewinding functions
//=======

//Instantly restores a unit to their oldest snapshot
//Returns the ID of the snapshot for extended functionality
function Wayback_RestoreUnit takes unit whichUnit returns integer
endfunction

//Instantly moves unit "time" seconds back in time, up to their oldest snapshot
//Returns the ID of the snapshot for extended functionality
function Wayback_RestoreUnitEx takes unit whichUnit, real time returns integer
endfunction

//Instantly moves unit a single snapshot back in time
//The unit ID variable should be the unit's handle ID
//Returns the ID of the snapshot for extended functionality
function Wayback_RestoreUnitByIdOneStep takes unit whichUnit, integer unitID returns integer
endfunction

//Instantly moves unit a single snapshot back in time
//Returns the ID of the snapshot for extended functionality
function Wayback_RestoreUnitOneStep takes unit whichUnit returns integer
endfunction

//=======

//Takes a unit back in "time" seconds in time, snapshot-by-snapshot, over "duration" seconds
function Wayback_RewindUnit takes unit whichUnit, real time, real duration returns nothing
endfunction
////////////////////////////////////////////////////////////////////////////////////////////////////
//End of Wayback
////////////////////////////////////////////////////////////////////////////////////////////////////



Test Map:


Command

Action

unregister

Unregisters all units from the system

register

Registers all units in the system

wayback

returns a unit 1 second in time

rewind

slowly rewinds a unit 2.5 seconds back in time

Units in the test map will automatically go back in time whenever they cast an ability. In addition, you may use the above commands to test wheter the system is correctly registering and unregistering units. An unregistered unit will die and revive at position (0,0) of the map. There's not much else to test, really.

Updates and Version History:
v1:
0.1.0 > Initial Release
1.0.0 > Added function to slowly rewind units and option to return less than the max time
1.0.0a > GLL Import now contains all the correct variables
1.0.0b > Fixed some mistakes in the system description
1.1.0 > Added StoreSnapshot data UnitLoadSnapshot functions for easy config.
Upcoming:
Contents

Guhun's Wayback System (Map)

Reviews
Dr Super Good
Comments and Suggestions: Potentially useful system for implementing Heroes of the Storm Tracer style Recall abilities. Fairly easy to use as well. Having a demonstration ability that works similar to Tracer's in Heroes of the Storm would be useful...
Level 12
Joined
Jun 12, 2010
Messages
413
I'll assume it just teleports the user to the old position/state?

I'd probably love a visual with that. Like Tracer's E from Overwatch

Yeah, basically it will by default return the unit to its original position and health/mana. But you can add more data to a snapshot. So, if, for example, you are using some sort of debuff system, you could make it so the unit loses all the debuffs it did not have, thought that may require some extra coding. For something like a stun system, though, that would be really easy to implement, I believe.

As for visuals, right now it just teleports the unit. You could always add special effects to that, but I'm also planning on making an easy way to make the unit slowly go back through time, like Tracer does in the Widow cinematic.
 
Level 12
Joined
Jun 12, 2010
Messages
413
so... I assume this will become like a GUI version of Bribe's Retro ?

Oh, yeah, that's basically what it comes down to, though I'm not too familiar with how retro works. But it doesn't seem like Retro supports instantly taking the unit back in time, though I could be wrong. Another difference is that Retro uses a global precision/max return time, while this system has it specified on a per-unit basis (which is a bit slower per-snapshot recording, but not gonna make that much of a diffrence, I think). Also Retro uses vJASS, so it actually looks like a decent piece of software engineering, unlike JASS ^^


Either way, I forgot to add it to the description as an alternative vJASS system. Gonna do that now.

Update:
Version 1.0.0 >

-Added function to slowly rewind units back in time
-Added option to specify a return time lower than the max time
 
Last edited:
Level 2
Joined
Nov 28, 2017
Messages
12
Hello, may I ask something... do you need any special program to open/save maps that including JASS code? I am using Warcraft World Editor v1.28f, from the official Warcraft III game disk, but when I try to copy a JASS code spell into a custom map, it always has some script errors. By the way, I clicked the "Automatically create unknown variables (...)" already.
111111.jpg

hqMjsR
 
Level 12
Joined
Jun 12, 2010
Messages
413
Hello, may I ask something... do you need any special program to open/save maps that including JASS code? I am using Warcraft World Editor v1.28f, from the official Warcraft III game disk, but when I try to copy a JASS code spell into a custom map, it always has some script errors. By the way, I clicked the "Automatically create unknown variables (...)" already.

It looks like you forgot to put the code in your map Header, thus the functions are not being found when they are referenced.

"
  1. Copy the "GUI MUI Engine" category into your map.
  2. Open the "GMUI Header" trigger and copy its contents into your map header.
  3. Copy the "GUI Linked Lists" category into your map.
  4. Open the "GLL Header" trigger and copy its contents into your map header, below GMUI.
"

The map header is the thing above your triggers which has the same name as your map file.

IMAGE
 
Last edited:
Level 2
Joined
Nov 28, 2017
Messages
12
It looks like you forgot to put the code in your map Header, thus the functions are not being found when they are referenced.

"
  1. Copy the "GUI MUI Engine" category into your map.
  2. Open the "GMUI Header" trigger and copy its contents into your map header.
  3. Copy the "GUI Linked Lists" category into your map.
  4. Open the "GLL Header" trigger and copy its contents into your map header, below GMUI.
"

The map header is the thing above your triggers which has the same name as your map file.

IMAGE
Thanks for responding. I did all the step you listed in the 'How to Import', but now it has more script errors...
22222.jpg
 
Level 12
Joined
Jun 12, 2010
Messages
413
Thanks for responding. I did all the step you listed in the 'How to Import', but now it has more script errors...

It seems I forgot to add two variables to the variable import trigger, which is the cause of that error. I'll fix this asap.

It should work once you create an integer variable named : "Lists_RECYCLE_KEY" and another trigger variable named "Lists_Trigger".

Sorry for the inconvenience.

PS: If it still doesn't work, you may have copied the GLL map header above the GMUI map header. It should be below.

Update:
1.0.0a > GLL Import now contains all the correct variables
 
Last edited:

Bribe

Code Moderator
Level 50
Joined
Sep 26, 2009
Messages
9,456
Hi thanks for your contribution. I actually will be having more free time at i got rid of a toxic game that was dragging me down (Hearthstone) and the GUI Retro rework has been in my sights for some time.

I haven't done a Teleport thing in Retro as the coordinates are logged in a 4D hashtable, but will make recalling instantly a feature in the system as it's more logical to build that in than to have a separate system for it.

The add/remove can either be automatic or manual.

Other stuff like i have in the Time Warp spell-such as effects-will be excluded from the internal system and enabled strictly through add-ons (where they belong).

The basic API would be a simple add/remove trigger command and for activating it would be a variable set by the user to the travel duration preceded by how much time to go back. The most basic form will look something like:

Retro__RewindUnit = (TriggeringUnit)
Retro__RewindTo = 2.00 (seconds ago)
Retro__RewindRate = 1.00 (takes 1 second to rewind by 2 seconds - 0 for instant).

I look forward to seeing what other stuff comes up, but i plan to see this at a public release point by end of Feb.
 
Level 12
Joined
Jun 12, 2010
Messages
413
Hi thanks for your contribution. I actually will be having more free time at i got rid of a toxic game that was dragging me down (Hearthstone) and the GUI Retro rework has been in my sights for some time.

That's great xD
Being too focused on a game can really be a detriment to productivity (talking from first-hand experience, too!)

I look forward to seeing what other stuff comes up, but i plan to see this at a public release point by end of Feb.

Can't wait for what you come up with :eek::eek:



Update: Version 1.1.0

Small update, but might be pretty useful one! Added an easy way to configure what data is stored in a snapshot of a unit by created two new fucntions which a JASS user can edit: Added StoreSnapshot data UnitLoadSnapshot functions for easy config.

(If vJASS is enabled, the functions are converted to textmacros for better performance.
 

Dr Super Good

Spell Reviewer
Level 63
Joined
Jan 18, 2005
Messages
27,180
Comments and Suggestions:
Potentially useful system for implementing Heroes of the Storm Tracer style Recall abilities. Fairly easy to use as well.

Having a demonstration ability that works similar to Tracer's in Heroes of the Storm would be useful as I can imagine such abilities being the main use case for a system like this.​
 
Top