找回密码
 点一下
查看: 2342|回复: 6

动态数据记录,数组变量的高级应用。

[复制链接]
发表于 2008-3-27 18:17:08 | 显示全部楼层 |阅读模式
在写此章之前,我在编写Jass时,在缓存方面遇到很多的问题,特别是配合ReturnBug系统后,这方面的问题显得更加的棘手。这些问题是什么呢? —— 缓存冲突。
这里的缓存冲突并非是指数据上的冲突。而是一个令人非常尴尬的现像。
比如,当我要作一个技能时,我用缓存记录了A单位,标记为 "A"。过一会,我把A单位删除,直接使用"A"标记记录B单位。这时,"A"标记代表的是B单位。当然,这种情况是很正常的。但在使用ReturnBug后,我们所记录的是单位的整数地址(详见WOW专用编辑器),也就是一个整数纺编号,这个整数编号在没有清空之前,是一直缓存着的。透过“整数地址”我可以得到A单位的整数地址为(假设例举):100486,而B单位的整数地址为:100488,当我们直接删除A单位后,100486所代表的数据为空,按照War3操作HandleTable的规则,B单位的整数地址有时候会“意外”的上调两位,也就是变成了:100486。嗯,这儿就是要点了,当我们没有清空缓存中的"A"标记中所记录的整数地址时,我们在删除A单位后,如果意外地再次使用"A"标记,那么我们很可能就会使用了B单位(当然,这种现像是随机的,因为HandleTable的变化是随机的)。这种情况下,就容易导致许多问题的出现,通常这种现像有人称之为“缓存遗漏”现像,但实际上,并非是缓存被漏掉了,而是HandleTable产生了变化,导到了一些数据指向的变化。这种变化我暂时定义为“缓存与内存的冲突”,简称为“缓存冲突”。
缓存冲突的现像是接触到缓存以及ReturnBug后经常碰到的问题,当然,如果你没有排除内存泄漏的习惯,这个问题发生的几率比较小。但这个问题的存在,引起了不少的麻烦,在我所做的大部分技能中,都采用了"ReturnBugSystem"的缓存体系。有时候测试时,发生一些“怪异”的现像,所以我研究了半天,终于找到一条能够解决这种现像的方法。
请看以下代码:
[jass]
globals
    // -----------------------------------------------------------------
    integer array                   var_Timer_Int
    timer   array                   var_Timer
    integer array                   var_Unit_Int
    unit    array                   var_Unit
    // -----------------------------------------------------------------
endglobals
function Unit_GetNull takes nothing returns integer
    // 取得一个空变量位,反回空变量位的索引
    local integer i = 0
    local integer var = 0
    local boolean exit = false
    loop
        if var_Unit == null then
            set var = i
            set exit = true
        endif
        set i = i + 1
        exitwhen exit
    endloop
    return var
endfunction
function Unit_GetInt takes unit u returns integer
    // 取得一个变量索引
    local integer i = 0
    local integer var = 0
    local boolean exit = false
    loop
        if var_Unit == u then
            set var = i
            set exit = true
        endif
        set i = i + 1
        exitwhen exit
    endloop
    return var
endfunction
function Unit_GetUnit takes integer i returns unit
    // 按引取得变量
    return var_Unit
endfunction
function Unit_SetUnit takes unit u returns integer
    // 动态记录变量,反回所记录数据的索引
    local integer i = Unit_GetNull()
    set var_Unit = u
    set var_Unit_Int   = 14856 + i
    return i
endfunction
function Unit_FlushInt takes integer i returns nothing
    // 清空变量
    set var_Unit = null
    set var_Unit_Int   = 0
endfunction
[/jass]
以上是一个储存临时单位的动态数据系统的示例。为什么称之为动态,是因为可以按照当前数据的情况来灵活分配所记录数据的索引,我们可以使用索引来取得记录一数据。为什么不用缓存记录变量呢,因为变量速度、效率上比缓存快得多。比如。我们记录N个单位,我们只需要记录单位的变量索引,而不是这个单位。通过索引,我们可以取回所记录的数据。变量索引是动态的,当数据不需要使用时,用清空功能就可以释放变量,释放后的变量又可以用来记录新的单位。这个用途,原理上是和War3中的HandleTable很想似的,只不过我们是给的固定索引,在我们没有清理这些索引变量前,这组变量是不能重新用来记录数据的。
通过以前的代码,我们可以轻易的在局部代替ReturnBug+GameCache,减少出错的几率。
发表于 2008-3-27 20:02:33 | 显示全部楼层
恩,貌似不错。。

