wc3campaigns
WC3C Homepage - www.wc3c.netUser Control Panel (Requires Log-In)Engage in discussions with other users and join contests in the WC3C forums!Read one of our many tutorials, ranging in difficulty from beginner to advanced!Show off your artistic talents in the WC3C Gallery!Download quality models, textures, spells (vJASS/JASS), systems, and scripts!Download maps that have passed through our rigorous approval process!

Go Back   Wc3C.net > Warcraft III Modding > Developer's Corner > Triggers & Scripts
User Name
Password
Register Rules Get Hosted! Chat Pastebin FAQ and Rules Members List Calendar



Closed Thread
 
Thread Tools Search this Thread
Old 08-22-2006, 01:06 AM   #1
karukef
User
 
Join Date: Jan 2004
Posts: 388

karukef has a spectacular aura about (97)karukef has a spectacular aura about (97)karukef has a spectacular aura about (97)karukef has a spectacular aura about (97)

Default SmartAttach concept+api - feedback needed.

I've been working on a complete GameCache replacement for attaching variables to objects. I started with SmartTimers and just now extended it to Units, Items as well. I'm writing a description on how it works from the perspective of the user, i.e how to use the system, and I'd like feedback on whether or not it sounds easy to use or complicated. That means YOU. Do YOU understand how to use this based on this post? Does it sound overly complicated or easy and useful?

I don't want to get into a technical discussion in this thread. If someone wants to discuss how SmartAttach works, they (or I) can open another thread for that.


Why SmartAttach?
To give some reasons why you might want to spend your time reading this and give feedback, here is a list of features:
  • Much MUCH faster than GameCache. (PRIMARY FEATURE)
  • Safety warnings that will detect some types of leaks.
  • Possibly safer than GameCache as it keeps all attached values alive in 'real' variables (as opposed to as integer-handles).

Basic Attach/Get
So, this is what it does: You can attach any kind of object to a Timer, a Unit or an Item. The syntax goes like this:

Collapse JASS:
//Attaches 1.45 to whichTimer
call ItemAttachReal(whichItem, "domain", "key", 1.45)
//Attaches whichUnit to whichTimer
call TimerAttachUnit(whichTimer, "domain", "key", whichUnit)
//Attaches whichEffect to whichUnit
call UnitAttachEffect(whichUnit, "domain", "key", whichEffect)

//Returns a real.
call ItemGetReal(whichItem, "domain", "key")

The "domain" value is a bit like MissionKey from gamecache, while "key" is exactly what it looks like. For now, let us assume we always use the value "global" for domain, i.e
Collapse JASS:
//Attaches the value 100 to the global key "damage" onto whichUnit.
call UnitAttachInt(whichUnit, "global", "damage", 100)

The 'whichUnit' variable is not actually of type 'unit', as you might expect, but of type 'integer'. To get the correct kind of integer to pass to Attach/Get functions, use SA_Unit(real_unit), SA_Item(real_item) and SA_Timer(real_timer).
Collapse JASS:
local integer whichUnit = SA_Unit(GetTriggerUnit())
//Returns the integer stored in key "damage" on the Triggering Unit.
local integer damage = UnitGetInt(whichUnit, "global", "damage")

Note about Timers
A special exception goes for Timers: All timers that are later passed to SA_Timer() must be created with SA_TimerNew() or SA_TimerStartNew() instead of the normal CreateTimer() function.
Wrong:
Collapse JASS:
local timer t = CreateTimer()
//ILLEGAL: t was created with CreateTimer.
local integer whichTimer = SA_Timer(t)
//Wont work, due to the error above.
set location l = TimerAttachLoc(whichTimer, "global", "target", GetUnitLoc(someUnit))
Correct:
Collapse JASS:
//Creates a timer but returns an Integer.
local integer whichTimer = SA_TimerNew()
//Attaches a location to the newly created timer under key "target"
set location l = TimerAttachLoc(whichTimer, "global", "target", GetUnitLoc(someUnit))

