找回密码
 点一下
查看: 4363|回复: 12

关于同步-断线-连接断开问题的测试

[复制链接]
发表于 2008-5-18 22:48:34 | 显示全部楼层 |阅读模式
一直对war3进行多人游戏时的同步机制很困惑,特别是发现GetLocalPlayer函数以后,所以在两台机器上做了一些测试,把测试结果给大家分享一下,可能很浅显,只是在论坛里没有找到讲解这方面问题的帖子

结论1. 全局变量和cache保存的数据是不进行同步的
      定义全局变量integer g_test_num = 0
            在函数里使用
      set g_test_num = GetPlayerId(GetLocalPlayer())
      那么玩家0的g_test_num就是0,玩家1的就是1,完全不会同步,即使过了很长的时间
      
      使用StoreCacheInteger和StoreInteger之类的cache变量操作函数进行操作,cache变量也不会同步

结论2: 如果对象数据不一致,会导致非主机玩家掉线
      其中的"对象"目前测试来看,包括unit, item, destructable, 等常用的界面元素,fogmodifier 不同步没有问题,更多的需要更有经验的前辈们说一下

结论3:每台机器的随机结果一致,如果使用如下的代码,会导致掉线(可能是让某个主机单独执行随机函数导致随机数不同步 )
      if GetLocalPlayer() == GetTriggerPlayer() then
                       set rand_num = GetRandomInt( 0, 100 )
            endif

结论4: 当一个单位被杀死时,实际所有的主机都执行了单位死亡的响应函数,而不是在某个机器上执行后,再把数据同步给其他主机(我开始以后会是这样)
            因为,变量都一致,随机结果也一样,最后单位爆的东西也一样,如果你一定要加上GetLocalPlayer的函数,导致爆出来的东西不一样,对不起,下一秒你就掉线了

最后发现一个有用的东东:
如果一定需要同步的全局变量,可以使用如下类似的方法进行同步
call TriggerSyncStart()
call StoreInteger( cache, "test", "num", ??? )
call SyncStoredInteger( cache, "test", "num" )
call TriggerSyncReady()
主要注意的是:必须在trigger下使用此函数,如果在timer中使用,执行TriggerSyncStart后程序就跑飞了,后面的不会执行
处于Start和Ready之间的语句,应该是只在主机(第一个玩家)上执行,然后ready是把数据发给其他机器


结论:小心的使用GetLocalPlayer函数,这个函数很容易导致掉线问题






         

评分

参与人数 2威望 +12 收起 理由
喀尔硫司之瞳 + 10 原创内容
kook + 2 addition

查看全部评分

发表于 2008-5-18 22:53:35 | 显示全部楼层
哦,这些东西其实已经是很常识的东西了,不过支持LZ的实验精神

至于某些语句是不是只在主机上运行,可以用我的调试器在JASS语句上下断点来看看就知道了
回复

使用道具 举报

 楼主| 发表于 2008-6-16 13:07:14 | 显示全部楼层
回复

使用道具 举报

发表于 2008-6-16 18:09:39 | 显示全部楼层
的确很尝试 不过毕竟有人总结出来还是不错的
从结论四看出数据传的仅仅是动作?而不是具体的数值吧
回复

使用道具 举报

发表于 2008-6-16 18:48:13 | 显示全部楼层
我觉得,相互传递的东西,只有触发的事件。并且事件是被封装到某个结构里传的。
(还有就是读图时,会传递一个随机种子,这样随机函数也会得到同样的值)


很多情况下,玩家的操作都会引发事件,比如移动镜头的位置。
绝大多数的common.j的函数都会引发事件。

接收事件后,war3会处理一些内定的东西,之后给jass脚本写的触发器去处理。 
触发器解理完毕,也要发送一个事件,声明自己完毕了,如果不声明,过了某一个时间,这个触发会被X掉的。

所有机器,因为得到的触发事件是同样的,随机种子也是一样的,那么,就可以认为会执行一样的动作,得到相同的结果。。

当然,有一些东西是不传的,比如,移动一下鼠标,就不会产生事件,虽然鼠标移动到单位的头上时会显示这个单位的血条。

或者说,引发Handle相关类型数据变化的,都能引出掉线。

而下面的代码放在:
if ( GetLocalPlayer()==Player(0) ) then
//...
endif
这样的条件中间,不会出问题。

给某一个玩家创建个闪电了,或是一行漂浮文字,(这两样东西很怪的,Handle值是很BT的)
或是显示一条消息,或是改变一个变量,改几条缓存,都没有什么事的。

还有一个不掉线的,就是让某一特殊玩家选择某一单位。
回复

使用道具 举报

发表于 2008-6-17 16:12:40 | 显示全部楼层
被2楼骗了
回复

使用道具 举报

发表于 2008-12-22 23:58:48 | 显示全部楼层
那么这个同步出来的是哪个值呢?
回复

使用道具 举报

发表于 2008-12-23 00:41:46 | 显示全部楼层
call StoreInteger( cache, "test", "num", ??? )
同步主机上 缓存 存的值..

话说我去试验的...准确率很低啊``
回复

使用道具 举报

发表于 2008-12-23 11:38:10 | 显示全部楼层
不是主机~是可以指定玩家的,在GetLocalPlayer中用的话

注意一点,这里的同步值是一个确切的动作记录而不是模拟过程记录~

比如在我的rep检验中如果只用一个玩家判断,得到true,录像中是false,用这个函数传递给所有玩家的话,得出的结果只有true。因为记录的是“游戏中将一个true传给所有人”,这个动作会在rep中完全再现
回复

使用道具 举报

发表于 2008-12-23 16:32:48 | 显示全部楼层
call SyncStoredInteger
如何指定玩家...

用本地玩家来运行的话...

假设主机没运行..但会同步哪个玩家的数据
回复

使用道具 举报

发表于 2008-12-24 13:58:24 | 显示全部楼层
都说是谁运行就把谁的数据传给所有人来着~
每台机器上的数据,不管是变量、缓存,都是独立存在的,魔兽的同步机制让它们能同时一致;
SyncStoredInteger让一个已经本地StoredInteger了本地值的机器将数据传给所有玩家并存在相应缓存里,这不难理解吧。
所以这个动过过后要经过一个同步时长才传到各机器,比如你要用TriggerSleepAction(0)
使用本地玩家的SyncStoredInteger才是标准用法;如果不用本地玩家会怎么样呢,所有玩家会试图把当前数据传给其他人~
那为什么一般情况下会得到主机胜出的情况,也就是可以用这种方式判断主机呢?
回复

使用道具 举报

发表于 2008-12-24 17:38:11 | 显示全部楼层
好神奇袄。。。本地玩家里的同步缓存也是网络操作啊。。。

可是那么主机应该是最快响应的。。。结果应该是主机几率最少啊。。。

时差后同步时候才读取数据,那时其他玩家的数据已经被主机同步老?
回复

使用道具 举报

发表于 2008-12-26 00:35:09 | 显示全部楼层
都说是谁运行就把谁的数据传给所有人来着~
使用本地玩家的SyncStoredInteger才是标准用法;如果不用本地玩家会怎么样呢,所有玩家会试图把当前数据传给其他人~

可是那么主机应该是最快响应的。。。结果应该是主机几率最少啊。。。

时差后同步时候才读取数据,那时其他玩家的数据已经被主机同步老?

似乎可以解释 判断主机结果不正确``
回复

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-5-2 18:45 , Processed in 0.124663 second(s), 22 queries .

Powered by Discuz! X3.5

© 2001-2023 Discuz! Team.

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