14856是什么意思

但是如果所有函数都用该数组的话,那么会怎么样?
回复

使用道具 举报

 楼主| 发表于 2008-3-27 20:17:01 | 显示全部楼层
采用的是动态索引,也就是说,会自动找一个没有被赋值的变量,并传回这个变量的索引。虽然索引最高只能达到8142个,但只要及时清空的话,这些足够用了。
14856 是 这个单位的第一个Id号,就是用来区分数据分类的。比如单位的初始Id号为14856 ,那往上加8142才能是下一个数组变量的初始Id号,这个可以用于缓存来储存变量索引。
回复

使用道具 举报

发表于 2008-3-27 21:09:41 | 显示全部楼层
很强大,可以随时自动单位存放在一个单位数组空位之中,想要得时候还可以提取出来,我看到你那里还有timer的,timer也是handle 也应该可以和unit一样的吧,
不过这个变量var_Unit_Int  的作用是什么呢?我看在提取单位的时候好像也没用上啊,就是用它做个标记吗?有i的话也不用它了吧。它是存储后单位的id吗?刚学jass有点迷茫,这个功能应该可以把不少东单位技能什么的关联到一起,然后再通过索引提取出来吧,
回复

使用道具 举报

 楼主| 发表于 2008-3-27 21:44:42 | 显示全部楼层
var_Unit_Int  是我用来记录一个数据的Id编号的,就像是给一个班级的成员排定学号一样,可以做为该数据独有的Id而存在,这个通常可以用来代替H2I返回的Handle地址,不同的是我们使用的我们给数据定义的编号而已,而Handle中,用H2I返回的是War3给Handle的编号。
回复

使用道具 举报

发表于 2008-3-28 10:45:59 | 显示全部楼层
以下是DataSystem关于Timer存值方面的范例

[jass]//这是用来获得Timer数组索引的函数
function GetTimerIndex takes timer tm returns integer
    return H2I(tm) - SYS_TimerStartLoc
endfunction

//这是用来清理存储位置信息的函数
function FlushTimerInfo takes timer t returns nothing
    local integer tmIndex = GetTimerIndex(t)
    set SYS_TimerData_TMDLG[tmIndex] = null
    set SYS_TimerData_UnitGroup[tmIndex] = null
    set SYS_TimerData_I00[tmIndex] = 0
    set SYS_TimerData_I01[tmIndex] = 0
    set SYS_TimerData_I02[tmIndex] = 0
    set SYS_TimerData_I03[tmIndex] = 0
    set SYS_TimerData_I04[tmIndex] = 0
    set SYS_TimerData_I05[tmIndex] = 0
    set SYS_TimerData_I06[tmIndex] = 0
    set SYS_TimerData_I07[tmIndex] = 0
    set SYS_TimerData_I08[tmIndex] = 0
    set SYS_TimerData_I09[tmIndex] = 0
//======实数======================================
    set SYS_TimerData_R00[tmIndex] = 0.00
    set SYS_TimerData_R01[tmIndex] = 0.00
    set SYS_TimerData_R02[tmIndex] = 0.00
    set SYS_TimerData_R03[tmIndex] = 0.00
    set SYS_TimerData_R04[tmIndex] = 0.00
    set SYS_TimerData_R05[tmIndex] = 0.00
    set SYS_TimerData_R06[tmIndex] = 0.00
    set SYS_TimerData_R07[tmIndex] = 0.00
    set SYS_TimerData_R08[tmIndex] = 0.00
    set SYS_TimerData_R09[tmIndex] = 0.00
//======单位=======================================
    set SYS_TimerData_U00[tmIndex] = null
    set SYS_TimerData_U01[tmIndex] = null
    set SYS_TimerData_U02[tmIndex] = null
    set SYS_TimerData_U03[tmIndex] = null
    set SYS_TimerData_U04[tmIndex] = null
    set SYS_TimerData_U05[tmIndex] = null
    set SYS_TimerData_U06[tmIndex] = null
    set SYS_TimerData_U07[tmIndex] = null
    set SYS_TimerData_U08[tmIndex] = null
    set SYS_TimerData_U09[tmIndex] = null