Global and Local namespace
In MOST CASES you want to use "global" as the domain. The only exception is if the object you attach to is a special purpose object. For example, if you have a timer that exists ONLY to drive a spell called "Snowball", you can use "snowball" as the domain.
Collapse JASS:
function SnowballSpell takes unit caster, real speed returns nothing
    //Create and start a new timer that repeats every 0.04 seconds.
    local integer whichTimer = SA_TimerStartNew(0.04, true, function SnowballSpellCallback)
    //Attach the caster with key "caster" to the timer using local domain "snowball"
    call TimerAttachUnit(whichTimer, "snowball", "caster", caster)
    //Attach the speed
    call TimerAttachReal(whichTimer, "snowball", "speed", speed)
endfunction

The callback, SnowballSpellCallback can then look like this:
Collapse JASS:
function SnowballSpellCallback takes nothing returns nothing
    //This timer was earlier created with SA_TimerStartNew()
    local integer whichTimer = SA_Timer(GetExpiredTimer())
    //Get the unit stored in key "caster" in the local domain "snowball" on the timer.
    local unit caster = TimerGetUnit(whichTimer, "snowball", "caster")
    //Get the speed attached to the timer.
    local real speed =  TimerGetReal(whichTimer, "snowball", "speed")
    //Do some spell-stuff
endfunction

The local domain is good for two things. First, it guarantees that the keys don't collide with any global keys, which means the following is safe.
Collapse JASS:
call UnitAttachGroup(whichUnit, "global", "g", someGroup)
call UnitAttachGroup(whichUnit, "snowball", "g", someOtherGroup)

//g1 becomes someGroup
set g1 = UnitGetGroup(whichUnit, "global", "g")
//g2 becomes someOtherGroup
set g2 = UnitGetGroup(whichUnit, "snowball", "g")

So the local domain makes it easy to not worry about colliding with global, non-specific keys.

The second benefit is that SmartAttach can optimize memory usage, sharing memory between two local domains that cannot exist at the same time. Which brings me to the next point, every object can only have ONE local domain.
Collapse JASS:
local integer whichUnit = SA_Unit(GetTriggerUnit())
//So far so good
call UnitAttachItem(whichUnit, "snowball", "fun", someItem)
//WRONG: the "snowball" local domain and "other_domain" for the same 
//object makes both this AND THE PREVIOUS LINE incorrect.
call UnitAttachItem(whichUnit, "other_domain", "fun", someItem)

//WRONG: It doesn't make a difference if the keys are different.
call UnitAttachItem(whichUnit, "other_domain", "other_key", someItem)

Other notes: You can NOT use a variable for domain or key.
Collapse JASS:
//WRONG: 'some_variable' is not a "literal" string
call UnitAttachInt(someUnit, some_variable, "key")
//WRONG: still not a literal string
call UnitAttachInt(someUnit, "wawa" + I2S(10), "key")
//CORRECT: A simple literal string please!
call UnitAttachInt(someUnit, "domain", "key")

To summarize domains, remember that you can always store and read anything from the "global" domain, and use a local domain only for objects that serve a special purpose, and only ONE local domain for any given object.

Cleaning up
Finally, all that is created must be destroyed. For every Unit, Item or Timer that is EVER converted to an integer using SA_Unit, SA_Item or SA_Timer, a corresponding SA_UnitRelease, SA_ItemRelease, SA_TimerRelease must be called. The functions take two boolean arguments that should normally be set to true.
Collapse JASS:
local integer whichItem = SA_Item(GetManipulatedItem())
//...Later (may be in another function)
call SA_ItemRelease(whichItem, true, true)

Now to make one thing clear. You only need to call for example SA_ItemRelease when the item is destroyed. You do NOT have to call it at the end of functions to prevent leaks or anything like that. You can call SA_Item(someItem) a million times for the same item, the only thing you need to remember is to call SA_ItemRelease ONCE (AND ONLY ONCE) when the item leaves the game. The same goes for units and timers.

What's with the two boolean parameters?
Hidden information:
The first is whether or not to nullify global values and the second is whether to nullify local domain values on release. This is strongly recommended, unless you wish to optimize by manually nullifying the variables. (But there is not much speed to gain anyway)


Once you call SA_ItemRelease(someItem) you do NOT pass the value of someItem to any other function.

