[System] Smooth Timers

Jesus4Lyf

Good Idea™
Reaction score
397
Smooth Timers​
Version 1.1.0​

See attached SC2Lib file.
Slightly similar to the Warcraft III Timer32 system, but nowhere near as cool. But GUI!

Example:
Trigger:
  • SmoothTimersExampleInit
    • Events
      • Timer - Elapsed time is 1.0 Game Time seconds
    • Local Variables
      • SmoothTimer = 0 <Integer>
    • Conditions
    • Actions
      • Variable - Set SmoothTimer = (NewSmoothTimer(SmoothTimersExample, 5))
      • General - Wait 2.0 Game Time seconds
      • DestroySmoothTimer(SmoothTimer)

Trigger:
  • SmoothTimersExample
    • Events
    • Local Variables
    • Conditions
    • Actions
      • UI - Display (Text((GetSmoothTimerData((GetExpiringSmoothTimer()))))) for (All players) to Debug area

The example will just display "5" a whole lot. The premise is, that using the data integer as an index, you can attach whatever you wish to timers, which will fire 32 times per second. This is to overcome SC2 limitations on timers only being able to fire as fast as 16 times per second, as well as overcoming their lack of data attachment. :thup:

The original SC2 timer system.
 

Attachments

  • SmoothTimers.SC2Lib
    53.2 KB · Views: 559

PurgeandFire

zxcvmkgdfg
Reaction score
509
Where is the code? Unless there is something to open .sc2lib besides galaxy editor. Well, I am mostly just curious of how you achieved it. I had an idea in mind but I doubted it would work. =)
 

Jesus4Lyf

Good Idea™
Reaction score
397
It's really difficult to show code. Because you can't show -everything- that easily. This lib has something like 24 things in it.

I just fire off two timers running at 16 execs/sec each, and try to seperate them by 0.03125. I discovered that the UI (ie. display messages) do not display more than 16 times per second regardless, so I've assumed this works but haven't thoroughly tested it yet. :thup:

The way I discovered that was by using 0.0 waits, which seem to equate to 0.03125 in single player (God knows if that's the same for b.net, though - timers on 0 period still go to 0.0625 it seems, so...).

So.. yeah. :)
I can always upgrade it some how if it turns out that the timers are somehow actually firing at the same time - and I'm sure that will be discovered soon enough, if they are. :D

Internally, aside from that, the code is much like Timer32, it uses a doubly linked list of nodes which has a periodic handler to iterate through them. :)
 

PurgeandFire

zxcvmkgdfg
Reaction score
509
Heh, I was actually thinking of that two-timer method. :D But I didn't think it would work; I had just assumed that timers were inaccurate in general. But my idea was a bit messy and since I don't have the editor, it was nothing but a theory. =P

The way I discovered that was by using 0.0 waits, which seem to equate to 0.03125 in single player (God knows if that's the same for b.net, though - timers on 0 period still go to 0.0625 it seems, so...).

How do these weird things always exist? :p It's as if blizzard adds them purposely for modders to find. I wonder what happens if you put in a negative (unless it crashes/syntax error) I guess you used game-time, since Romek got 0 wait = 0 s from using real-time. (Then again, real-time is apparently approximated)

Nice of you to kick off with a decent timer system though, props for that since it is usually started off using some typecasting and whatever Blizz has to offer. =P
 

Zwiebelchen

You can change this now in User CP.
Reaction score
60
Is there no way to make the timer fire faster than 16 times per second? How did you actually find that out? I mean ... couldn't the DisplayMessage be the one that can only fire 16 times and not the timer?

If timers in SC2 can not run faster than 16 fps, then this really is a slap into the face of anyone who wants to "script" special effects or unit movement, etc.

And did you do intense tests on the Wait function? Maybe timer systems are obsolete in SC2, depending on how good the wait function turns out to be.


EDIT: I read the other threads in this forum ... seems that wait is awful too.

However, first of, I want to thank you for the effort you are already putting into the editor to write all those amazing scripts already that come in so handy for all mappers out there in the future.

One suggestion for this system: Could you somehow make it able to attach structs instead of integers to the timer? I know this is not possible, as indexing only allows integers, but I know you can come up with some neat workaround ... I do not want to index all my structs in the future - except you write an additional system like "GetStructId" or something that perfectly identifies all structs used.
 

Jesus4Lyf

Good Idea™
Reaction score
397
One suggestion for this system: Could you somehow make it able to attach structs instead of integers to the timer? I know this is not possible, as indexing only allows integers, but I know you can come up with some neat workaround ... I do not want to index all my structs in the future - except you write an additional system like "GetStructId" or something that perfectly identifies all structs used.
Thanks for your response.

I can't yet pass records as parameters or return records. It's really unfortunate, but Blizzard has not (at least yet) implemented pointers in GUI.

I expect some things to be done around function pointers and record pointers, at which point systems like this shall receive an update. Until then, I'm not even sure how they're going to go about it - if they are at all.

I agree that indexing records is a pain. :)
 

