找回密码
 点一下
查看: 1455|回复: 9

RPBug(续)

  [复制链接]
发表于 2008-1-25 01:30:03 | 显示全部楼层 |阅读模式
问题还没解决,怎么原先那帖被锁了呢! 渣A你要针对我随你,我没空陪你玩。

======================================朴素的分割线======================================

关于这个RPBug,有新的发现;这是JASS培训班作业,由blandheart提交。以下是代码
[codes=jass]
function H2I takes handle h returns integer
    return h
    return 0
endfunction

function I2U takes integer i returns unit
    return i
    return null
endfunction  
  
function I2TC takes integer i returns triggercondition
      return i
      return null
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




//================================================================================================
//WC函数
function Trig_WC_Conditions takes nothing returns boolean
    local unit Unit1 = GetTriggerUnit()          //获得触发单位
    local trigger trig = GetTriggeringTrigger()    //获得当前触发
    local player P = GetOwningPlayer(Unit1)
    local real x = GetStoredReal(udg_GC,I2S(H2I(trig)),"RectUnitMoveX")    //从缓存中读出目标区域中心的X坐标
    local real y = GetStoredReal(udg_GC,I2S(H2I(trig)),"RectUnitMoveY")    //从缓存中读出目标区域中心的Y坐标
    local integer WCuid = GetStoredInteger(udg_GC,I2S(H2I(trig)),"WCuid")    //从缓存中读出指定单位类型
    local integer WChero = GetStoredInteger(udg_GC,I2S(H2I(trig)),"WChero")    //从缓存中读出指定单位类型
    local integer uid=GetUnitTypeId(Unit1)   
    if WCuid!=uid then
        call DoNothing()                                
      else            
        
        call CreateUnit(P,WChero,x,y,bj_UNIT_FACING)
        call PanCameraToTimedForPlayer(P,x,y,0)    //镜头跟随
        call IssueImmediateOrderById(Unit1,OrderId("stop"))  
            //由于用坐标函数移动单位,单位当前状态不变,因此进洞后会继续移动,所以得让它停下来
    endif  
    call DestroyTriggerAll(trig)
    set Unit1=null
    set trig=null
    return false         
endfunction
                                    

function WCMoveTrigger takes integer Herouid,integer Unituid,rect r1,rect r2 returns nothing
    local real x = GetRectCenterX(r2)      //获得目标区域中心的X坐标
    local real y = GetRectCenterY(r2)      //获得目标区域中心的Y坐标  
    local trigger trig=CreateTrigger()
    call StoreReal(udg_GC,I2S(H2I(trig)),"RectUnitMoveX",x)    // 储存目标区域中心的X坐标  
    call StoreReal(udg_GC,I2S(H2I(trig)),"RectUnitMoveY",y)    // 储存目标区域中心的Y坐标
    call StoreInteger(udg_GC,I2S(H2I(trig)),"WCuid",Unituid)  //存储进入区域单位类型
    call StoreInteger(udg_GC,I2S(H2I(trig)),"WChero",Herouid)  //存储进入区域单位类型  
    call TriggerRegisterEnterRectSimple( trig, r1 )          //以单位进入指定区域为事件
    call TriggerAddCondition(trig,Condition(function Trig_WC_Conditions))    //添加条件
    set trig = null   
endfunction[/codes]

大家看到了,这段代码采用的是老狼的写法,一样是在条件里删除条件,但奇怪的是,我选完了所有英雄,结果都没有弹出游戏,以下是演示
a.w3x (20 KB, 下载次数: 3)

希望大家能继续对这BUG进行探讨,看来这BUG真的是RPBug
发表于 2008-1-25 11:17:02 | 显示全部楼层
everguo大人,这个没有弹出,貌似是因为他没有把triggercondition用缓存记录下来额,所以DestroyTriggerAll只不过是把trigger删了,triggercondition实际是空的额………………
回复

使用道具 举报

发表于 2008-1-25 11:36:00 | 显示全部楼层
嗯...blandheart同学忘记把triggercondition用缓存记录下来了- -
PS:everguo大大....在那个填坑的帖子中,你把我名字打错了.
回复

使用道具 举报

发表于 2008-1-25 11:41:52 | 显示全部楼层
引用第2楼trevors于2008-01-25 11:36发表的  :
PS:everguo大大....在那个填坑的帖子中,你把我名字打错了.

哈哈哈,发现了~~
嗯啊e->a了~~
回复

使用道具 举报

 楼主| 发表于 2008-1-25 13:16:54 | 显示全部楼层
汗   没注意   还真是这样    那么此帖作废吧

to  trevors:不好意思哈,这就改过来
回复

使用道具 举报

 楼主| 发表于 2008-1-25 22:42:00 | 显示全部楼层
原来那个填坑帖实在太长了,我还是在这个帖整理下RPBUG


==================================朴素的分割线=============================


序:
            科学无法解释的问题,我们称之为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 (18 KB, 下载次数: 6)



        那么,为何老狼的代码会弹出游戏,而把条件换成动作就不会出错,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了么——没有,相反才刚开始。
        下面是zhezhutou提供的演示,在这个演示中,当最后一个农民生命值小于50后,就会弹出游戏
rpbug.w3x (19 KB, 下载次数: 6)

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

使用道具 举报

发表于 2008-1-25 23:51:58 | 显示全部楼层
引用第5楼938于2008-01-25 22:42发表的  :
下面是zhezhutou提供的演示,在这个演示中,当最后一个农民生命值小于50后,就会弹出游戏

好吧………………
zhezhutou………………我真变猪头了额………………
回复

使用道具 举报

 楼主| 发表于 2008-1-26 01:00:55 | 显示全部楼层
===================================================================JASS培训班专用分割线===========================================================



十、三个陷阱
      临时赶制的演示,有许多小BUG,不过既然作为给大家当参考,没事改着玩的代码,还是有必要发上来的。
      里面包含三个陷阱:
      火焰陷阱:每隔一段时间吐出火焰;火焰伤害持续时间、陷阱发动间隔时间和火焰长度可以自行修改。
      炸弹陷阱:炸弹人按指定路线巡逻,碰到敌人会爆炸,爆炸后会出现新的炸弹人继续按原来路线巡逻;巡逻路线和巡逻起始方向可以修改。
      刀刃陷阱:刀刃按指定路线来回移动,移动路线和移动速度可以更改。
00.jpg

      希望对大家学习JASS能有帮助
JASS培训班——三个陷阱.w3x (33 KB, 下载次数: 11)
回复

使用道具 举报

 楼主| 发表于 2008-1-26 01:12:17 | 显示全部楼层
厄   已经修正了   在此向你道歉
回复

使用道具 举报

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

也不是这种原因,比如你不flush缓存的话也不会跳错~ 再或者放到某些图里又没事了`~~

再一个极度无敌的现象:

对战初始化
    事件
        单位 - 单位进入 (完整地图区域)
    条件
    动作
        游戏缓存 - 创建游戏缓存,使用文件名: Test.w3v
        设置 GC = (最后创建的游戏缓存)
        设置 hero = (触发单位)
        自定义代码: call RegisterUnitAmortEvent(udg_hero)


于是第一个触发的单位没有跳错,第2次触发则跳错了
这J8的Bug,让我很是不爽~~
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-10-1 19:20 , Processed in 0.060165 second(s), 21 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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