Syntax Summary
This may sound like a whole lot of things, so let's summarize it to see how easy it really is:
Collapse JASS:
//A unit
local unit u = CreateUnit(parameters)
//Get an integer that can be passed to all SA functions.
local integer whichUnit = SA_Unit(u)
//Attach a value
call UnitAttachInt(whichUnit, "global", "your_value", 100)
//Retreives the value
set your_value UnitGetInt(whichUnit, "global", "your_value")

//At some point, i.e unit dies event:
//Take the dying unit, convert it to an SA_Unit integer, and release it.
call SA_UnitRelease(SA_Unit(GetDyingUnit()), true, true)

That's 95% of the functionality right there.


How to use with a map?

Some advanced JASSers have probably guessed that this system does a lot of peculiar things. To make it all work, you have to
  1. Insert a chunk of code called SmartAttach Definitions into the custom script section of your map. (This is only needed once)
  2. 'compile' the map using my SmartAttach.exe tool before playing it in War3. (i.e, on the command line, SmartAttach.exe -f YourMap.w3x -o YourMapCompiled.w3x).

Attached is a beta-version of the SmartAttach compiler and a test map that shows smart attach in action using a large amount of 0.04 timers, storing and retreiving values and moving objects without lag. If you wish to try out SmartAttach, copy the declarations from the test-maps custom script section into your own map before compiling. Note that the compiler is beta, so tell me if it works or not.

About the test-map: For every unit you summon, that unit will be "linked" to a RANDOM unit on the map. If that unit dies, so does the link-unit. Summon a lot and watch it to know what I mean :)
Attached Files
File Type: w3x SmartAttachTest.w3x (55.7 KB, 53 views)
File Type: rar SmartAttachBeta1.rar (1.34 MB, 54 views)

Last edited by karukef : 08-22-2006 at 01:12 AM.
karukef is offline  
Sponsored Links - Login to hide this ad!
Old 08-30-2006, 11:24 AM   #2
PitzerMike
Alcopops
 
PitzerMike's Avatar


Tools & Tutorials Moderator
 
Join Date: Jan 2003
Posts: 2,794

Submissions (12)

PitzerMike is a splendid one to behold (643)PitzerMike is a splendid one to behold (643)PitzerMike is a splendid one to behold (643)PitzerMike is a splendid one to behold (643)

Approved Map: Pitzer's Minesweeper

Default

Personally I don't mind wrappers over constructors and destructors. Afterall it won't take me longer to write SA_TimerNew() instead of CreateTimer(). And the rest is exactly as easy as using gamecache with CSCache.

So I really don't see any reason not to use this, as it's much faster than gamecache. The one domain per object rule helps keeping it organized, I don't have a problem with that.

I'm not sure what Vex is using for his new CSCache (is it available already?), but of course then we'll have to compare speeds again and see what is the overall better solution. But for now this beats gamecache.
__________________
Zoom (requires log in)
PitzerMike is offline  
Old 08-30-2006, 03:13 PM   #3
shadow1500
STARCRAFT II OMFG
 
shadow1500's Avatar
 
Join Date: Jul 2004
Posts: 1,004

Submissions (9)

shadow1500 is just really nice (306)shadow1500 is just really nice (306)shadow1500 is just really nice (306)

Send a message via ICQ to shadow1500 Send a message via AIM to shadow1500 Send a message via MSN to shadow1500
Default

Quote:
Other notes: You can NOT use a variable for domain or key.
Collapse JASS:
//WRONG: 'some_variable' is not a "literal" string
call UnitAttachInt(someUnit, some_variable, "key")
//WRONG: still not a literal string
call UnitAttachInt(someUnit, "wawa" + I2S(10), "key")
//CORRECT: A simple literal string please!
call UnitAttachInt(someUnit, "domain", "key")
This can be a big limitation at times, many of my systems use a variable in the keys. I probably cant use this.
shadow1500 is offline  
Old 08-30-2006, 03:47 PM   #4
PipeDream
Moderator
 
PipeDream's Avatar


Code Moderator
 
Join Date: Feb 2006
Posts: 1,405

Submissions (6)

PipeDream is a glorious beacon of light (463)PipeDream is a glorious beacon of light (463)PipeDream is a glorious beacon of light (463)PipeDream is a glorious beacon of light (463)