Zwiebelchen

You can change this now in User CP.
Reaction score
60
Thanks for your response.

I can't yet pass records as parameters or return records. It's really unfortunate, but Blizzard has not (at least yet) implemented pointers in GUI.
Hmm, so you wrote this especially for GUI users? In that case, would it be possible to attach structs in a galaxy-users-only version, as I am not going to use GUI at all, but start with galaxy right from the start.

If not ... then there is always the possibility to create an auto-indexing system for structs, kinda like all those unit indexing systems in wc3. Is there really nothing like a native GetHandleId for structs?

Alternatively, you could implement an internal struct ID for this timer system only. Kinda like when the data is attached, it puts the struct into an T32 internal global struct array and attaches the index of that struct in this array to the timer.

This would magically allow structs for timers. However, the amount of timers and structs you can attach to them would be limited that way because of max array size, but I think that shouldn't be a problem.

Or simply write a GetStructId lib ... I think that would be the easiest way to deal with that.


PS: We need a systems&tutorials subforum for galaxy ;)
 

Jesus4Lyf

Good Idea™
Reaction score
397
I can't yet pass records as parameters or return records.
That, and currently pointers to structs are currently type safe, so far as I can tell - unlike in WC3 where pointers to structs were literally integers.

So, in other words, currently even if I did a Galaxy version, I believe I'd have to hard code what struct or struct pointer type can be passed in - making this approach useless.

I think we will have to see what Blizz gives us in future patches, if you view the system in its current for as inadequate. Personally, I've never been a fan of waiting for Blizz. :)
PS: We need a systems&tutorials subforum for galaxy ;)
It is being considered, especially when some more content turns up.
 

Zwiebelchen

You can change this now in User CP.
Reaction score
60
That, and currently pointers to structs are currently type safe, so far as I can tell - unlike in WC3 where pointers to structs were literally integers.

So, in other words, currently even if I did a Galaxy version, I believe I'd have to hard code what struct or struct pointer type can be passed in - making this approach useless.

I think we will have to see what Blizz gives us in future patches, if you view the system in its current for as inadequate. Personally, I've never been a fan of waiting for Blizz. :)

It is being considered, especially when some more content turns up.
I could imagine structs being an extend of some other type ... have you checked that? In that case, you'd only need to create that mothertype array.

If nothing else helps, then we would have to use custom structs by extends integer kinda like Newgen did them again ... But that would be such a waste.

Damn, I can simply not understand why blizzard is trying to fuck us so much with timers.

You have to agree that - in the current state - the system is quite useless as you do not want to create a struct array for every damn system you write. At least I wouldn't want to do that.
 

Jesus4Lyf

Good Idea™
Reaction score
397
Depends. A struct array can be really neat. Consider attaching to units or players - anything that has an index naturally. Example.
I should do an indexing system, because guess what, Blizz implemented the same ol' custom value/user data thing...

>I could imagine structs being an extend of some other type
I'm not sure there's such a thing as "extend" yet. :confused:
I'm hoping they add some flexibility with type safety around pointers. Lol... I just don't assume they would.
 

Zwiebelchen

