# 运行机制推测

注意:本文绝大部分内容均为主观推测​,因此正确性不做保证,仅供参考。

规则会同时在服务器与不同玩家的设备上运行。这保证了所有玩家的体验一致,但也导致了一些问题,例如服务器拥挤的情况下可能会感到不流畅,随机并不是真随机。

部分操作不会立刻生效,因为在OW中,命令的模拟(即实际运行命令)是周期性的,目前大致为16.6ms(60Hz)。又称每16.6ms是一个tick。例如,当你重生一名玩家后,立刻改变玩家的一些属性很可能无效。

所有能在屏幕上显示或能发出声音的东西,包括玩家、建筑、文字、图标、特效等,都可以被称作“实体”,但不包括HUD(广义的)部分。地图工坊仅能操作由地图工坊创建的实体,和一些实体的特定内容(例如访问玩家的部分状态)。地图工坊限制的实体数量,只包括由地图工坊创建的实体,并且所有玩家共享此上限。

# 运行过程

OW的地图工坊很可能是单线程运行的(指规则运行过程)如果没有发生阻塞(即等待动作),则当前的动作会一直运行下去,不会被其他规则打断。

根据我们的测试,我们推测OW的运行过程如下:

  • 维护一个运行队列。
  • 每个tick,进行:
    • 游戏本身的逻辑(如命中判定、移动模拟等)
      • 如果在此过程中,触发了事件(如“玩家造成伤害”等),则将其放入队列。
    • 等待队列是否有到达等待时间或条件不满足的
      • 到达等待时间:加入到执行队列中。
      • 条件不满足:根据动作处理。
    • 检查每个可用的持续事件的条件是否满足,如果满足就加入到执行队列中。
    • 更新部分带有“重新赋值”属性的实体、HUD。
  • 按照运行队列执行。

# 优化建议

# 独立重复运算

目前所观察到的现象表明:持续事件的“条件”、带有“重新赋值”属性的实体、HUD,会在每个tick进行运算。因此,有多个规则使用了同样的运算时,例如:(规则1、规则2、规则3事件均为“持续 - 每名玩家”)

  • 规则1:相距距离(事件玩家, 全局变量(A)) < 5
  • 规则2:相距距离(事件玩家, 全局变量(A)) > 0
  • 规则3:相距距离(事件玩家, 全局变量(A)) == 5

则可以写为:

  • 规则A:
    • 事件:持续 - 每名玩家
    • 动作:
      • 设置玩家变量(事件玩家, B, 相距距离(事件玩家, 全局变量(A)))
      • 等待(0.016, 无视条件)
      • 循环
  • 规则1:玩家变量(事件玩家, B) < 5
  • 规则2:玩家变量(事件玩家, B) > 0
  • 规则3:玩家变量(事件玩家, B) == 5

这样写有一个小问题:本来响应条件变化的时间不超过16.7ms,但现在则不超过33.3ms。但一般不会有太大负面作用。

另外,直接读取属性(如玩家是否按下按键、玩家的生命值、游戏时间等)的操作其实优化空间并不大,所以不需要单独独立出来。

# 模拟局部变量

目前所观察到的现象表明:若无“等待”动作,规则运行不会被中断。因此,单个规则中若有多个同样的运算时,例如:

  • 根据条件跳过(相距距离(事件玩家, 全局变量(A)) < 5, 1)
  • // xxx
  • 根据条件跳过(相距距离(事件玩家, 全局变量(A)) > 10, 1)
  • // xxx
  • 根据条件跳过(相距距离(事件玩家, 全局变量(A)) > 20, 1)
  • // xxx

则可以写为:

  • 设置玩家变量(事件玩家, B, 相距距离(事件玩家, 全局变量(A)))
  • 根据条件跳过(玩家变量(事件玩家, B) < 5, 1)
  • // xxx
  • 根据条件跳过(玩家变量(事件玩家, B) > 10, 1)
  • // xxx
  • 根据条件跳过(玩家变量(事件玩家, B) > 20, 1)
  • // xxx

# 其他

  • 因为运行机制,“等待”并不完全准确。一次等待时间,误差一般不超过16ms。

# “服务器意外关闭”的猜测

关于“服务器意外关闭”,我们有一些猜测,可能并不完全准确。

  • “运行队列”可能到了某个上限
  • 每个tick运行的时间超过了某个上限

# 参考资料

另外感谢竹子菌 (opens new window)昭华 (opens new window)的协助