Default

That is rarely a limitation. The vast majority of game cache use is for structure-like use which this compiles down *statically*. For arrays there are several alternative options including one karu is cooking up.
It would be neat if use of variables switched it from static compilation to array use but that's also an inconsistency in internal behavior. You can argue both ways about whether or not it should automatically decide whether or not to work in all situations.
__________________
PipeDream is offline  
Old 08-30-2006, 07:16 PM   #5
karukef
User
 
Join Date: Jan 2004
Posts: 388

karukef has a spectacular aura about (97)karukef has a spectacular aura about (97)karukef has a spectacular aura about (97)karukef has a spectacular aura about (97)

Default

Before I start this post, I would like to point out one thing: In any case where SmartAttach for some reason does not fit the need of a given problem, GameCache can be used. (GameCache will even be slightly faster than usual, as the normal I2S call is replaced with an inlined array reference).

===

Yeah, I did toy with the idea of automatically detect whether key is a variable, but in addition to Pipe's argument that it makes for inconsistent behaviour, I also strongly believe that invariable keys are best practice.

Attaching "key" to unit covers a specific purpose, namely that of structuring data around an object. When you wish to attach variable data to an object, it is usually because you want to attach multiple values, right?

That is why I recently added both SmartStack and SmartArray, which will further extend the cases in which the system can be used.

SmartStack is mostly a tool used internally (although it certainly has other uses), but SmartArray should be greatly beneficial for anyone. For example, you can define a smart array named "Snowballs" that holds units and give it a size of max 32 elements with maximum for example 128 such arrays alive at any give time. (Those values are of course configured seperately for every defined SmartArray)

Collapse JASS:
function SnowballSpell takes unit caster, integer num, real damage returns nothing
    local integer i = 0
    local unit u
    //Get a new "Snowballs" array
    local integer unit_array = UnitArrayNew("Snowballs")
    loop
        exitwhen i == num
        //Create a snowball unit
        set u = CreateUnit(...)
        //Attach the damage to the newly created snowball
        call UnitAttachReal(SA_Unit(u), "Snowball", "damage", damage)
        //Attach the caster unit to the snowball so that damage dealt later can come from the right source
        call UnitAttachUnit(SA_Unit(u), "Snowball", "source", caster)
        //Add the snowball unit to the array at position 'i'
        call UnitArraySet("Snowballs", unit_array, i, u)
        set i = i + 1
    endloop
    //Finally, attach the entire array of snowballs to a new timer that can move them around etc (the array is just an integer remember)
    call TimerAttachInteger(SA_TimerStartNew(0.04, True, function SnowballMove), "Snowball", "snowball_array", unit_array)
endfunction

//SnowballMove could look like this
function SnowballMove takes nothing returns nothing
    local integer i = 0
    local integer t = SA_Timer(GetExpiredTimer())
    local integer unit_array = TimerGetInteger(t, "Snowball", "snowball_array")
    loop
        //Do stuff with each snowball
    endloop
endfunction

There are still some details I need to figure out to make SmartArrays even more flexible. That's why any feedback like, "with this system I can't do this" or even better "how can I do X with this system?" is very valuable.

Thanks for the feedback so far though, I've been very lucky to have some clever people to chat with while implementing this and I am close to a release of the entire toolset which should make using SmartAttach painless.
karukef is offline  
Old 08-31-2006, 11:11 AM   #6
Toadcop
BuranX
 
Toadcop's Avatar
 
Join Date: Jul 2006
Posts: 1,886

Submissions (4)

Toadcop is just really nice (299)Toadcop is just really nice (299)

Approved Map: TcXSpell Making Session 10 Winner

Send a message via ICQ to Toadcop
Default

My Buran Lib is lower but more universal http://xgm.ru/forum/attachment.php?attachmentid=8509

PS the code is in common.j =) is more handly for all...
Toadcop is offline  
Old 08-31-2006, 01:54 PM   #7
iNfraNe
PhD
 
iNfraNe's Avatar


Cinematics Moderator
 
Join Date: Dec 2003
Posts: 2,283

Submissions (7)