You can change this now in User CP.
Reaction score
60
Depends. A struct array can be really neat. Consider attaching to units or players - anything that has an index naturally. Example
Yeah, but there are situations where you have to attach to timers ...

I simply can not believe that blizzard hasnt implemented a way to get a struct's ID. I mean: there are hashtables in Galaxy, arent they? Without a GetStructId, you wouldnt be able to use them in hashtables ...
There simply HAS to be a mother-type, or certain natives wouldn't work. (I suppose there are natives that allow structs as input parameter ... maybe check the natives list ...)

I should do an indexing system, because guess what, Blizz implemented the same ol' custom value/user data thing...
I once read somewhere that you could define user data completely different in SC2 ... but maybe that was just a false information.

I'm not sure there's such a thing as "extend" yet. :confused:
I'm hoping they add some flexibility with type safety around pointers. Lol... I just don't assume they would.
I think there is "extends". I saw it somewhere in one of those pre-editor "I checked the luas of the maps" discussions.
 

Romek

Super Moderator
Reaction score
963
> I mean: there are hashtables in Galaxy, arent they?
There are? :rolleyes:
 

Zwiebelchen

You can change this now in User CP.
Reaction score
60
> I mean: there are hashtables in Galaxy, arent they?
There are? :rolleyes:
In this case, forget what I said. Blizzard obviously screwed us hard with Galaxy in its current state and I think I am definitely not going to script more complex systems until it fucking allows non-typesafe arrays or at least to create a GetStructId function.
I am so going to spam the beta forums about that -_- ... I just feel like they made a fool out of us, providing us with an editor that is - script-wise - worse than the Wc3 editor.

EDIT: If only they would allow me to post into the US beta forums ... >_>
 

Cookiemaster

New Member
Reaction score
36
Hmm, are data tables just more-dimensional arrays or are they natives? In that case, you could check the input parameters for the data fields to find out the mother-type of structs.

Taken from: http://paste.sc2mapster.com/1979/

It's not possible to create a data table in any way, you only specify wether the set/get var should be global or local, and supply a key with it. (which is in the form of a string.)

Using DataTableValueType(bool global, string name) you can get what kind of object has been stored in the data table.
JASS:
//--------------------------------------------------------------------------------------------------
// Data Table
// - Data tables provide named storage for any script type.
//   Table access may be either global or thread-local.
//--------------------------------------------------------------------------------------------------
// Types
const int c_dataTypeUnknown             = -1;
const int c_dataTypeAbilCmd             =  0;
const int c_dataTypeActor               =  1;
const int c_dataTypeActorScope          =  2;
const int c_dataTypeAIFilter            =  3;
const int c_dataTypeBank                =  4;
const int c_dataTypeBool                =  5;
const int c_dataTypeByte                =  6;
const int c_dataTypeCameraInfo          =  7;
const int c_dataTypeCinematic           =  8;
const int c_dataTypeColor               =  9;
const int c_dataTypeControl             = 10;
const int c_dataTypeConversation        = 11;
const int c_dataTypeDialog              = 12;
const int c_dataTypeDoodad              = 13;
const int c_dataTypeFixed               = 14;
const int c_dataTypeInt                 = 15;
const int c_dataTypeMarker              = 16;
const int c_dataTypeObjective           = 17;
const int c_dataTypeOrder               = 18;
const int c_dataTypePing                = 19;
const int c_dataTypePlanet              = 20;
const int c_dataTypePlayerGroup         = 21;
const int c_dataTypePoint               = 22;
const int c_dataTypePortrait            = 23;
const int c_dataTypeRegion              = 24;
const int c_dataTypeReply               = 25;
const int c_dataTypeRevealer            = 26;
const int c_dataTypeRoom                = 27;
const int c_dataTypeSound               = 28;
const int c_dataTypeSoundLink           = 29;
const int c_dataTypeString              = 30;
const int c_dataTypeText                = 31;
const int c_dataTypeTimer               = 32;
const int c_dataTypeTransmission        = 33;
const int c_dataTypeTransmissionSource  = 34;
const int c_dataTypeTrigger             = 35;
const int c_dataTypeUnit                = 36;
const int c_dataTypeUnitFilter          = 37;
const int c_dataTypeUnitGroup           = 38;
const int c_dataTypeUnitRef             = 39;
const int c_dataTypeWave                = 40;
const int c_dataTypeWaveInfo            = 41;
const int c_dataTypeWaveTarget          = 42;

