找回密码
 点一下
楼主: hke

移除光出错条件的诡异问题[重新整理]

[复制链接]
 楼主| 发表于 2008-7-14 11:26:55 | 显示全部楼层
你们看过第三个问题没
留下一个触发就不会弹?
回复

使用道具 举报

发表于 2008-7-14 11:28:07 | 显示全部楼层
[jass]function Trig_c_Conditions takes nothing returns boolean
call BJDebugMsg("1")
call TriggerRemoveCondition(gg_trg_c, udg_cond[174])
//call BJDebugMsg("2")
      return false
endfunction

//===========================================================================
function InitTrig_c takes nothing returns nothing
    set gg_trg_c = CreateTrigger(  )
    call TriggerRegisterPlayerEvent(gg_trg_c,Player(0),ConvertPlayerEvent(17))
set udg_cond[174]=TriggerAddCondition(gg_trg_c , Condition(function Trig_c_Conditions))  
endfunction[/jass]


删除条件后如果还有除了返回值外的动作就会弹出
如果把那个动作删了就不弹出
[jass]
function Trig_c_Conditions takes nothing returns boolean
call BJDebugMsg("1")
//call TriggerRemoveCondition(gg_trg_c, udg_cond[174])
call DestroyTrigger(gg_trg_c)
call BJDebugMsg("2")
      return false
endfunction
[/jass]

删除触发的话不会弹出  顺便还看了 删除触发后
条件h2i值还在
回复

使用道具 举报

 楼主| 发表于 2008-7-14 11:34:22 | 显示全部楼层
的确是这样
但是还是不能解释为啥call DestroyTrigger(gg_trg_b)去掉就正常了?
回复

使用道具 举报

发表于 2008-7-14 11:43:31 | 显示全部楼层
只要不在当前触发移除条件就不会弹。


而且火龙你话说的那个过一段时间后不弹,但是我测试还是要弹错。

  1. function func takes nothing returns boolean
  2.           local integer i=0
  3.           local trigger t = GetTriggeringTrigger()
  4.           loop
  5.               exitwhen i>20
  6.               if t == udg_tri[i] then
  7.                   //call TriggerRemoveCondition(udg_tri[i], udg_cond[i])
  8.                   call DestroyTrigger(udg_tri[i])
  9.                   //set udg_tri[i]=null
  10.                   //set udg_cond[i]=null
  11.                   call BJDebugMsg(I2S(i))
  12.               else
  13.                   call TriggerRemoveCondition(udg_tri[i], udg_cond[i])
  14.                   call DestroyTrigger(udg_tri[i])
  15.                   //set udg_tri[i]=null
  16.                   //set udg_cond[i]=null
  17.                   call BJDebugMsg(I2S(i))
  18.               endif
  19.               set i=i+1
  20.           endloop
  21.           set t = null
  22.           return false
  23. endfunction
复制代码
回复

使用道具 举报

 楼主| 发表于 2008-7-14 11:48:38 | 显示全部楼层
不是移除func里面的
是移除那个b里面的
难道我没说清楚
回复

使用道具 举报

发表于 2008-7-14 12:11:50 | 显示全部楼层
果然全部条件没了 就弹。。。
你们继续把。。
我下午消失
回复

使用道具 举报

发表于 2008-7-14 13:04:10 | 显示全部楼层
Destroy触发前  并不一定需要Remove条件和动作的
如果不删除  仅仅只会造成泄漏而已   不会把魔兽弹出的
而且听说 不删除条件所造成的泄露和不删除动作做造成的泄露相比    可以忽略
回复

使用道具 举报

 楼主| 发表于 2008-7-14 13:07:40 | 显示全部楼层
因为我那个需要频繁创建删除触发
泄露的后果是很可观的
不过解决删光出错的方法很简单是留一个触发让他泄露吧
现在问题在于为啥会出现那几个诡异问题
回复

使用道具 举报

发表于 2008-7-14 13:09:45 | 显示全部楼层
关于问题3,我的理解是这样的~~
  1. 你将动作写在了条件中,而触发的默认执行顺序是判断条件函数返回值为真时执行触发的动作函数,一般情况下,程序根据触发的句柄寻找相应的动作,即使一个触发没有动作函数,那么返回NULL,跳过动作,执行下一个队列,而你在条件函数中将触发销毁后,使得该触发的句柄无效,程序无法寻找一无效句柄对应的动作,于是出错弹出。
