| 03-01-2007, 02:59 AM | #1 |
I seem to be, not having a hard time with, but a hard time finding away around using game cache while using structs, for ex. I saw in the Caster System, when Vex recycled casters after a certain time, thus when I rewrote my CS, using structs, I did it in the same way: JASS:function EndCasterTimed_Child takes nothing returns nothing local timer t = GetExpiredTimer() local end_caster dat = GetData(t) call EndCaster(dat.u,dat.abil) call dat.destroy() call EndTimer(t) set t = null endfunction function EndCasterTimed takes unit u, integer abil, real time returns nothing local timer t = GetTimer() local end_caster dat = end_caster.create() set dat.u = u set dat.abil = abil call SetData(t,dat) call TimerStart(t,time,false,function EndCasterTimed_Child) set t = null endfunction GetData/SetData == SetCSData/GetCSData now to me this seems like it will leak the stored integer each time it is done, since the data is never cleared, and again, it uses Game Cache another example, when creating a local trigger and using it: JASS:struct movement_struct trigger trig triggeraction ta unit u endstruct function Movement_Ability_Knockback takes nothing returns nothing local movement_struct dat = GetTableInt(I2S(CS_H2I(GetTriggeringTrigger())),"data") // Do Stuff endfunction function Movement_Ability_Start takes unit u returns nothing local movement_struct dat = movement_struct.create() set dat.trig = CreateTrigger() set dat.ta = TriggerAddAction(dat.trig,function Movement_Ability_Knockback) set dat.u = u call TriggerRegisterUnitInRange(dat.trig,u,Movement_Area,null) call SetTableInt(I2S(CS_H2I(dat.trig)),"data",dat) endfunction the only way I could see to get the struct back in the trigger was to store the integer onto the trigger, which again, needs game cache am I missing something here and is there a better way to go about doing such things? |
| 03-01-2007, 03:35 AM | #2 |
For the first question you could do something like this: JASS:globals endcaster array endcaster_ar timer endcaster_timer = CreateTimer() integer endcaster_count = 0 endglobals struct endcaster unit caster integer time = 100 //however many timer expirations you want it to last method time takes nothing returns nothing set this.time = this.time - 1 endmethod endstruct function endcaster_timer_callback takes nothing returns nothing local endcaster dat local integer i loop exitwhen i = endcaster_count set dat = endcaster_ar[i] call dat.time() if dat.time == 0 then //remove caster actions here set endcaster_ar[i] = endcaster_count - 1 set endcaster_count = endcaster_count - 1 call dat.destroy() else set i = i + 1 endif endloop if endcaster_count == 0 then call PauseTimer(endcaster_timer) endif endfunction function AddCasterToStruct takes unit u returns nothing local endcaster dat = endcaster.create() if endcaster_count == 0 then call TimerStart(endcaster_timer, 1, TRUE, function endcaster_timer_callback) endif set dat.caster = u set endcaster_ar[endcaster_count] set endcaster_count = endcaster_count + 1 endfunction For the second question, why are you creating the struct in that function, why not create it in the movement ability knockback function instead? You can then just add it to an array or alternatively you can attach it to the unit using its custom value. |
| 03-01-2007, 04:21 AM | #3 |
i know of your method for the first one, however it was a more of a is there any other way question, since i don't want to have to do that for every spell that I make with timers for the second, what is wrong with where I created the struct? how else would I store the unit and trigger action, so I could get the unit in the function and the trigger action at a later date so I could remove the leak? and again, I do now want to have to go through that whole array method for every spell that I make *Keep in mind that is not the whole trigger, nor is neither function complete with what it has, I just left the parts significant to the question |
| 03-01-2007, 04:42 AM | #4 |
CSData does not use gamecache unless the H2I of the handle exceeds the limit of 16000ish, and if you wanted to avoid it you could just add in more variables for it to store things in. and for your second example why not just do SetCSData on the trigger and use GetCSData on the triggering trigger? I just had an idea for a CSData type system that doesn't even need to use H2I to associate any type of thing with a handle... I should make it... |
| 03-01-2007, 04:56 AM | #5 |
Well if you don't want to do the array thing, I guess your stuck using gamecache, or in certain instances using a unit's custom value. You shouldn't need to make any more arrays to recycle casters though. |
| 03-01-2007, 04:59 AM | #6 |
why would he be stuck using gamecache or custom value? |
| 03-01-2007, 05:06 AM | #7 |
I should say that those are the only easy ways that I personally know of to attach a struct to something. Although if CSData also does not use Gamecache unless necessary as you say, then that is another way. I'm not familiar with Vex's Caster System. Maybe there are other ways? I'd certainly like to know them if there are. |
| 03-01-2007, 05:16 AM | #8 |
JASS:function SetData takes handle h, integer v returns nothing local integer i=CS_H2I(h)-0x100000 if (i>=8191) then call StoreInteger(cscache,"csdata",I2S(i),v) else set cs_array[i]=v endif endfunction function GetData takes handle h returns integer local integer i=CS_H2I(h)-0x100000 if (i>=8191) then return GetStoredInteger(cscache,"csdata",I2S(i)) endif return cs_array[i] endfunction your right, I don't know what I was thinking, it only uses GC if you have used SetData on 8192 things if I am getting this correctly regardless, and I may be wrong, but it seems that storing the things with GC or to an array would still take up the same amount of memory, no? and i think it would make sense to be able to remove the data once you have no need of it anymore, though I may be off my hinges here with that being said, I do see what you mean about me using CSData instead of tables how I did, would make more sense, heh in anycase, it seems that the only method, other then that whole array dealy with the 1 timer, to move structs around is to use CSData, am I right? and I imagine using custom values of units would make it non MUI |
| 03-01-2007, 05:31 AM | #9 |
well, an array already consumes memory when it's created, so filling it with numbers should not make any difference in memory usage (unless I am mistaken). either way this is an infinitesimal amount of space to be "leaked" by an integer. if you really wanted to you could do SetCSData(h, 0) to set the thing back to zero, but I don't think that would make a difference. CSData is forced to use gamecache if the H2I of the object you are associating the integer with is greater than 8190. if you have handles of 8191 or higher in your map (many maps do) you can add an extra storage variable in there. overall i think that the method described in vexorian's tutorial using the Optical Flare as an example is the best method for your typical spell. global array of structs and global integer to know how many times you need to loop, one timer to process every instance of the spell. there is actually no need for associating the struct with any specific handle as long as you have a list of the structs to iterate through. |
| 03-03-2007, 12:45 AM | #10 |
I wrote a textmacro to make it a lot faster to use the array method. JASS://! textmacro StructStuff takes NAME, STRUCTNAME, STRUCTARRAY, GLOBAL, TIMER, FUNCTION //! scope $NAME$ public function Recycle takes $STRUCTNAME$ dat, integer i returns nothing set $STRUCTARRAY$[i] = $STRUCTARRAY$[$GLOBAL$ - 1] set $GLOBAL$ = $GLOBAL$-1 call dat.destroy() endfunction public function Add2StructAr takes $STRUCTNAME$ dat, real period returns nothing if $GLOBAL$ == 0 then call TimerStart($TIMER$, period, TRUE, function $FUNCTION$) endif set $STRUCTARRAY$[$GLOBAL$] = dat set $GLOBAL$ = $GLOBAL$ + 1 endfunction //! endscope //! endtextmacro //! runtextmacro StructStuff("EC","endcaster","endcaster_ar","endcaster_count","endcaster_timer","endcaster_timer_callback") JASS://! runtextmacro StructStuff("newname","newstruct","newstructarray","newglobal","newtimer","new timer callback functin")Here it is for the endcaster struct: JASS:globals endcaster array endcaster_ar timer endcaster_timer = CreateTimer() integer endcaster_count = 0 endglobals struct endcaster unit caster integer time = 100 //however many timer expirations you want it to last method sub takes nothing returns nothing set this.time = this.time - 1 endmethod endstruct function endcaster_timer_callback takes nothing returns nothing local endcaster dat local integer i loop exitwhen i == endcaster_count set dat = endcaster_ar[i] call dat.sub() if dat.time == 0 then //remove caster actions here call EC_Recycle(dat, i) else set i = i + 1 endif endloop if endcaster_count == 0 then call PauseTimer(endcaster_timer) endif endfunction function createcaster takes unit u returns nothing local endcaster dat = endcaster.create() set dat.caster = u call EC_Add2StructAr(dat, 1) endfunction //! textmacro StructStuff takes NAME, STRUCTNAME, STRUCTARRAY, GLOBAL, TIMER, FUNCTION //! scope $NAME$ public function Recycle takes $STRUCTNAME$ dat, integer i returns nothing set $STRUCTARRAY$[i] = $STRUCTARRAY$[$GLOBAL$ - 1] set $GLOBAL$ = $GLOBAL$-1 call dat.destroy() endfunction public function Add2StructAr takes $STRUCTNAME$ dat, real period returns nothing if $GLOBAL$ == 0 then call TimerStart($TIMER$, period, TRUE, function $FUNCTION$) endif set $STRUCTARRAY$[$GLOBAL$] = dat set $GLOBAL$ = $GLOBAL$ + 1 endfunction //! endscope //! endtextmacro //! runtextmacro StructStuff("EC","endcaster","endcaster_ar","endcaster_count","endcaster_timer","endcaster_timer_callback") When I say this is faster, I don't mean it will run faster. I just mean its a lot less coding to do. Edit: Actually this won't work the way it is right now. The textmacro needs to be above the functions, since they call its functions but it also needs to be below the callback function since one of the textmacro functions calls it. The solution would be to split it into two textmacros, one for each function, or to not start the timer in the textmacro. |
| 03-03-2007, 04:15 AM | #11 |
textmacros are indeed useful |
| 03-03-2007, 01:53 PM | #12 |
You can throw the globals in the textmacro too so you don't have to set them up for each struct. Edit: Greatly simplified the textmacro. JASS://! textmacro StructStuff takes STRUCTNAME globals $STRUCTNAME$ array $STRUCTNAME$_ar timer $STRUCTNAME$_timer = CreateTimer() integer $STRUCTNAME$_count = 0 endglobals function Recycle_$STRUCTNAME$ takes $STRUCTNAME$ dat, integer i returns nothing set $STRUCTNAME$_ar[i] = $STRUCTNAME$_ar[$STRUCTNAME$_count - 1] set $STRUCTNAME$_count = $STRUCTNAME$_count-1 call dat.destroy() endfunction function StopTimer_$STRUCTNAME$ takes nothing returns nothing if $STRUCTNAME$_count == 0 then call PauseTimer($STRUCTNAME$_timer) endif endfunction //! endtextmacro //! runtextmacro StructStuff("endcaster") //! textmacro StartTimer takes STRUCTNAME function Add2Ar_$STRUCTNAME$ takes $STRUCTNAME$ dat, real period returns nothing if $STRUCTNAME$_count == 0 then call TimerStart($STRUCTNAME$_timer, period, TRUE, function $STRUCTNAME$_timer_callback) endif set $STRUCTNAME$_ar[$STRUCTNAME$_count] = dat set $STRUCTNAME$_count = $STRUCTNAME$_count + 1 endfunction //! endtextmacro //! runtextmacro StartTimer("endcaster") |
| 07-31-2007, 04:21 PM | #13 |
| 07-31-2007, 04:57 PM | #14 |
I just use CSCache when its needed |
| 07-31-2007, 06:28 PM | #15 |
me too = never |