// General functionality
native void     DataTableClear (bool global);
native int      DataTableValueCount (bool global);
native string   DataTableValueName (bool global, int index);
native bool     DataTableValueExists (bool global, string name);
native int      DataTableValueType (bool global, string name);
native void     DataTableValueRemove (bool global, string name);

// Type-specific value set/get
// - c_dataTypeAbilCmd
native void         DataTableSetAbilCmd (bool global, string name, abilcmd val);
native abilcmd      DataTableGetAbilCmd (bool global, string name);

// - c_dataTypeActor
native void         DataTableSetActor (bool global, string name, actor val);
native actor        DataTableGetActor (bool global, string name);

// - c_dataTypeActorScope
native void         DataTableSetActorScope (bool global, string name, actorscope val);
native actorscope   DataTableGetActorScope (bool global, string name);

// - c_dataTypeAIFilter
native void         DataTableSetAIFilter (bool global, string name, aifilter val);
native aifilter     DataTableGetAIFilter (bool global, string name);

// - c_dataTypeBank
native void         DataTableSetBank (bool global, string name, bank val);
native bank         DataTableGetBank (bool global, string name);

// - c_dataTypeBool
native void         DataTableSetBool (bool global, string name, bool val);
native bool         DataTableGetBool (bool global, string name);

// - c_dataTypeByte
native void         DataTableSetByte (bool global, string name, byte val);
native byte         DataTableGetByte (bool global, string name);

// - c_dataTypeCameraInfo
native void         DataTableSetCameraInfo (bool global, string name, camerainfo val);
native camerainfo   DataTableGetCameraInfo (bool global, string name);

// - c_dataTypeCinematic
native void         DataTableSetCinematic (bool global, string name, int val);
native int          DataTableGetCinematic (bool global, string name);

// - c_dataTypeColor
native void         DataTableSetColor (bool global, string name, color val);
native color        DataTableGetColor (bool global, string name);

// - c_dataTypeControl
native void         DataTableSetControl (bool global, string name, int val);
native int          DataTableGetControl (bool global, string name);

// - c_dataTypeConversation
native void         DataTableSetConversation (bool global, string name, int val);
native int          DataTableGetConversation (bool global, string name);

// - c_dataTypeDialog
native void         DataTableSetDialog (bool global, string name, int val);
native int          DataTableGetDialog (bool global, string name);

// - c_dataTypeDoodad
native void         DataTableSetDoodad (bool global, string name, doodad val);
native doodad       DataTableGetDoodad (bool global, string name);

// - c_dataTypeFixed
native void         DataTableSetFixed (bool global, string name, fixed val);
native fixed        DataTableGetFixed (bool global, string name);

// - c_dataTypeInt
native void         DataTableSetInt (bool global, string name, int val);
native int          DataTableGetInt (bool global, string name);

// - c_dataTypeMarker
native void         DataTableSetMarker (bool global, string name, marker val);
native marker       DataTableGetMarker (bool global, string name);

// - c_dataTypeObjective
native void         DataTableSetObjective (bool global, string name, int val);
native int          DataTableGetObjective (bool global, string name);

// - c_dataTypeOrder
native void         DataTableSetOrder (bool global, string name, order val);
native order        DataTableGetOrder (bool global, string name);

// - c_dataTypePing
native void         DataTableSetPing (bool global, string name, int val);
native int          DataTableGetPing (bool global, string name);

// - c_dataTypePlanet
native void         DataTableSetPlanet (bool global, string name, int val);
native int          DataTableGetPlanet (bool global, string name);

// - c_dataTypePlayerGroup
native void         DataTableSetPlayerGroup (bool global, string name, playergroup val);
native playergroup  DataTableGetPlayerGroup (bool global, string name);

// - c_dataTypePoint
native void         DataTableSetPoint (bool global, string name, point val);
native point        DataTableGetPoint (bool global, string name);