复制代码
以上纯个人理论,仅供参考~~

事实证明这里纯属胡扯~~
回复

使用道具 举报

 楼主| 发表于 2008-7-14 13:11:13 | 显示全部楼层
不是很理解嗯
跟情况条件有啥关联?
回复

使用道具 举报

发表于 2008-7-14 13:14:35 | 显示全部楼层
    序:
                科学无法解释的问题,我们称之为RP问题。

            今天发布电子书,征集书中的BUG;随后有朋友给我消息,说Return Bug+GameCache的应用(一)中,老狼的代码加入图中会导致崩溃,于是,我看了下这段代码:


    [codes=jass]function H2I takes handle h returns integer
             return h
             return 0
    endfunction
    function I2TC takes integer i returns triggercondition
             return i
             return null
    endfunction
    function I2TG takes integer i returns trigger
             return i
             return null
    endfunction
    function DestroyTriggerAllById takes integer t returns nothing      
                      call TriggerRemoveCondition(I2TG(t),I2TC(GetStoredInteger (udg_GC,I2S(t),"TriggerCondition")))
                      call DestroyTrigger(I2TG(t))
                      call FlushStoredMission(udg_GC,I2S(t))
    endfunction
    function DestroyTriggerAll takes trigger trg returns nothing
                      call TriggerRemoveCondition(trg,I2TC(GetStoredInteger(udg_GC,I2S(H2I(trg)),"TriggerCondition")))
                      call DestroyTrigger(trg)
                      call FlushStoredMission(udg_GC,I2S(H2I(trg)))
    endfunction
    //========================================================
    function RegisterUnitAmortCond takes nothing returns nothing
                               call SetUnitInvulnerable(GetTriggerUnit(), true)
                               call DestroyTriggerAll(GetTriggeringTrigger())
    endfunction
    function RegisterUnitAmortEvent takes unit witchUnit returns nothing
                      local trigger trg = CreateTrigger()
                      call TriggerRegisterUnitStateEvent(trg, witchUnit, UNIT_STATE_LIFE, LESS_THAN_OR_EQUAL, 50)
                      call StoreInteger(udg_GC,I2S(H2I(trg)),"TriggerCondition",H2I (TriggerAddCondition(trg,Condition(function RegisterUnitAmortCond))))
                      set trg = null
    endfunction[/codes]

            这段代码横看竖看都没问题,于是我把它加进地图,果然,弹出来了.于是我暂时把代码中的条件换成了动作

    [codes=jass]function H2I takes handle h returns integer
             return h
             return 0
    endfunction
    function I2TA takes integer i returns triggeraction
             return i
             return null
    endfunction
    function I2TG takes integer i returns trigger
             return i
             return null
    endfunction
    function DestroyTriggerAllById takes integer t returns nothing      
                      call TriggerRemoveAction(I2TG(t),I2TA(GetStoredInteger (udg_GC,I2S(t),"Triggeraction")))
                      call DestroyTrigger(I2TG(t))
                      call FlushStoredMission(udg_GC,I2S(t))
    endfunction
    function DestroyTriggerAll takes trigger trg returns nothing
                      call TriggerRemoveAction(trg,I2TA(GetStoredInteger(udg_GC,I2S(H2I(trg)),"Triggeraction")))
                      call DestroyTrigger(trg)
                      call FlushStoredMission(udg_GC,I2S(H2I(trg)))
    endfunction
    //========================================================
    function RegisterUnitAmortAction takes nothing returns nothing
                               call SetUnitInvulnerable(GetTriggerUnit(), true)
                               call DestroyTriggerAll(GetTriggeringTrigger())
    endfunction
    function RegisterUnitAmortEvent takes unit witchUnit returns nothing
                      local trigger trg = CreateTrigger()
                      call TriggerRegisterUnitStateEvent(trg, witchUnit, UNIT_STATE_LIFE, LESS_THAN_OR_EQUAL, 50)
                      call StoreInteger(udg_GC,I2S(H2I(trg)),"Triggeraction",H2I (TriggerAddAction(trg,function RegisterUnitAmortAction)))
                      set trg = null
    endfunction[/codes]
          运行下,没有问题;因此朋友交给我的任务完成了.不过为何用动作没有问题,而用条件会弹出游戏呢.经过尝试,发现个非常有趣的BUG,大家看这行代码

    [codes=jass]function H2I takes handle h returns integer
             return h
             return 0
    endfunction
    function I2TC takes integer i returns triggercondition
             return i
             return null
    endfunction
    function I2TG takes integer i returns trigger
             return i
             return null
    endfunction

    function DestroyTriggerAllById takes integer t returns nothing      
                      call TriggerRemoveCondition(I2TG(t),I2TC(GetStoredInteger (udg_GC,I2S(t),"TriggerCondition")))
                      call DestroyTrigger(I2TG(t))
                      call FlushStoredMission(udg_GC,I2S(t))
    endfunction
    function DestroyTriggerAll takes trigger trg returns nothing
                      call TriggerRemoveCondition(trg,I2TC(GetStoredInteger(udg_GC,I2S(H2I(trg)),"TriggerCondition")))
                      call DestroyTrigger(trg)
                      call FlushStoredMission(udg_GC,I2S(H2I(trg)))
                      call BJDebugMsg(I2S(0))
    endfunction
    //========================================================
    function RegisterUnitAmortCond takes nothing returns   nothing                                       
                               call SetUnitInvulnerable(GetTriggerUnit(), true)
                               call DestroyTriggerAll(GetTriggeringTrigger())                                          
    endfunction
    function RegisterUnitAmortEvent takes unit witchUnit returns nothing
                      local trigger trg = CreateTrigger()
                      call TriggerRegisterUnitStateEvent(trg, witchUnit, UNIT_STATE_LIFE, LESS_THAN_OR_EQUAL, 50)
                      call StoreInteger(udg_GC,I2S(H2I(trg)),"TriggerCondition",H2I (TriggerAddCondition(trg,Condition(function RegisterUnitAmortCond))))
                      set trg = null
    endfunction[codes]
          大家看这段代码有什么不同,无非是加了段call BJDebugMsg(I2S(0)),这个纠错函数,其实就是显示个字符在屏幕上,并不会影响程序运行,但不可思议的事发生了,这段代码加入后,游戏不会弹出了.

            或许你还没明白我在说什么,我想说的是,将一个语法上百分百没有错误的代码,加入到地图后百分百会弹出,但加了个百分百没有用的call BJDebugMsg(I2S(0))后,游戏就不会出错.

            是不是一个很有趣的BUG~

            放上演示,大家不妨试试,去掉代码中的call BJDebugMsg(I2S(0)),就会弹出游戏。
    未知BUG.w3x (见附件)



            那么,为何老狼的代码会弹出游戏,而把条件换成动作就不会出错,feelerly给出了一个比较好的回答——“在条件动作中不能删除条件”:
          “今天做了很多测试,基本上搞懂了出错的原因:在同个触发器中,不能直接用条件动作来删除该条件。 否则会出错(这个有点奇怪,删除触发器没有事,删条件就有事了)
            根据我的分析, 应该是条件动作没有返回真假值之前,一直处于运行状态,如果直接在没有返回真假值之前就给触发器移除条件,这就相当于你在吃饼的时候,突然咽住了一样(就是内存冲突)
            所以,我们必须在条件返回真假值之后(就是用计时器延时删除)这样就不会出错了。”以下是feelerly给出的代码:


    [codes=jass]function ConvertHandleInt takes handle h returns integer
          return h
          return 0
    endfunction
    function ConvertTrigger takes integer i returns trigger
          return i
          return null
    endfunction
    function ConvertCondition takes integer i returns triggercondition
          return i
          return null
    endfunction
    function TimerDestroyTriggerAll takes nothing returns nothing
          local integer c = GetStoredInteger(bj_lastCreatedGameCache, "T","C")
          local integer t = GetStoredInteger(bj_lastCreatedGameCache, I2S(ConvertHandleInt(GetExpiredTimer())),"T")
          call TriggerRemoveCondition(ConvertTrigger(t), ConvertCondition(c) )
          call DestroyTrigger( ConvertTrigger(t) )
          call FlushStoredMission(bj_lastCreatedGameCache, I2S(ConvertHandleInt(GetExpiredTimer())))
          call FlushStoredMission(bj_lastCreatedGameCache, "T")
          call DestroyTimer( GetExpiredTimer() )
    endfunction
    function Trig_T_Conditions takes nothing returns boolean
          local timer t = CreateTimer()
          call FogEnable( false )
          call FogMaskEnable( false )
          call DisplayTextToPlayer( Player(0), 0,0, "123")
          call StoreInteger( bj_lastCreatedGameCache,I2S(ConvertHandleInt(t)),"T",ConvertHandleInt(GetTriggeringTrigger()))
          call TimerStart( t, 0.05, false, function TimerDestroyTriggerAll )
          return true
    endfunction

    //===========================================================================
    function InitTrig_T takes nothing returns nothing
          local integer i = 0
          set bj_lastCreatedGameCache=InitGameCache("test.m3v")
          set gg_trg_T = CreateTrigger(   )
          call TriggerRegisterPlayerEventEndCinematic( gg_trg_T, Player(0) )
          set i = ConvertHandleInt(TriggerAddCondition( gg_trg_T, Condition(function Trig_T_Conditions) ))
          call StoreInteger( bj_lastCreatedGameCache, "T","C", i )
    endfunction[/codes]

            我补充下,为何“删除触发器没有事,删条件就有事”:因为触发器即便被销毁,也会执行一次;同样的道理,在触发器动作上也适用。
            此外,feelerly的方法,利用到了call与Timer线程的不同。  call 函数的执行是窜行的,而触发器、Timer和ExecuteFunc等执行是并行的;因此,call 函数中执行的函数,也被看做是条件中的一部分,因此这函数中销毁条件,实际是在条件中销毁条件,  条件在没有运行完前就被销毁。
          但使用Timer(其实也可用ExecuteFunc)后,线程关系是并行的,因此这样删除条件,Timer或ExecuteFunc执行的函数,不隶属于条件,它是在条件的外部销毁条件,所以不会出错。

            不过,使用ExecuteFunc也会出错,feelerly猜测ExecuteFunc仍会保持那个进程中的数。

            那么,到目前为止,我们解决这个RPBug了么——没有,相反才刚开始。
            下面是zhuzeitou提供的演示,在这个演示中,当最后一个农民生命值小于50后,就会弹出游戏
    rpbug.w3x (见附件)

                  为何要执行到最后一个农民,程序才会崩溃呢,feelerly说这可能跟JASS的编译有关;目前这个问题仍是无解,我也很想知道为何在老狼代码中加个无用的函数能阻止程序的崩溃。
            很抱歉,身为前辈的我们无法解决这问题,但解决它是你们的目标和任务;如果能解决这BUG,那我们对JASS的认识可以更深一步。