iNfraNe is just really nice (266)iNfraNe is just really nice (266)iNfraNe is just really nice (266)iNfraNe is just really nice (266)iNfraNe is just really nice (266)

Approved Map: Mortar Ball

Send a message via MSN to iNfraNe
Default

This seems nice. I wont use it since I enjoy making systems myself. I've just got a question.

Collapse JASS:
function SA_ly takes location l returns location
    return GetLocationY(l)
    return null
endfunction
and
Collapse JASS:
function SA_GetLocationY_Loc takes location loc returns location
    set bj_enumDestructableCenter=SA_ly(loc)
    return bj_enumDestructableCenter
endfunction
Whats the use of the second function?
__________________
Ever so slightly active.
Table:
Past Projects:
The Spirit of Vengeance (Cinematic, Blizzard contest winner)
Elimination Tournament
Mortar Ball
iNfraNe is offline  
Old 08-31-2006, 02:52 PM   #8
shadow1500
STARCRAFT II OMFG
 
shadow1500's Avatar
 
Join Date: Jul 2004
Posts: 1,004

Submissions (9)

shadow1500 is just really nice (306)shadow1500 is just really nice (306)shadow1500 is just really nice (306)

Send a message via ICQ to shadow1500 Send a message via AIM to shadow1500 Send a message via MSN to shadow1500
Default

Because there's a problem with return-bugging reals, storing them in a variable first fixes it.
shadow1500 is offline  
Old 08-31-2006, 06:12 PM   #9
Anitarf
Procrastination Incarnate


Development Director
 
Join Date: Feb 2004
Posts: 8,190

Submissions (19)

Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)

2008 Spell olympics - Fire - SilverApproved Map: Old School Alliance TacticsHero Contest #2 - 3rd PlaceSpell making session 2 winner

Default

As a user, I am not satisfied with having to run another program over the map after I save it to make it work. Could you do without that?

Also, what's the use of having domains anyway? We could always inline the domain string into the key if we needed to organise stuff, so I see no need for it. It only complicates matters because you can't have more than two of them anyway.
__________________
Anitarf is offline  
Old 09-01-2006, 08:10 AM   #10
karukef
User
 
Join Date: Jan 2004
Posts: 388

karukef has a spectacular aura about (97)karukef has a spectacular aura about (97)karukef has a spectacular aura about (97)karukef has a spectacular aura about (97)

Default

@iNfraNe: Yeah, we all love to make our own systems :D Also, I'd like to point out that I don't use location stacks anymore, assuming that's where you saw that code. SmartAttach now uses it's own SmartStack for internal stacks, which is a gazillion times faster :)

@Anitarf: I have not really disclosed the details of this system, but to answer your questions of whether an external program is needed, I have to do that.

Why a compiler: Basically, the compiler transforms all the above mentioned calls into tiny inlined set/get array calls. This makes a Get/Set functions so fast that, compared to GC Get/Set, it takes 0 time. And yes, I mean virtually 0 time.

Now I am aware of people's general resistance to doing something as mind bogglingly time consuming and exhausting as having my GUI program running in the background and press 'Compile' every time they save their map. ;) Luckily, PipeDream's Grimoire let's my soon to be released full compiler automatically parse the map as soon as you press Test Map in the world editor. And as a bonus, you get to use PJASS for syntax checking.

So, I really do hope that I do not have to hear any "this is too difficult" arguments, because I really do believe that this system should be used by any advanced mappers needing to attach variables.

Why domains: As for the need for domains I'd be glad to explain why it is of prime importance. First, I consider it cleaner to have a seperate 'domain' and 'key' system as opposed to ad-hoc and non-enforced "domain_key" unique keys. It enforces the use of a domain (even if that domain is global, but believe me, 'global' will not be the most used domain in practice), and the enforcement is by itself important.

Second, again I have to delve into the implementation, all local domains share memory. Because object A (i.e a timer) by definition 'exists' in only one local domain, the implementation can use this to optimize memory usage. TimerAttachUnit(t, "Snowballs", "caster", u) may very well use the same memory location as TimerAttachUnit(t, "FireSpell", "target", u).

This memory sharing is important, because without it a very large and complex maps would end up with an excessive amount of memory usage.