//======物品========================================
    set SYS_TimerData_IT00[tmIndex] = null
    set SYS_TimerData_IT01[tmIndex] = null
    set SYS_TimerData_IT02[tmIndex] = null
    set SYS_TimerData_IT03[tmIndex] = null
    set SYS_TimerData_IT04[tmIndex] = null
    set SYS_TimerData_IT05[tmIndex] = null
    set SYS_TimerData_IT06[tmIndex] = null
    set SYS_TimerData_IT07[tmIndex] = null
    set SYS_TimerData_IT08[tmIndex] = null
    set SYS_TimerData_IT09[tmIndex] = null
//======特效========================================
    set SYS_TimerData_E00[tmIndex] = null
    set SYS_TimerData_E01[tmIndex] = null
    set SYS_TimerData_E02[tmIndex] = null
    set SYS_TimerData_E03[tmIndex] = null
    set SYS_TimerData_E04[tmIndex] = null
    set SYS_TimerData_E05[tmIndex] = null
    set SYS_TimerData_E06[tmIndex] = null
    set SYS_TimerData_E07[tmIndex] = null
    set SYS_TimerData_E08[tmIndex] = null
    set SYS_TimerData_E09[tmIndex] = null
endfunction

function InitTimerSlotArray takes nothing returns nothing
    local integer i = 1
    local timer t = CreateTimer()
    set SYS_TimerMaxNum = 8000
    set SYS_TimerStartLoc = H2I(t)
    set SYS_TimerSlotArray[0] = 0
    loop
       exitwhen(i>SYS_TimerMaxNum)
       set t = CreateTimer()
       set SYS_Timer = t
       set SYS_TimerSlotArray = i
       set i = i + 1
    endloop
    set SYS_TimerSlotArrayP = SYS_TimerMaxNum
    set SYS_TimerSlotArrayP2 = 0
    set SYS_TimerArrayFlag = true
    set SYS_TimerNum = 0
endfunction

//从timer堆中获得一个空闲Timer的函数
function GetTimer takes nothing returns timer
    local integer tIndex
    if(SYS_TimerArrayFlag)then
       set tIndex = SYS_TimerSlotArray[SYS_TimerSlotArrayP]
       set SYS_TimerSlotArrayP = SYS_TimerSlotArrayP - 1
       if(SYS_TimerSlotArrayP<=0)then
          set SYS_TimerArrayFlag = not(SYS_TimerArrayFlag)
       endif
    else
       set tIndex = SYS_TimerSlotArray2[SYS_TimerSlotArrayP2]
       set SYS_TimerSlotArrayP2 = SYS_TimerSlotArrayP2 - 1
       if(SYS_TimerSlotArrayP2<=0)then
          set SYS_TimerArrayFlag = not(SYS_TimerArrayFlag)
       endif
    endif
    if(tIndex>=0 and tIndex<=SYS_TimerMaxNum)then
       return SYS_Timer[tIndex]
    else
       return null
    endif
endfunction

//释放不再使用的Timer
function ReleaseTimer takes timer t returns nothing
    call PauseTimer(t)
    call FlushTimerInfo(t)
    if(not(SYS_TimerArrayFlag))then
       set SYS_TimerSlotArrayP = SYS_TimerSlotArrayP + 1
       set SYS_TimerSlotArray[SYS_TimerSlotArrayP] = H2I(t) - SYS_TimerStartLoc
    else
       set SYS_TimerSlotArrayP2 = SYS_TimerSlotArrayP2 + 1
       set SYS_TimerSlotArray2[SYS_TimerSlotArrayP2] = H2I(t) - SYS_TimerStartLoc
    endif
endfunction[/jass]
回复

使用道具 举报

发表于 2008-3-28 15:03:00 | 显示全部楼层
这个......
IceFrog的做法是 用记录触发器的handle来替代用单位handle  
有些必要记录的 就一个单位一个触发 因为只在触发内部使用 应该不会出现问题
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 点一下

本版积分规则

Archiver|移动端|小黑屋|地精研究院

GMT+8, 2024-11-22 03:42 , Processed in 0.045927 second(s), 19 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表