以上为guo教程中的相关内容………………
回复

使用道具 举报

 楼主| 发表于 2008-7-14 13:17:16 | 显示全部楼层
“今天做了很多测试,基本上搞懂了出错的原因:在同个触发器中,不能直接用条件动作来删除该条件。 否则会出错(这个有点奇怪,删除触发器没有事,删条件就有事了)

不是这样吧
你按照3.的描述做
删除条件就不崩溃了
回复

使用道具 举报

发表于 2008-7-14 13:18:44 | 显示全部楼层
    为何要执行到最后一个农民,程序才会崩溃呢,feelerly说这可能跟JASS的编译有关

这句火龙漏了么??
回复

使用道具 举报

发表于 2008-7-14 13:41:23 | 显示全部楼层
引用第31楼hke于2008-07-14 13:17发表的  :
“今天做了很多测试,基本上搞懂了出错的原因:在同个触发器中,不能直接用条件动作来删除该条件。 否则会出错(这个有点奇怪,删除触发器没有事,删条件就有事了)

不是这样吧
你按照3.的描述做
删除条件就不崩溃了

其实是删除任何一个没有事,两个同时删除时就跳出
回复

使用道具 举报

发表于 2008-7-14 14:20:06 | 显示全部楼层
不时地,只删除条件就足够跳出了~~
回复