As for whatever Toadcop posted, I can only say that if it does not need a compiler to transform, it isn't anything like this system.

It is about time I write down a detailed explanation of what this system really does that makes it so much better than GC, because I certainly admit without that knowledge, the need for SmartAttach might be hard to figure out :)



Also, here is a few additions I am adding to it today:

Collapse JASS:
//Create a unique Id integer that can have values attached to it
//Good when you need to attach stuff to just 'anything'.
//A complex spell might just create a new id, attach a bunch of data
//to it, and then attach this Id to related units, timers etc.
set id = SA_IdNew()
call IdAttachXXX(id, "domain", "key", value)
call IdGetXXX(id, "domain", "key")

//Also, to make SmartArrays 100 times more useful,
//all kinds of SmartArrays support Push/Pop/Remove/Size

//Puts 'u' to the end of the array-as-stack
if UnitArraySize("Fireparticles", i) < 32 then
    call UnitArrayPush("Fireparticles", i, u)
endif
//Retreives and removes the last unit in the array-as-stack
if UnitArraySize("Fireparticles", i) > 0 then
    set u = UnitArrayPop("Fireparticles", i)
endif
//Finds and removes the unit u from the array-as-stack
call UnitArrayRemove("Fireparticles", i, u)

//Loop through all items
set x = 0
loop
    exitwhen x == UnitArraySize("Fireparticles", i)
    call EatUnitAlive(UnitArrayGet("Fireparticles", i, x))
    set x = x + 1
endloop

//Note: You either use a SmartArray as a stack or as an array
//not both at the same time. Although, looping through it as above
//is just fine :)

Last edited by karukef : 09-01-2006 at 08:19 AM.
karukef is offline  
Old 09-01-2006, 08:49 PM   #11
Anitarf
Procrastination Incarnate


Development Director
 
Join Date: Feb 2004
Posts: 8,190

Submissions (19)

Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)Anitarf has a brilliant future (903)

2008 Spell olympics - Fire - SilverApproved Map: Old School Alliance TacticsHero Contest #2 - 3rd PlaceSpell making session 2 winner

Default

Quote:
Originally Posted by karukef
So, I really do hope that I do not have to hear any "this is too difficult" arguments, because I really do believe that this system should be used by any advanced mappers needing to attach variables.
Not too difficult, just impractical for public systems. I can't release a new version of my cinematic system and say: hey, ok, this is how things go now, for making cinematics with this you need all these addons to your editor to be able to make it work.
__________________
Anitarf is offline  
Old 09-01-2006, 09:43 PM   #12
PipeDream
Moderator
 
PipeDream's Avatar


Code Moderator
 
Join Date: Feb 2006
Posts: 1,405

Submissions (6)

PipeDream is a glorious beacon of light (463)PipeDream is a glorious beacon of light (463)PipeDream is a glorious beacon of light (463)PipeDream is a glorious beacon of light (463)

Default

Quote:
Not too difficult, just impractical for public systems. I can't release a new version of my cinematic system and say: hey, ok, this is how things go now, for making cinematics with this you need all these addons to your editor to be able to make it work.
It's difficult to have progress if you don't build on the work of others. Maybe there will be false starts, but you've got to take some gambles to win.
__________________
PipeDream is offline  
Old 09-02-2006, 08:21 AM   #13
karukef
User
 
Join Date: Jan 2004
Posts: 388

karukef has a spectacular aura about (97)karukef has a spectacular aura about (97)karukef has a spectacular aura about (97)karukef has a spectacular aura about (97)

Default

Quote:
Originally Posted by Anitarf
Not too difficult, just impractical for public systems. I can't release a new version of my cinematic system and say: hey, ok, this is how things go now, for making cinematics with this you need all these addons to your editor to be able to make it work.

Actually, if you want, you can do exactly that. But I can certainly understand why you wouldn't want that.

I wouldn't recommend using SmartAttach just for the sake of using it. How much speed impact does Get/Set values have in your cinematic system? Would it even matter? Unless SmartAttach lets your system do more with less lag, and noticably so, it doesn't really need to use it does it?

I can not decide for others where SmartAttach will be of use, but I at least want to make it clear that using the system isn't cumbersome to use. In fact, compared to the work involved in implementing someones system, copying triggers and whatnot, this compiler is a piece of cake. You just run it on a map or let WE run it on your map.


