As you can see in the title of this thread, I'm working with a memory system, like Game cache, but without using GameCache. I've been doing that for two weeks and now I'm stuck, so I will need some help
First let me explain a little bit how it works. This system requires a memory pool which is made with an array of locations. Why locations?? because this structure let me save a data pair (x,y) where I use the x value to save the data (using the return bug) and the linked submemory (the location memory using return bug too). Let's see the picture below.
Moyack Memory System:
We can set a subspace for allocationg a permanent memory (for storing data during all the game) and a variable subspace which will be used temporally by spells or other triggers in the game. By default the permanent space = 0, and it can be changeable at run time.
Other feature is that each Slot can have other linked memories, very useful for carrying several variables which can be obtained calling the index of the slot.
How this system manage the space in the non permanent subspace?? well, when you call the function to create a new memory, the system check in the first slots if one of them is free, if so, it assigns that slot to the trigger/spell, and this slot will be identified with a handle index. If in an strange case, you reach the slot 8192, then the system will take the first slot, it will erase it and then it will uses it. Obviously this system has functions to purge the memory, so if you do that, you won't have any problem and the slot system will always use the first free slot in the array.
The usage of this system is like gamecache, but easier. In order to see how it works, I'm going to show a demo spell:
Demo Spell
JASS:
//******************************************************************************//* Moyack's Memory System Test spell. Movement Frenzy. *//******************************************************************************constantfunctionMovement_Frenzy_SpellIDtakesnothingreturnsintegerreturn'A000'endfunctionconstantfunctionMovement_Frenzy_Max_Affected_Unitstakesnothingreturnsintegerreturn5endfunctionconstantfunctionMovement_Frenzy_AOEtakesnothingreturnsrealreturn500.0endfunctionconstantfunctionMovement_Frenzy_SpellDurtakesnothingreturnsrealreturn20.0endfunctionfunctionMovement_Frenzy_Get_Allied_Unitstakesnothingreturnsbooleanlocalunitu = GetFilterUnit()
localplayerp = GetOwningPlayer(GetSpellTargetUnit())
localbooleanb = IsUnitAlly(u, p)
setu = nullsetp = nullreturnbendfunctionfunctionMovement_Frenzy_CopyGrouptakesgroupgreturnsgroupsetbj_groupAddGroupDest = CreateGroup()
callForGroup(g, functionGroupAddGroupEnum)
returnbj_groupAddGroupDestendfunctionfunctionMovement_Frenzy_Tmp1takesnothingreturnsnothing// Controls the lightingslocaltimert = GetExpiredTimer()
localgroupg = H2G(MMSys_GetHandleData(t, 1))
localgroupg1 = Movement_Frenzy_CopyGroup(g)
locallightningarrayllocalunitu1localunitu2localintegeri = 0loopsetu1 = FirstOfGroup(g)
exitwhenCountUnitsInGroup(g1) == 1callGroupRemoveUnit(g1, u1)
setu2 = FirstOfGroup(g1)
setl[i] = H2Ltn(MMSys_GetHandleData(t, i+2))
seti = i + 1callMoveLightning(l[i], true, GetUnitX(u1), GetUnitY(u1), GetUnitX(u2), GetUnitY(u2))
endloopcallDestroyGroup(g1)
setg1 = nullsetu1 = nullsetu2 = nullendfunctionfunctionMovement_Frenzy_Tmp2takesnothingreturnsnothing// Controls the units movementlocaltimert = GetExpiredTimer()
localgroupg = H2G(MMSys_GetHandleData(t, 1))
localgroupg1 = Movement_Frenzy_CopyGroup(g)
localunitulocalrealxlocalrealylocalrealaloopsetu = FirstOfGroup(g1)
exitwhenu == nullseta = GetRandomReal(0, 2 * bj_PI)
setx = GetUnitX(u) + Movement_Frenzy_AOE() * Cos(a)
sety = GetUnitY(u) + Movement_Frenzy_AOE() * Sin(a)
callIssuePointOrder(u, "move", x, y)
callGroupRemoveUnit(g1, u)
endloopcallDestroyGroup(g1)
setg1 = nullendfunctionfunctionMovement_Frenzy_Tmp3takesnothingreturnsnothing// Kill the spells and variableslocaltimert = GetExpiredTimer()
localgroupg = H2G(MMSys_GetHandleData(t, 1))
localtimert1 = H2T(MMSys_GetHandleData(t, 2))
localtimert2 = H2T(MMSys_GetHandleData(t, 3))
locallightningarrayllocalintegeri = 0loopexitwheni == Movement_Frenzy_Max_Affected_Units()-1setl[i] = H2Ltn(MMSys_GetHandleData(t, i+4))
callDestroyLightning(l[i])
setl[i] = nullseti = i + 1endloopcallMMSys_ClearMemorySlot(t) // Free the memory slotcallMMSys_ClearMemorySlot(t1) // Free the memory slotcallMMSys_ClearMemorySlot(t2) // Free the memory slotcallDestroyTimer(t)
callDestroyGroup(g)
callDestroyTimer(t1)
callDestroyTimer(t2)
sett = nullsetg = nullsett1 = nullsett2 = nullendfunctionfunctionMovement_Frenzy_ConditionstakesnothingreturnsbooleanreturnGetSpellAbilityId() == Movement_Frenzy_SpellID()
endfunctionfunctionMovement_Frenzy_Actionstakesnothingreturnsnothinglocalunitc = GetSpellAbilityUnit()
localunitt = GetSpellTargetUnit()
localtimertmp1 = CreateTimer() // Controls the lighting effectlocaltimertmp2 = CreateTimer() // Controls the target movementlocaltimertmp3 = CreateTimer() // Controls the spell durationlocallocationltg = GetUnitLoc(t)
localboolexprCnd = Condition( functionMovement_Frenzy_Get_Allied_Units )
localgroupg = GetUnitsInRangeOfLocMatching( Movement_Frenzy_AOE(), ltg, Cnd)
localgroupg1 = GetRandomSubGroup(Movement_Frenzy_Max_Affected_Units(), g)
locallightningarrayllocalintegeri = 0localunitu1localunitu2callRemoveLocation(ltg)
callDestroyGroup(g)
setg = nullsetg = Movement_Frenzy_CopyGroup(g1)
callMMSys_Create_Memory(tmp1, false, 0) // Sets a memory slot using tmp1 as indexcallMMSys_Create_Memory(tmp2, false, 0) // Sets the next memory slot using tmp2 as indexcallMMSys_Create_Memory(tmp3, false, 0) // Sets the next memory slot using tmp3 as indexcallMMSys_SetHandleData(tmp1, 1, g1) // Stores the unit grouploopsetu1 = FirstOfGroup(g)
exitwhenCountUnitsInGroup(g) == 1callGroupRemoveUnit(g, u1)
setu2 = FirstOfGroup(g)
setl[i] = AddLightning("SPLK", true, GetUnitX(u1), GetUnitY(u1), GetUnitX(u2), GetUnitY(u2))
seti = i + 1callMMSys_SetHandleData(tmp1, i + 2, l[i]) // Stores the lightningcallMMSys_SetHandleData(tmp3, i + 4, l[i]) // Stores the lightning endloopcallDestroyGroup(g)
callMMSys_SetHandleData(tmp2, 1, g1) // Stores the unit groupcallMMSys_SetHandleData(tmp3, 1, g1)
callMMSys_SetHandleData(tmp3, 2, tmp1) // Stores the timer tmp1callMMSys_SetHandleData(tmp3, 3, tmp2) // Stores the timer tmp2callTimerStart(tmp1, 0.05, true, functionMovement_Frenzy_Tmp1)
callTimerStart(tmp2, 2.0, true, functionMovement_Frenzy_Tmp2)
callTimerStart(tmp3, Movement_Frenzy_SpellDur(), true, functionMovement_Frenzy_Tmp3)
setltg = nullsetg = nullsetc = nullsett = nullsetu1 = nullsetu2 = nullendfunction//===========================================================================functionInitTrig_Movement_Frenzytakesnothingreturnsnothinglocaltriggert = CreateTrigger( )
callTriggerRegisterAnyUnitEventBJ( t, EVENT_PLAYER_UNIT_SPELL_EFFECT )
callTriggerAddCondition( t, Condition( functionMovement_Frenzy_Conditions ) )
callTriggerAddAction( t, functionMovement_Frenzy_Actions )
sett = nullendfunction
Usually the first step is to create an empty memory (set a slot with a handle index) the function is the following:
Create memory function:
functionMovement_Frenzy_Actionstakesnothingreturnsnothing...localtimertmp1 = CreateTimer() // Controls the lighting effect...callMMSys_Create_Memory(tmp1, false, 0) // Sets a memory slot using tmp1 as index...endfunction
As you can see, it takes a handle as index, a boolean which indicates if you are going to set a permanent variable and an integer to indicate an index if you use a permanent slot. Because we are using the temporally array pool, we set false and 0 in the second and third parameter.
In order to store and get data, you have the functions:
MMSys_SetHandleData and MMSys_SetRealData to store handle and real variables respectivelly.
MMSys_GetHandleData and MMSys_GetRealData to get handle or real variables respectivelly.
Here are some examples:
Get ans set data functions:
functionMovement_Frenzy_Actionstakesnothingreturnsnothing...callMMSys_SetHandleData(tmp3, 1, g1) // handle index, data index, variable to be stored (handle)...endfunctionfunctionMovement_Frenzy_Tmp2takesnothingreturnsnothing...localtimert = GetExpiredTimer()
localgroupg = H2G(MMSys_GetHandleData(t, 1)) // Gets data using the handle index as reference, // getting the handle variable with index 1...endfunction
To clean the slot for later use by other function, you can do it in the following way:
Clean memory function:
functionMovement_Frenzy_Tmp3takesnothingreturnsnothing// Kill the spells and variableslocaltimert = GetExpiredTimer()
...callMMSys_ClearMemorySlot(t) // Free the memory slot...callDestroyTimer(t)
...sett = null...endfunction
And that's all
Final comment:
Unfortunatelly I'm having problems with the storing part, sometimes it saves the data, other times don't. So I decided to release the code with a test map. I really appreciate if somebody can help me to figure it out what is the bug. And if the system has an impossibility, I really want to know, so we can find other approach.
Any comments, critics, leaks, bug reports, are welcome.
Moyack.
Moyack's Memory System code
JASS:
//******************************************************************************//* *//* Moyack's Memory System *//* *//* version 1.0 *//* *//******************************************************************************globalslocationarrayudg_Memory_Poolintegerudg_PermanentSlots = 0// Sets the slots which won't be automatically erased, they will be the first n slotsintegerudg_MCounter = udg_PermanentSlots// Sets the variable slot index.endglobals//******************************************************************************//* Return Bug functions *//******************************************************************************constantfunctionH2Itakeshandlehreturnsintegerreturnhreturn0endfunctionconstantfunctionI2Htakesintegerireturnshandlereturnireturnnullendfunction//******************************************************************************//* Converters *//* Here you can add the converters you will need in your map. *//******************************************************************************constantfunctionH2Ltakeshandlehreturnslocation// Converts handle to locationreturnhendfunctionconstantfunctionH2Gtakeshandlehreturnsgroup// Converts handle to groupreturnhendfunctionconstantfunctionH2Utakeshandlehreturnsunit// Converts handle to unitreturnhendfunctionconstantfunctionH2Ttakeshandlehreturnstimer// Converts handle to timerreturnhendfunctionconstantfunctionH2Ltntakeshandlehreturnslightning// Converts handle to lightningreturnhendfunction//******************************************************************************//* End converters *//******************************************************************************//******************************************************************************//* this functions make internal memory management (slot detection and edit) *//******************************************************************************functionMMSys_GetFreeSlottakesbooleanIncludePermanentreturnsinteger// Gets first free slot indexlocalintegeriifIncludePermanentthenseti = 0elseseti = udg_PermanentSlotsendifloopexitwhenudg_Memory_Pool[i] == nullseti = i + 1endloopreturniendfunctionfunctionMMSys_MemoryGetIDtakeslocationmemoryreturnsinteger// Determines which memory slot correspond with the memory variable// That location variable must be part of the udg_Memory_Pool arraylocalintegeri = 0loopexitwhenmemory == udg_Memory_Pool[i]
seti = i + 1endloopreturniendfunctionfunctionMMSys_GetMemorybyHandleIndextakeshandleHandleIndexreturnslocation// Gets the main memory slot tagged with the handle Indexlocalintegerhi = H2I(HandleIndex)
localintegerc = 0loopexitwhenR2I(GetLocationX(udg_Memory_Pool[c])) == hisetc = c + 1endloopreturnudg_Memory_Pool[c]
endfunctionfunctionMMSys_EraseMemorytakeslocationmemreturnsnothing// Erase recursivelly the datalocallocationm = H2L(I2H(R2I(GetLocationY(mem))))
ifm != nullthencallMMSys_EraseMemory(m)
endifcallRemoveLocation(m)
callRemoveLocation(mem)
setm = nullsetmem = nullendfunctionfunctionMMSys_Counttakeslocationmemreturnsinteger// Internal Counter functionlocalintegeri = 0locallocationl = Location(GetLocationX(mem), GetLocationY(mem))
loopexitwhenGetLocationY(l) == 0setl = H2L(I2H(R2I(GetLocationY(l))))
seti = i + 1endloopcallRemoveLocation(l)
setl = nullreturniendfunctionfunctionMMSys_SetDatatakeslocationmem, integerindex, realDatareturnsnothing// Sets a data in a submemorylocalrealxlocalrealylocallocationlc = H2L(I2H(R2I(GetLocationY(mem))))
ifindex == 1then// Sets the datasety = GetLocationY(lc)
callRemoveLocation(lc)
setlc = Location(Data, y)
setx = GetLocationX(mem)
sety = I2R(H2I(lc))
callRemoveLocation(mem)
setmem = Location(x, y)
elseiflc == nullthen// Fills empty submemories with zerossetlc = Location(0, 0)
setx = GetLocationX(mem)
sety = I2R(H2I(lc))
callRemoveLocation(mem)
setmem = Location(x, y)
callMMSys_SetData(lc, index - 1, Data)
elseifindex != 1then// Search in the next submemorycallMMSys_SetData(lc, index - 1, Data)
endifendfunctionfunctionMMSys_GetDatatakeslocationmem, integerindexreturnsreal// Gets a data froma submemorylocalrealy = GetLocationY(mem)
locallocationllocalrealr = 0ifindex > 0thenify > 0andindex != 1thensetl = H2L(I2H(R2I(y)))
callMMSys_GetData(l, index - 1)
elseifindex == 1thensetr = GetLocationX(mem)
endifendifreturnrendfunction//******************************************************************************//* End internal Functions *//******************************************************************************//******************************************************************************//* Here's the main functions *//******************************************************************************functionMMSys_ClearMemorySlottakeshandleHandleIndexreturnsnothing// Clear a memory Slotlocallocationmem = MMSys_GetMemorybyHandleIndex(HandleIndex)
callMMSys_EraseMemory(mem)
endfunctionfunctionMMSys_CountDatatakeshandleHandleIndexreturnsinteger// Returns the number of variables stored in a memorylocalintegeri = 0locallocationmem = MMSys_GetMemorybyHandleIndex(HandleIndex)
seti = MMSys_Count(mem)
returniendfunctionfunctionMMSys_SetRealDatatakeshandleHandleIndex, integerIndexData, realvaluereturnsnothing// Sets the real data in the memory alocation, creating a new index if neccesarylocallocationmem = MMSys_GetMemorybyHandleIndex(HandleIndex)
callMMSys_SetData(mem, IndexData, value)
endfunctionfunctionMMSys_SetHandleDatatakeshandleHandleIndex, integerIndexData, handleNewDatareturnsnothing// Sets the handle data in the memory alocationlocallocationmem = MMSys_GetMemorybyHandleIndex(HandleIndex)
callMMSys_SetData(mem, IndexData, I2R(H2I(NewData)))
endfunctionfunctionMMSys_GetRealDatatakeshandleHandleIndex, integerIndexDatareturnsreal// Gets the handle data in the memory alocationlocallocationmem = MMSys_GetMemorybyHandleIndex(HandleIndex)
returnMMSys_GetData(mem, IndexData)
endfunctionfunctionMMSys_GetHandleDatatakeshandleHandleIndex, integerIndexDatareturnshandle// Gets the handle data in the memory alocationlocallocationmem = MMSys_GetMemorybyHandleIndex(HandleIndex)
returnI2H(R2I(MMSys_GetData(mem, IndexData)))
endfunctionfunctionMMSys_SetNewStandardIndextakesnothingreturnsinteger// Autoset a new memory slotifudg_MCounter == JASS_MAX_ARRAY_SIZEthensetudg_MCounter = udg_PermanentSlotselsesetudg_MCounter = MMSys_GetFreeSlot(false)
endifreturnudg_MCounterendfunctionfunctionMMSys_Create_MemorytakeshandleHandleIndex, booleanPermanent, integerPermIndexreturnsboolean// Creates a memory slot.localintegeri = H2I(HandleIndex)
localintegerc = MMSys_SetNewStandardIndex()
ifPermanentthen// Saves in the permanent sectionifPermIndex < udg_PermanentSlotsthencallMMSys_EraseMemory(udg_Memory_Pool[PermIndex])
setudg_Memory_Pool[PermIndex] = Location(I2R(i), 0)
returntrueelsereturnfalseendifelse// Saves in the temporal sectioncallMMSys_EraseMemory(udg_Memory_Pool[c])
setudg_Memory_Pool[c] = Location(I2R(i), 0)
returntrueendifendfunctionfunctionMMSys_Set_PermanentPoolSizetakesintegersizereturnsnothing// Sets the size of the Permanent Poollocalintegeri = 0setudg_PermanentSlots = sizeloopexitwheni == sizecallMMSys_EraseMemory(udg_Memory_Pool[i])
seti = i + 1endloopendfunction//******************************************************************************//* End main functions *//******************************************************************************
Use grimoire(war3err.dll), it is the best (the only) debug environment out there.
I did and it seems you are calling RemoveLocation(null) thousands of times and there is also an op limit hit in the GetMemoryByHandleWhatever function.
That said I don't see why would this system be used above the n alternatives to gamecache already made, so if there is a reason please explain?
It is a system that I'm developing for my project Power of Corruption, and I consider this memory concept interesting and efficient (I want to know if I'm wrong). I just wanted to get some help with it, and if somebody likes it, well, it can use it (when it works 100% fine).
My intention with this system is to share it, and know if it has something really bad or good. That's all.
For that reason I want to know the opinion of good jassers like you.
So at a glance it looks to me like you have an array of lists from which you parcel out slots. I think it could be improved enormously if you replaced the parceller (GetFreeSlot) with a stack. Another thing you could do is replace your lists with tries. Take a number and break it into base 2. Then go through the bits, each time you hit 1 go left through the trie otherwise go right.
Interesting ideas I can say. I added the test map.
I was thinking in something (probably is the reason for a bug with my system) When you create a new location using setl = Location(x, y) if x and/or y are bigger that the map boundaries, the location will be modified to the "closest" inside the map?? In theory it should save the values that you entered.
Thanks PipeDream, I hadn't seen before and it's very interesting.
I'll work with the system (as soon as I fix a problem with my video card, it's broken the hardware acceleration) and I'll try to follow your comments (because I have to figure it out how to implement them :P)