使用道具 举报

发表于 2008-7-14 14:31:54 | 显示全部楼层
但是我这样写
[jass]
function Trig_test_Conditions takes nothing returns boolean
    //call BJDebugMsg("rm cond")
    //call TriggerRemoveCondition(gg_trg_test,udg_trgcond)
    call BJDebugMsg("des trg")
    call DestroyTrigger( gg_trg_test )
    if ( not ( GetPlayerSlotState(Player(0)) == PLAYER_SLOT_STATE_PLAYING ) ) then
        return false
    endif
    return true
endfunction

function Trig_test_Actions takes nothing returns nothing
    call BJDebugMsg("rm cond")
    call TriggerRemoveCondition(gg_trg_test,udg_trgcond)
    call BJDebugMsg("rm action")
    call TriggerRemoveAction(gg_trg_test,udg_trgact)
    call BJDebugMsg("des trg")
    call DestroyTrigger( gg_trg_test )
    call BJDebugMsg("all done")
endfunction

//===========================================================================
function InitTrig_test takes nothing returns nothing
    set gg_trg_test = CreateTrigger(  )
    call TriggerRegisterPlayerEventEndCinematic( gg_trg_test, Player(0) )
    set udg_trgcond=TriggerAddCondition( gg_trg_test, Condition( function Trig_test_Conditions ) )
    set udg_trgact=TriggerAddAction( gg_trg_test, function Trig_test_Actions )