Some more complete docs and a first release seem to be coming up this weekend and I hope people will keep their minds open until the real thing is here. Again, thanks for the feedback :)
karukef is offline  
Old 10-03-2006, 11:09 PM   #14
aquilla
User
 
aquilla's Avatar
 
Join Date: Mar 2003
Posts: 217

Submissions (1)

aquilla will become famous soon enough (71)aquilla will become famous soon enough (71)aquilla will become famous soon enough (71)

Send a message via MSN to aquilla
Default

Collapse JASS:
//Create a unique Id integer that can have values attached to it
//Good when you need to attach stuff to just 'anything'.
//A complex spell might just create a new id, attach a bunch of data
//to it, and then attach this Id to related units, timers etc.
set id = SA_IdNew()
call IdAttachXXX(id, "domain", "key", value)
call IdGetXXX(id, "domain", "key")
How does this id thing work? I mean, it seems it doesn't take a handle, how would you be able to get the id from what you attached it to?
__________________
You don't care what I've listened to lately
but I'll tell you anyway,
because that's the only thing I'm good at.
aquilla is offline  
Old 10-03-2006, 11:58 PM   #15
karukef
User
 
Join Date: Jan 2004
Posts: 388

karukef has a spectacular aura about (97)karukef has a spectacular aura about (97)karukef has a spectacular aura about (97)karukef has a spectacular aura about (97)

Default

That's a good question. IDs are something that haven't been explained well.

Lets say you are making a spell that creates some STUFF and FX and, you know, whatever a spell makes. I would write that using an ID.

Collapse JASS:
function AwesomeSpell takes unit caster, unit target, real damage returns nothing
    //Create a new id to store all sorts of spell stuff in.
    local integer spell_id = SA_IdNew()
    //Create a timer to handle the periodic activity of the spell
    local integer spell_timer = SA_TimerStartNew(0.05, true, function AwesomeSpellHandle)
    //Attach the caster of the spell to the id
    call IdAttachUnit(spell_id, "AwesomeSpell", "caster", caster)
    //Attach the target of this spell
    call IdAttachUnit(spell_id, "AwesomeSpell", "target", target)
    //Attach the damage the spell does
    call IdAttachReal(spell_id, "AwesomeSpell", "damage", damage)
    //Attach this id to the timer
    call TimerAttachInt(spell_timer, "AwesomeSpell", "spell_id", spell_id)
    //Done, now let the handle function do it's job
endfunction

//The following function should be ABOVE, but I put it below to make it more readable
function AwesomeSpellHandle takes nothing returns nothing
    //Retreive the id of the spell
    local integer spell_id = TimgerGetInt(SA_ExpiredTimer(), "AwesomeSpell", "spell_id")
    //Get the stuff we stored
    local unit caster = IdGetUnit(spell_id, "AwesomeSpell", "caster")
    local unit target = IdGetUnit(spell_id, "AwesomeSpell", "target")
    local real damage = IdGetReal(spell_id, "AwesomeSpell", "damage")
    //Now we can do our periodic stuff, whatever that may be.
endfunction

This should make it obvious why IDs are very very powerful. Whatever the spell creates, whether projectiles, special effects, sounds - it can all be stored onto one id, so when you need to cleanup the spell, its all easily stored there.

SA_IdNew() just returns a unique integer. Therefore it must be released using SA_IdRelease(whichId) afterwards to assure you don't run out of unique ids.

If you look at the Lightning Storm example in the WeWarlock beta thread, you will see IDs being used to their potential by creating a multisegmented lightning (that spell uses up to 100+ ids at the same time)

Last edited by karukef : 10-04-2006 at 12:00 AM.
karukef is offline  
Closed Thread


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off


All times are GMT. The time now is 12:16 AM.


Affiliates
The Hubb The JASS Vault Clan WEnW Campaign Creations Clan CBS GamesModding Flixreel Videos

Powered by vBulletin (Copyright ©2000 - 2019, Jelsoft Enterprises Ltd).
Hosted by www.OICcam.com
IT Support and Services provided by Executive IT Services