// - c_dataTypePortrait
native void         DataTableSetPortrait (bool global, string name, int val);
native int          DataTableGetPortrait (bool global, string name);

// - c_dataTypeRegion
native void         DataTableSetRegion (bool global, string name, region val);
native region       DataTableGetRegion (bool global, string name);

// - c_dataTypeReply
native void         DataTableSetReply (bool global, string name, int val);
native int          DataTableGetReply (bool global, string name);

// - c_dataTypeRevealer
native void         DataTableSetRevealer (bool global, string name, revealer val);
native revealer     DataTableGetRevealer (bool global, string name);

// - c_dataTypeRoom
native void         DataTableSetRoom (bool global, string name, int val);
native int          DataTableGetRoom (bool global, string name);

// - c_dataTypeSound
native void         DataTableSetSound (bool global, string name, sound val);
native sound        DataTableGetSound (bool global, string name);

// - c_dataTypeSoundLink
native void         DataTableSetSoundLink (bool global, string name, soundlink val);
native soundlink    DataTableGetSoundLink (bool global, string name);

// - c_dataTypeString
native void         DataTableSetString (bool global, string name, string val);
native string       DataTableGetString (bool global, string name);

// - c_dataTypeText
native void         DataTableSetText (bool global, string name, text val);
native text         DataTableGetText (bool global, string name);

// - c_dataTypeTimer
native void         DataTableSetTimer (bool global, string name, timer val);
native timer        DataTableGetTimer (bool global, string name);

// - c_dataTypeTransmission
native void         DataTableSetTransmission (bool global, string name, int val);
native int          DataTableGetTransmission (bool global, string name);

// - c_dataTypeTransmissionSource
native void                 DataTableSetTransmissionSource (bool global, string name, transmissionsource val);
native transmissionsource   DataTableGetTransmissionSource (bool global, string name);

// - c_dataTypeTrigger
native void         DataTableSetTrigger (bool global, string name, trigger val);
native trigger      DataTableGetTrigger (bool global, string name);

// - c_dataTypeUnit
native void         DataTableSetUnit (bool global, string name, unit val);
native unit         DataTableGetUnit (bool global, string name);

// - c_dataTypeUnitFilter
native void         DataTableSetUnitFilter (bool global, string name, unitfilter val);
native unitfilter   DataTableGetUnitFilter (bool global, string name);

// - c_dataTypeUnitGroup
native void         DataTableSetUnitGroup (bool global, string name, unitgroup val);
native unitgroup    DataTableGetUnitGroup (bool global, string name);

// - c_dataTypeUnitRef
native void         DataTableSetUnitRef (bool global, string name, unitref val);
native unitref      DataTableGetUnitRef (bool global, string name);

// - c_dataTypeWave
native void         DataTableSetWave (bool global, string name, wave val);
native wave         DataTableGetWave (bool global, string name);

// - c_dataTypeWaveInfo
native void         DataTableSetWaveInfo (bool global, string name, waveinfo val);
native waveinfo     DataTableGetWaveInfo (bool global, string name);

// - c_dataTypeWaveTarget
native void         DataTableSetWaveTarget (bool global, string name, wavetarget val);
native wavetarget   DataTableGetWaveTarget (bool global, string name);
 

Zwiebelchen

You can change this now in User CP.
Reaction score
60
So without a struct indexing system, you can not use structs in the data table ... hell, blizzard did really make a mess out of that struct engine. :thdown:

I just hope this is all still subject of change ...

In the current state, Galaxy is even worse than JASS.
 

Romek

Super Moderator
Reaction score
963
> JASS had arrays, and GetHandleID/H2I.
Exactly. :p

Also, I can confirm that the timers can indeed only run 16 times per second. It took 6.25 seconds for a timer with a 0.01 second timeout to expire 100 times. :(
 
General chit-chat
Help Users
  • No one is chatting at the moment.

      The Helper Discord

      Members online

      Affiliates

      Hive Workshop NUON Dome World Editor Tutorials

      Network Sponsors

      Apex Steel Pipe - Buys and sells Steel Pipe.
      Top