endfunction
[/jass]

和 这样写

[jass]
function Trig_test_Conditions takes nothing returns boolean
    call BJDebugMsg("rm cond")
    call TriggerRemoveCondition(gg_trg_test,udg_trgcond)
    //call BJDebugMsg("des trg")
    //call DestroyTrigger( gg_trg_test )
    if ( not ( GetPlayerSlotState(Player(0)) == PLAYER_SLOT_STATE_PLAYING ) ) then
        return false
    endif
    return true
endfunction

function Trig_test_Actions takes nothing returns nothing
    call BJDebugMsg("rm cond")
    call TriggerRemoveCondition(gg_trg_test,udg_trgcond)
    call BJDebugMsg("rm action")
    call TriggerRemoveAction(gg_trg_test,udg_trgact)
    call BJDebugMsg("des trg")
    call DestroyTrigger( gg_trg_test )
    call BJDebugMsg("all done")
endfunction

//===========================================================================
function InitTrig_test takes nothing returns nothing
    set gg_trg_test = CreateTrigger(  )
    call TriggerRegisterPlayerEventEndCinematic( gg_trg_test, Player(0) )
    set udg_trgcond=TriggerAddCondition( gg_trg_test, Condition( function Trig_test_Conditions ) )
    set udg_trgact=TriggerAddAction( gg_trg_test, function Trig_test_Actions )
endfunction
[/jass]

都不会跳出
只有这样
[jass]
function Trig_test_Conditions takes nothing returns boolean
    call BJDebugMsg("rm cond")
    call TriggerRemoveCondition(gg_trg_test,udg_trgcond)
    call BJDebugMsg("des trg")
    call DestroyTrigger( gg_trg_test )
    if ( not ( GetPlayerSlotState(Player(0)) == PLAYER_SLOT_STATE_PLAYING ) ) then
        return false
    endif
    return true
endfunction

function Trig_test_Actions takes nothing returns nothing
    call BJDebugMsg("rm cond")
    call TriggerRemoveCondition(gg_trg_test,udg_trgcond)
    call BJDebugMsg("rm action")
    call TriggerRemoveAction(gg_trg_test,udg_trgact)
    call BJDebugMsg("des trg")
    call DestroyTrigger( gg_trg_test )
    call BJDebugMsg("all done")
endfunction

//===========================================================================
function InitTrig_test takes nothing returns nothing
    set gg_trg_test = CreateTrigger(  )
    call TriggerRegisterPlayerEventEndCinematic( gg_trg_test, Player(0) )
    set udg_trgcond=TriggerAddCondition( gg_trg_test, Condition( function Trig_test_Conditions ) )
    set udg_trgact=TriggerAddAction( gg_trg_test, function Trig_test_Actions )
endfunction
[/jass]

才跳出~~
回复

使用道具 举报

发表于 2008-7-14 14:33:12 | 显示全部楼层
但是你可以看那个rpbug,w3x,只需RemoveCondition就会跳了………………
回复

使用道具 举报

 楼主| 发表于 2008-7-14 15:46:37 | 显示全部楼层
话说3并没删除条件嗯
回复

使用道具 举报

发表于 2008-7-14 16:18:51 | 显示全部楼层
那是那个触发被干掉了,条件只是一个无用的triggercondition而已

可能运行时有专门的一个空间是存放应用中的条件的,当某条件自身删除本身的同时使得这一空间变成空的时候会造成某些错误而弹错………………
回复

使用道具 举报

 楼主| 发表于 2008-7-14 16:49:57 | 显示全部楼层

好吧
大概是这样吧
不过为啥每次进这个帖子就感觉很卡...
难道引起了BUG
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-4-27 02:50 , Processed in 0.190323 second(s), 17 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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