|
|
| (未显示同一用户的1个中间版本) |
| 第1行: |
第1行: |
| __NOTOC__
| |
| <div class="mdtLogicTutorial"><span id="引言"></span>
| |
| == 引言 ==
| |
|
| |
|
| 这是《逻辑教学》的超完整版 (进阶篇), 适用于已经掌握基础语句的玩家.
| |
|
| |
| 本教程不是语句词典, 而是偏工程与实战的写法总结.
| |
|
| |
| 基线版本:
| |
| * Mindustry 155
| |
|
| |
|
| |
| ----
| |
|
| |
| <span id="执行模型与调试"></span>
| |
| == 执行模型与调试 ==
| |
|
| |
| <span id="执行四步"></span>
| |
| === 执行四步 ===
| |
|
| |
| 逻辑运行可抽象为四步<sup>[[#fn-2|2]]</sup>:
| |
|
| |
| # 读取 <code>@counter</code> 指向语句
| |
| # <code>@counter += 1</code>
| |
| # 执行被读取语句
| |
| # 回到 1
| |
|
| |
| 这条规则解释了:
| |
|
| |
| * <code>jump</code> 的本质是改写下一条语句位置
| |
| * <code>wait/stop</code> 的“卡住”是通过 <code>counter-- + yield</code> 实现
| |
| * 所有函数/跳表都能用 <code>@counter</code> 手工实现
| |
|
| |
| <span id="变量表调试法"></span>
| |
| === 变量表调试法 ===
| |
|
| |
| 建议你固定三层调试变量:
| |
|
| |
| * 控制层: <code>state phase step</code>
| |
| * 数据层: <code>in out tmp err</code>
| |
| * 时序层: <code>tick heartbeat watchdog</code>
| |
|
| |
| 典型调试输出模板:
| |
|
| |
| <pre>
| |
| print "s="; print state
| |
| print " p="; print phase
| |
| print " t="; print tick
| |
| printflush message1
| |
| </pre>
| |
|
| |
| <div class="mdtMarkdownAlert mdtMarkdownAlert-note">
| |
| 变量表刷新频率低于逻辑执行频率, 快速跳转下会误读 @counter.
| |
| </div>
| |
|
| |
| <span id="最小监控框架"></span>
| |
| === 最小监控框架 ===
| |
|
| |
| '''心跳''' 是什么: 持续变化的计数值。作用: 判断逻辑是否仍在运行。<br />
| |
| '''卡死''' 是什么: 逻辑未崩溃但长期不推进。作用: 作为触发恢复的判据。<br />
| |
| '''看门狗''' 是什么: 监控“是否长期无进展”的计数器。作用: 超时后触发重置或降级。
| |
|
| |
| <pre>
| |
| # 监控心跳和卡死
| |
| op add heartbeat heartbeat 1
| |
| op mod heartbeat heartbeat 1000000
| |
|
| |
| op add watchdog watchdog 1
| |
| jump wd_ok lessThan watchdog 600
| |
| print "watchdog trip"
| |
| printflush message1
| |
| set watchdog 0
| |
| wd_ok:
| |
| end
| |
| </pre>
| |
|
| |
| ----
| |
|
| |
|
| |
| ----
| |
|
| |
| <span id="进阶控制流-基础"></span>
| |
| == 进阶控制流-基础 ==
| |
|
| |
| 这一章只做“衔接”, 不再重复基础控制流定义。
| |
|
| |
| 以下基础结构已移动到基础教程《逻辑教学.wiki》中的“控制流基础补充”章节:
| |
|
| |
| * skip
| |
| * if-else
| |
| * do-while
| |
| * while
| |
| * gwhile
| |
|
| |
| 进阶篇只保留工程侧规则:
| |
|
| |
| * 多层循环必须用唯一标签前缀, 防止跳错行
| |
| * break/continue 跳转必须显式写“目标层级”
| |
| * 所有循环都要能从外部条件中断
| |
|
| |
| 多层循环命名模板:
| |
|
| |
| <pre>
| |
| # outer loop
| |
| O_LOOP:
| |
| # inner loop
| |
| I_LOOP:
| |
| jump I_CONT lessThan x 0
| |
| jump I_BREAK equal innerStop true
| |
| # inner body...
| |
| I_CONT:
| |
| # inner tail...
| |
| jump I_LOOP lessThan i 10
| |
| I_BREAK:
| |
| jump O_BREAK equal outerStop true
| |
| # outer tail...
| |
| jump O_LOOP lessThan o 5
| |
| O_BREAK:
| |
| </pre>
| |
|
| |
| ----
| |
|
| |
|
| |
| ----
| |
|
| |
| <span id="进阶控制流-选择"></span>
| |
| == 进阶控制流-选择 ==
| |
|
| |
| <span id="跳表基础"></span>
| |
| === 跳表基础 ===
| |
|
| |
| '''跳表''' 是什么: 用 @counter 偏移把输入映射到分支入口。作用: 用常数时间做多分支分派。
| |
|
| |
| <pre>
| |
| # sel in [0,2]
| |
| op add @counter @counter sel
| |
| jump C0 always 0 0
| |
| jump C1 always 0 0
| |
| jump C2 always 0 0
| |
| C0:
| |
| print "0"
| |
| jump END always 0 0
| |
| C1:
| |
| print "1"
| |
| jump END always 0 0
| |
| C2:
| |
| print "2"
| |
| END:
| |
| printflush message1
| |
| </pre>
| |
|
| |
| <span id="跳表防越界"></span>
| |
| === 跳表防越界 ===
| |
|
| |
| <pre>
| |
| # clamp sel to [0,2]
| |
| op max sel sel 0
| |
| op min sel sel 2
| |
| op add @counter @counter sel
| |
| jump C0 always 0 0
| |
| jump C1 always 0 0
| |
| jump C2 always 0 0
| |
| </pre>
| |
|
| |
| <span id="等长块分派"></span>
| |
| === 等长块分派 ===
| |
|
| |
| 每块长度固定时, 可减少子表行数:
| |
|
| |
| <pre>
| |
| # len=4
| |
| op mul off idx 4
| |
| op add @counter @counter off
| |
| print "A"
| |
| jump END always 0 0
| |
| noop
| |
| noop
| |
|
| |
| print "B"
| |
| jump END always 0 0
| |
| noop
| |
| noop
| |
| END:
| |
| printflush message1
| |
| </pre>
| |
|
| |
| <span id="匹配守卫"></span>
| |
| === 匹配守卫 ===
| |
|
| |
| '''匹配守卫''' 是什么: case 之前的额外条件跳转。作用: 在不增加主分派复杂度的前提下细化命中条件。
| |
|
| |
| <pre>
| |
| # case 0 if a<b
| |
| op mul k n 2
| |
| op add @counter @counter k
| |
| jump C0_G lessThan a b
| |
| jump C0 always 0 0
| |
| jump C1 always 0 0
| |
| C0_G:
| |
| print "0 guard"
| |
| jump END always 0 0
| |
| C0:
| |
| print "0"
| |
| jump END always 0 0
| |
| C1:
| |
| print "1"
| |
| END:
| |
| printflush message1
| |
| </pre>
| |
|
| |
| ----
| |
|
| |
|
| |
| ----
| |
|
| |
| <span id="复杂条件"></span>
| |
| == 复杂条件 ==
| |
|
| |
| <span id="逻辑代数定义"></span>
| |
| === 逻辑代数定义 ===
| |
|
| |
| {| class="wikitable"
| |
| |-
| |
| ! 形式
| |
| ! 名称
| |
| ! 说明
| |
| |-
| |
| | !A
| |
| | 非
| |
| | 反转条件
| |
| |-
| |
| | A && B
| |
| | 短路与
| |
| | A假时不看B
| |
| |-
| |
| | A || B
| |
| | 短路或
| |
| | A真时不看B
| |
| |}
| |
|
| |
| <span id="基本反转表"></span>
| |
| === 基本反转表 ===
| |
|
| |
| {| class="wikitable"
| |
| |-
| |
| ! 原
| |
| ! 反
| |
| |-
| |
| | lessThan
| |
| | greaterThanEq
| |
| |-
| |
| | lessThanEq
| |
| | greaterThan
| |
| |-
| |
| | greaterThan
| |
| | lessThanEq
| |
| |-
| |
| | greaterThanEq
| |
| | lessThan
| |
| |-
| |
| | equal
| |
| | notEqual
| |
| |-
| |
| | notEqual
| |
| | equal
| |
| |}
| |
|
| |
| <span id="德摩根定律"></span>
| |
| === 德摩根定律 ===
| |
|
| |
| * <code>!(A && B) = (!A) || (!B)</code>
| |
| * <code>!(A || B) = (!A) && (!B)</code>
| |
|
| |
| <span id="构建算法"></span>
| |
| === 构建算法 ===
| |
|
| |
| <pre>
| |
| def build(cond, target):
| |
| if cond.type == AND:
| |
| tmp = newTag()
| |
| build(not cond.left, tmp)
| |
| build(cond.right, target)
| |
| add(tmp)
| |
| elif cond.type == OR:
| |
| build(cond.left, target)
| |
| build(cond.right, target)
| |
| else:
| |
| add(jump target cond)
| |
| </pre>
| |
|
| |
| <span id="实战示例-复杂条件"></span>
| |
| === 实战示例-复杂条件 ===
| |
|
| |
| 目标: <code>(a<b && c<d) || e<f</code>
| |
|
| |
| <pre>
| |
| jump T1 greaterThanEq a b
| |
| jump TARGET lessThan c d
| |
| T1:
| |
| jump TARGET lessThan e f
| |
| print "false"
| |
| TARGET:
| |
| print "true"
| |
| printflush message1
| |
| </pre>
| |
|
| |
| ----
| |
|
| |
|
| |
| ----
| |
|
| |
| <span id="函数系统-非递归"></span>
| |
| == 函数系统-非递归 ==
| |
|
| |
| <span id="函数组成"></span>
| |
| === 函数组成 ===
| |
|
| |
| # 入口跳过
| |
| # 函数体
| |
| # 返回语句 <code>set @counter ret</code>
| |
|
| |
| <pre>
| |
| jump DEF_END always 0 0
| |
| fn_print:
| |
| print msg
| |
| set @counter ret
| |
| DEF_END:
| |
|
| |
| set msg "Hello"
| |
| op add ret @counter 1
| |
| jump fn_print always 0 0
| |
|
| |
| set msg "World"
| |
| op add ret @counter 1
| |
| jump fn_print always 0 0
| |
|
| |
| printflush message1
| |
| </pre>
| |
|
| |
| <span id="函数参数约定"></span>
| |
| === 函数参数约定 ===
| |
|
| |
| 推荐约定:
| |
|
| |
| * 入参: <code>arg1 arg2 ...</code>
| |
| * 出参: <code>retv</code>
| |
| * 返回地址: <code>ret</code>
| |
|
| |
| <span id="函数复用案例"></span>
| |
| === 函数复用案例 ===
| |
|
| |
| 平方函数:
| |
|
| |
| <pre>
| |
| jump D_END always 0 0
| |
| fn_sqr:
| |
| op mul retv arg1 arg1
| |
| set @counter ret
| |
| D_END:
| |
|
| |
| set arg1 12
| |
| op add ret @counter 1
| |
| jump fn_sqr always 0 0
| |
| print retv
| |
| printflush message1
| |
| </pre>
| |
|
| |
| ----
| |
|
| |
|
| |
| ----
| |
|
| |
| <span id="函数系统-递归与栈"></span>
| |
| == 函数系统-递归与栈 ==
| |
|
| |
| 递归函数必须解决两个问题:
| |
|
| |
| # 返回地址会多层嵌套
| |
| # 中间变量会被后续递归覆盖
| |
|
| |
| 所以要用内存做调用栈<sup>[[#fn-3|3]]</sup>.
| |
|
| |
| <span id="栈模型"></span>
| |
| === 栈模型 ===
| |
|
| |
| 建议每帧栈帧结构:
| |
|
| |
| {| class="wikitable"
| |
| |-
| |
| ! 偏移
| |
| ! 含义
| |
| |-
| |
| | +0
| |
| | 返回地址
| |
| |-
| |
| | +1
| |
| | 参数n
| |
| |-
| |
| | +2
| |
| | 临时值tmp
| |
| |}
| |
|
| |
| <span id="递归框架"></span>
| |
| === 递归框架 ===
| |
|
| |
| <pre>
| |
| # 仅示意骨架
| |
| set sp -1
| |
| jump DEF_END always 0 0
| |
| fib:
| |
| # push ret
| |
| # push n
| |
| # recurse
| |
| # pop
| |
| set @counter ret
| |
| DEF_END:
| |
| </pre>
| |
|
| |
| <span id="尾递归优化"></span>
| |
| === 尾递归优化 ===
| |
|
| |
| 尾递归可改循环, 大幅降复杂度和 bug 风险.
| |
|
| |
| <pre>
| |
| # tail recursion -> loop
| |
| LOOP:
| |
| # body
| |
| jump LOOP lessThan i n
| |
| </pre>
| |
|
| |
| ----
| |
|
| |
|
| |
| ----
| |
|
| |
| <span id="多处理器协作协议"></span>
| |
| == 多处理器协作协议 ==
| |
|
| |
| 超大逻辑应拆分为多个处理器协作.
| |
|
| |
| <span id="协议字段"></span>
| |
| === 协议字段 ===
| |
|
| |
| '''协议''' 是什么: 多处理器共享内存字段和时序规则的约定。作用: 避免协作时读写歧义与乱序。<br />
| |
| '''消费者心跳''' 是什么: 由消费者更新的心跳字段。作用: 让生产者判断消费者是否卡住。<br />
| |
| '''ACK''' 是什么: 命令处理完成回执值。作用: 让发送方安全进入下一步。
| |
|
| |
| {| class="wikitable"
| |
| |-
| |
| ! 地址
| |
| ! 字段
| |
| |-
| |
| | 0
| |
| | 协议版本
| |
| |-
| |
| | 1
| |
| | 生产者心跳
| |
| |-
| |
| | 2
| |
| | 消费者心跳
| |
| |-
| |
| | 3
| |
| | 命令码
| |
| |-
| |
| | 4
| |
| | 参数A
| |
| |-
| |
| | 5
| |
| | 参数B
| |
| |-
| |
| | 6
| |
| | ACK
| |
| |-
| |
| | 7
| |
| | 错误码
| |
| |}
| |
|
| |
| <span id="握手流程"></span>
| |
| === 握手流程 ===
| |
|
| |
| # Producer 写 cmd + args
| |
| # Consumer 读取并执行
| |
| # Consumer 写 ack=cmd
| |
| # Producer 校验 ack
| |
|
| |
| <span id="协作模板"></span>
| |
| === 协作模板 ===
| |
|
| |
| 生产者:
| |
|
| |
| <pre>
| |
| write 1 bank1 0
| |
| op add hb hb 1
| |
| write hb bank1 1
| |
| write 200 bank1 3
| |
| write x bank1 4
| |
| write y bank1 5
| |
| read ack bank1 6
| |
| jump 0 notEqual ack 200
| |
| </pre>
| |
|
| |
| 消费者:
| |
|
| |
| <pre>
| |
| read ver bank1 0
| |
| jump 0 notEqual ver 1
| |
| read cmd bank1 3
| |
| jump 0 notEqual cmd 200
| |
| read x bank1 4
| |
| read y bank1 5
| |
| # do work...
| |
| write 200 bank1 6
| |
| </pre>
| |
|
| |
| ----
| |
|
| |
|
| |
| ----
| |
|
| |
| <span id="单位控制进阶"></span>
| |
| == 单位控制进阶 ==
| |
|
| |
| <span id="抢控保护"></span>
| |
| === 抢控保护 ===
| |
|
| |
| '''抢控''' 是什么: 当前单位被其他逻辑或玩家接管。作用: 提醒当前控制逻辑立即重绑或回退。
| |
|
| |
| <pre>
| |
| find:
| |
| ubind @flare
| |
| sensor c @unit @controlled
| |
| jump find notEqual c 0
| |
|
| |
| ctrl:
| |
| ucontrol move tx ty 0 0 0
| |
| sensor dead @unit @dead
| |
| jump find notEqual dead false
| |
| sensor owner @unit @controller
| |
| jump ctrl equal owner @this
| |
| jump find always 0 0
| |
| </pre>
| |
|
| |
| <span id="控制最小化"></span>
| |
| === 控制最小化 ===
| |
|
| |
| 不用控制语句时不要发控制信号<sup>[[#fn-4|4]]</sup>:
| |
|
| |
| <pre>
| |
| # 用 op len 判定距离, 替代 ucontrol within
| |
| sensor ux @unit @x
| |
| sensor uy @unit @y
| |
| op sub dx ux tx
| |
| op sub dy uy ty
| |
| op len dist dx dy
| |
| op lessThan near dist 10
| |
| </pre>
| |
|
| |
| <span id="可靠解绑"></span>
| |
| === 可靠解绑 ===
| |
|
| |
| <pre>
| |
| # 确认当前确实在控制时再 unbind
| |
| sensor owner @unit @controller
| |
| jump skip notEqual owner @this
| |
| ucontrol unbind 0 0 0 0 0
| |
| skip:
| |
| </pre>
| |
|
| |
| ----
| |
|
| |
|
| |
| ----
| |
|
| |
| <span id="单位批处理与调度"></span>
| |
| == 单位批处理与调度 ==
| |
|
| |
| 目标: 降低单帧峰值, 提升稳定性.
| |
|
| |
| <span id="时间片调度"></span>
| |
| === 时间片调度 ===
| |
|
| |
| <pre>
| |
| # task 0..2
| |
| op add @counter @counter task
| |
| jump T0 always 0 0
| |
| jump T1 always 0 0
| |
| jump T2 always 0 0
| |
| T0:
| |
| # bind / select
| |
| jump NEXT always 0 0
| |
| T1:
| |
| # sense
| |
| jump NEXT always 0 0
| |
| T2:
| |
| # control
| |
| jump NEXT always 0 0
| |
| NEXT:
| |
| op add task task 1
| |
| op mod task task 3
| |
| end
| |
| </pre>
| |
|
| |
| <span id="轮询类型"></span>
| |
| === 轮询类型 ===
| |
|
| |
| <pre>
| |
| lookup unit utype slot
| |
| ubind utype
| |
| # ... process one ...
| |
| op add slot slot 1
| |
| op mod slot slot @unitCount
| |
| </pre>
| |
|
| |
| <span id="负载退避"></span>
| |
| === 负载退避 ===
| |
|
| |
| <pre>
| |
| # backlog高时减少控制频率
| |
| jump light lessThan backlog 20
| |
| wait 0.05
| |
| jump done always 0 0
| |
| light:
| |
| wait 0.01
| |
| done:
| |
| </pre>
| |
|
| |
| ----
| |
|
| |
|
| |
| ----
| |
|
| |
| <span id="世界处理器-安全框架"></span>
| |
| == 世界处理器-安全框架 ==
| |
|
| |
| <span id="双开关安全门"></span>
| |
| === 双开关安全门 ===
| |
|
| |
| 建议两个按钮:
| |
|
| |
| * <code>switch1</code>: 总开关
| |
| * <code>switch2</code>: 危险操作开关
| |
|
| |
| <pre>
| |
| sensor en1 switch1 @enabled
| |
| sensor en2 switch2 @enabled
| |
| jump END equal en1 false
| |
| jump END equal en2 false
| |
| # privileged dangerous ops...
| |
| END:
| |
| end
| |
| </pre>
| |
|
| |
| <span id="回滚点"></span>
| |
| === 回滚点 ===
| |
|
| |
| 任何会改地图状态的逻辑建议保留回滚参数:
| |
|
| |
| <pre>
| |
| # 写入前先存旧值
| |
| getblock block oldB x y
| |
| write oldB bank1 20
| |
| # ... setblock ...
| |
| </pre>
| |
|
| |
| <span id="速率保险丝"></span>
| |
| === 速率保险丝 ===
| |
|
| |
| '''速率保险丝''' 是什么: 先短时提速再自动回落的控制策略(本教程命名)。作用: 避免 setrate 长期高负载导致全局卡顿。
| |
|
| |
| <pre>
| |
| # 防止 setrate 长时间高负载
| |
| setrate 20
| |
| wait 0.2
| |
| setrate 1
| |
| </pre>
| |
|
| |
| ----
| |
|
| |
|
| |
| ----
| |
|
| |
| <span id="世界处理器-高级语句"></span>
| |
| == 世界处理器-高级语句 ==
| |
|
| |
| <span id="fetch"></span>
| |
| === fetch ===
| |
|
| |
| <pre>
| |
| fetch unit u @sharded i 0
| |
| fetch build b @sharded i @conveyor
| |
| fetch unitCount uc @sharded 0 0
| |
| </pre>
| |
|
| |
| <span id="message"></span>
| |
| === message ===
| |
|
| |
| <pre>
| |
| print "系统广播"
| |
| message announce 1 @wait
| |
| </pre>
| |
|
| |
| <span id="setprop"></span>
| |
| === setprop ===
| |
|
| |
| <pre>
| |
| # 高风险示例
| |
| setprop @health @this 0
| |
| </pre>
| |
|
| |
| <span id="setrule"></span>
| |
| === setrule ===
| |
|
| |
| <pre>
| |
| setrule lighting 1 0 0 0 0
| |
| </pre>
| |
|
| |
| <span id="status"></span>
| |
| === status ===
| |
|
| |
| <pre>
| |
| status false wet unit 10
| |
| status true boss unit 0
| |
| </pre>
| |
|
| |
| <div class="mdtMarkdownAlert mdtMarkdownAlert-warning">
| |
| 世界处理器语句破坏性极强, 建议默认禁用, 仅在维护窗口开启.
| |
| </div>
| |
|
| |
| ----
| |
|
| |
|
| |
| ----
| |
|
| |
| <span id="性能优化与资源预算"></span>
| |
| == 性能优化与资源预算 ==
| |
|
| |
| <span id="资源预算模型"></span>
| |
| === 资源预算模型 ===
| |
|
| |
| 建议给每帧设置预算变量:
| |
|
| |
| * <code>budgetOps</code>
| |
| * <code>budgetIO</code>
| |
| * <code>budgetDraw</code>
| |
|
| |
| <span id="高频热点"></span>
| |
| === 高频热点 ===
| |
|
| |
| * 高频 <code>printflush/drawflush</code>
| |
| * 全量遍历单位/链接
| |
| * 重复 sensor 同一属性
| |
| * 大量字符串拼接
| |
|
| |
| <span id="优化手段"></span>
| |
| === 优化手段 ===
| |
|
| |
| {| class="wikitable"
| |
| |-
| |
| ! 问题
| |
| ! 手段
| |
| |-
| |
| | 全量扫描卡顿
| |
| | 分帧批处理
| |
| |-
| |
| | 输出过于频繁
| |
| | 合并输出/降低 flush 频率
| |
| |-
| |
| | 逻辑难维护
| |
| | 状态机 + 协议层
| |
| |-
| |
| | 控制抖动
| |
| | 降频 + 持续控制窗口
| |
| |}
| |
|
| |
| <span id="实战-分帧遍历链接"></span>
| |
| === 实战: 分帧遍历链接 ===
| |
|
| |
| <pre>
| |
| # 每帧只处理一个链接
| |
| getlink b idx
| |
| # ... do something ...
| |
| op add idx idx 1
| |
| op mod idx idx @links
| |
| end
| |
| </pre>
| |
|
| |
| ----
| |
|
| |
|
| |
| ----
| |
|
| |
| <span id="可维护性规范"></span>
| |
| == 可维护性规范 ==
| |
|
| |
| <span id="命名规范"></span>
| |
| === 命名规范 ===
| |
|
| |
| 推荐前缀:
| |
|
| |
| * <code>s_</code> 状态变量
| |
| * <code>t_</code> 临时变量
| |
| * <code>io_</code> 协议变量
| |
| * <code>cfg_</code> 配置变量
| |
|
| |
| <span id="模块边界"></span>
| |
| === 模块边界 ===
| |
|
| |
| 建议一个处理器只负责一个职责:
| |
|
| |
| * 采集
| |
| * 决策
| |
| * 执行
| |
| * 可视化
| |
|
| |
| <span id="注释规范"></span>
| |
| === 注释规范 ===
| |
|
| |
| 注释写“为什么”, 不写“做了什么”.
| |
|
| |
| <pre>
| |
| # bad: op add i i 1 # i加1
| |
| # good: # 轮询链接索引, 防止固定打同一建筑
| |
| op add i i 1
| |
| </pre>
| |
|
| |
| <span id="发布规范"></span>
| |
| === 发布规范 ===
| |
|
| |
| 建议维护:
| |
|
| |
| * 版本号
| |
| * 协议版本
| |
| * 变更记录
| |
|
| |
| ----
| |
|
| |
|
| |
| ----
| |
|
| |
| <span id="编译器与工程化"></span>
| |
| == 编译器与工程化 ==
| |
|
| |
| <span id="什么时候上编译器"></span>
| |
| === 什么时候上编译器 ===
| |
|
| |
| 满足任一条件就建议上:
| |
|
| |
| * 代码 > 300 行
| |
| * 需要函数与复用
| |
| * 需要自动构建复杂条件
| |
| * 需要多人协作
| |
|
| |
| <span id="编译器对比"></span>
| |
| === 编译器对比 ===
| |
|
| |
| {| class="wikitable"
| |
| |-
| |
| ! 名称
| |
| ! 特点
| |
| ! 适配人群
| |
| |-
| |
| | mindcode
| |
| | 优化强、成熟
| |
| | 重性能
| |
| |-
| |
| | mlogjs
| |
| | JS/TS生态好
| |
| | 前端/脚本开发者
| |
| |-
| |
| | bang-lang
| |
| | 贴近 mlog、元编程强
| |
| | 深度控制流玩家
| |
| |}
| |
|
| |
| <span id="工程化流水线"></span>
| |
| === 工程化流水线 ===
| |
|
| |
| 推荐流程:
| |
|
| |
| # 源码仓库
| |
| # 编译脚本
| |
| # 自动导出 mlog
| |
| # 回归测试图
| |
| # 版本发布
| |
|
| |
| <span id="bang最小用法"></span>
| |
| === bang 最小用法 ===
| |
|
| |
| <pre>
| |
| mindustry_logic_bang_lang cl <<< 'print "Hello, World!";'
| |
| </pre>
| |
|
| |
| ----
| |
|
| |
|
| |
| ----
| |
|
| |
| <span id="155与146差异对照"></span>
| |
| == 155与146差异对照 ==
| |
|
| |
| 本章整理“旧教程常见说法”与 155 行为的关键差异.
| |
|
| |
| {| class="wikitable"
| |
| |-
| |
| ! 项目
| |
| ! 146常见说法
| |
| ! 155/当前基线
| |
| |-
| |
| | print缓冲上限
| |
| | 常被写成约220
| |
| | 源码上限为400<sup>[[#fn-5|5]]</sup>
| |
| |-
| |
| | 二/十六进制负号
| |
| | 多写作 0b-101, 0x-80
| |
| | 也支持 +0b/-0b/+0x/-0x
| |
| |-
| |
| | read/write对象范围
| |
| | 常仅讲内存
| |
| | 可扩展到字符串/信息板/画板/逻辑变量等
| |
| |-
| |
| | select语句
| |
| | 旧版本无
| |
| | 新版本可直接用
| |
| |-
| |
| | ucontrol细节
| |
| | 文档较少
| |
| | 选项与行为更丰富
| |
| |-
| |
| | control范围
| |
| | 严格依赖链接
| |
| | 某些版本行为有变化, 以当版实测为准
| |
| |}
| |
|
| |
| <div class="mdtMarkdownAlert mdtMarkdownAlert-important">
| |
| 若遇到“教程说法”和游戏行为冲突, 以当前版本实测 + 源码为准.
| |
| </div>
| |
|
| |
| ----
| |
|
| |
|
| |
| ----
| |
|
| |
| <span id="附录01-op方法进阶"></span>
| |
| == 附录01-op方法进阶 ==
| |
|
| |
| {| class="wikitable"
| |
| |-
| |
| ! 类别
| |
| ! 操作
| |
| |-
| |
| | 算术
| |
| | add sub mul div idiv mod emod pow
| |
| |-
| |
| | 比较
| |
| | equal notEqual lessThan lessThanEq greaterThan greaterThanEq strictEqual
| |
| |-
| |
| | 位运算
| |
| | shl shr ushr and or xor not
| |
| |-
| |
| | 数学
| |
| | abs sign floor ceil round sqrt log log10 logn max min rand
| |
| |-
| |
| | 几何/三角
| |
| | len angle angleDiff sin cos tan asin acos atan noise
| |
| |}
| |
|
| |
| 要点:
| |
|
| |
| * <code>mod</code> 与 <code>emod</code> 在负数时行为不同
| |
| * 位运算前会转整数
| |
| * 三角函数是角度制
| |
|
| |
| ----
| |
|
| |
| <span id="附录02-传感器速查"></span>
| |
| == 附录02-传感器速查 ==
| |
|
| |
| {| class="wikitable"
| |
| |-
| |
| ! 分类
| |
| ! 属性
| |
| |-
| |
| | 坐标
| |
| | x y shootX shootY mineX mineY
| |
| |-
| |
| | 生存
| |
| | health maxHealth dead shield armor
| |
| |-
| |
| | 资源
| |
| | totalItems totalLiquids totalPower itemCapacity liquidCapacity powerCapacity
| |
| |-
| |
| | 行为
| |
| | enabled shooting boosting mining speed range
| |
| |-
| |
| | 标识
| |
| | team type id name controlled controller flag
| |
| |-
| |
| | 载荷
| |
| | payloadType payloadCount totalPayload payloadCapacity
| |
| |-
| |
| | 文本/显示
| |
| | size bufferSize displayWidth displayHeight
| |
| |}
| |
|
| |
| ----
| |
|
| |
| <span id="附录03-环境变量速查"></span>
| |
| == 附录03-环境变量速查 ==
| |
|
| |
| <span id="逻辑信息"></span>
| |
| === 逻辑信息 ===
| |
|
| |
| * <code>@this</code> / <code>@thisx</code> / <code>@thisy</code>
| |
| * <code>@links</code>
| |
| * <code>@unit</code>
| |
| * <code>@ipt</code>
| |
| * <code>@counter</code>
| |
|
| |
| <span id="常量与数学"></span>
| |
| === 常量与数学 ===
| |
|
| |
| * <code>true</code> <code>false</code> <code>null</code>
| |
| * <code>@pi</code> <code>@e</code>
| |
| * <code>@degToRad</code> <code>@radToDeg</code>
| |
|
| |
| <span id="世界变量"></span>
| |
| === 世界变量 ===
| |
|
| |
| * <code>@time</code> <code>@tick</code> <code>@second</code> <code>@minute</code>
| |
| * <code>@waveNumber</code> <code>@waveTime</code>
| |
| * <code>@mapw</code> <code>@maph</code>
| |
|
| |
| <span id="lookup计数"></span>
| |
| === lookup计数 ===
| |
|
| |
| * <code>@itemCount</code>
| |
| * <code>@unitCount</code>
| |
| * <code>@blockCount</code>
| |
| * <code>@liquidCount</code>
| |
|
| |
| ----
| |
|
| |
| <span id="附录04-术语表"></span>
| |
| == 附录04-术语表 ==
| |
|
| |
| {| class="wikitable"
| |
| |-
| |
| ! 术语
| |
| ! 解释
| |
| |-
| |
| | 跳表
| |
| | 是什么: 用 @counter 偏移把输入值映射到不同代码块。作用: 用常数时间完成多分支分派。
| |
| |-
| |
| | 匹配守卫
| |
| | 是什么: 在进入某个分支前额外检查一次条件的跳转。作用: 让同一个 case 支持更细粒度筛选。
| |
| |-
| |
| | 穿透
| |
| | 是什么: 分支执行后没有跳出, 继续执行后续分支。作用: 可用于刻意复用后续逻辑, 也可能引发误执行。
| |
| |-
| |
| | 阻塞
| |
| | 是什么: 在一行或几行上反复循环等待条件。作用: 保证条件满足后再继续, 但会牺牲推进速度。
| |
| |-
| |
| | 协议
| |
| | 是什么: 多处理器共享内存字段和时序规则的约定。作用: 避免协作时读写歧义和乱序。
| |
| |-
| |
| | 抢控
| |
| | 是什么: 单位控制权被其他逻辑或玩家接管。作用: 提醒当前控制逻辑需要重绑或回退。
| |
| |-
| |
| | 心跳
| |
| | 是什么: 持续递增并回写的计数值。作用: 用来判断某个处理器是否仍在运行。
| |
| |-
| |
| | 消费者心跳
| |
| | 是什么: 由消费者处理器维护的心跳值。作用: 让生产者检测消费者是否卡住或停机。
| |
| |-
| |
| | ACK
| |
| | 是什么: Acknowledgement, 命令已处理完成的回执值。作用: 让发送方确认可进入下一步。
| |
| |-
| |
| | 卡死
| |
| | 是什么: 逻辑没有崩溃, 但长期停在同一等待或循环。作用: 作为故障信号触发恢复流程。
| |
| |-
| |
| | 速率保险丝
| |
| | 是什么: 短时提速后自动回落的保护策略(本教程命名)。作用: 防止 setrate 长期高负载导致全局卡顿。
| |
| |-
| |
| | 看门狗
| |
| | 是什么: 监控流程是否长期无进展的保护计数器。作用: 超时后触发重置或降级恢复。
| |
| |}
| |
|
| |
| <span id="术语-人话例子"></span>
| |
| === 高频术语(一句人话 + 最小例子) ===
| |
|
| |
| <span id="术语-心跳"></span>
| |
| '''心跳''': 一句话人话: 一个持续变化的数字, 用来证明“这个逻辑还活着”.
| |
|
| |
| 最小例子:
| |
| <pre>
| |
| op add hb hb 1
| |
| op mod hb hb 1000000
| |
| write hb bank1 1
| |
| </pre>
| |
|
| |
| <span id="术语-消费者心跳"></span>
| |
| '''消费者心跳''': 一句话人话: 消费者处理器每轮报平安, 让生产者知道它没停机.
| |
|
| |
| 最小例子:
| |
| <pre>
| |
| # consumer side
| |
| op add hb_c hb_c 1
| |
| op mod hb_c hb_c 1000000
| |
| write hb_c bank1 2
| |
| </pre>
| |
|
| |
| <span id="术语-ack"></span>
| |
| '''ACK''': 一句话人话: “我这条命令做完了”的回执信号.
| |
|
| |
| 最小例子:
| |
| <pre>
| |
| # producer
| |
| write 200 bank1 3
| |
| read ack bank1 6
| |
| jump 0 notEqual ack 200
| |
|
| |
| # consumer
| |
| read cmd bank1 3
| |
| # ...do work...
| |
| write cmd bank1 6
| |
| </pre>
| |
|
| |
| <span id="术语-卡死"></span>
| |
| '''卡死''': 一句话人话: 逻辑没崩, 但一直卡在某个等待/循环里, 业务不前进.
| |
|
| |
| 最小例子:
| |
| <pre>
| |
| wait_btn:
| |
| sensor on switch1 @enabled
| |
| jump wait_btn equal on false
| |
| # 按钮不变真就会一直卡在这里
| |
| </pre>
| |
|
| |
| <span id="术语-速率保险丝"></span>
| |
| '''速率保险丝(本教程命名)''': 一句话人话: 短时提速, 自动回落, 防止 setrate 长期高负载.
| |
|
| |
| 最小例子:
| |
| <pre>
| |
| setrate 20
| |
| # heavy work ...
| |
| wait 0.2
| |
| setrate 1
| |
| </pre>
| |
|
| |
| <span id="术语-看门狗"></span>
| |
| '''看门狗''': 一句话人话: 发现流程长期没进展就触发恢复动作.
| |
|
| |
| 最小例子:
| |
| <pre>
| |
| jump progressed notEqual step lastStep
| |
| op add stuck stuck 1
| |
| jump chk always 0 0
| |
| progressed:
| |
| set stuck 0
| |
| set lastStep step
| |
| chk:
| |
| jump ok lessThan stuck 600
| |
| # recovery
| |
| set state 0
| |
| ok:
| |
| </pre>
| |
|
| |
| ----
| |
|
| |
| <span id="附录05-排错清单"></span>
| |
| == 附录05-排错清单 ==
| |
|
| |
| 请按顺序检查:
| |
|
| |
| # 变量是否初始化
| |
| # 链接名是否存在且正确
| |
| # 是否同队伍且有权限
| |
| # @counter 是否跳飞
| |
| # 是否被 wait/stop 阻塞
| |
| # 单位是否被抢控
| |
| # 协议版本是否一致
| |
| # ACK 是否回写
| |
| # flush 频率是否过高
| |
| # 是否触发了安全门
| |
|
| |
| 最小排错模板:
| |
|
| |
| <pre>
| |
| print "state="; print state
| |
| print " err="; print err
| |
| print " ack="; print ack
| |
| printflush message1
| |
| </pre>
| |
|
| |
| ----
| |
|
| |
| <span id="注释"></span>
| |
| == 注释 ==
| |
|
| |
| * <span id="fn-2"></span> [2] @counter 四步模型是理解所有高级控制流的基础.
| |
| * <span id="fn-3"></span> [3] 递归调用必须隔离返回地址和跨调用变量.
| |
| * <span id="fn-4"></span> [4] 单位控制语句会发控制信号, 非必要不要滥用.
| |
| * <span id="fn-5"></span> [5] 当前基线中 textBuffer 上限为 400.
| |
| * <span id="fn-6"></span> [6] 跳表前务必约束输入范围.
| |
| * <span id="fn-7"></span> [7] 复杂条件转换时优先做逻辑代数化简.
| |
| * <span id="fn-8"></span> [8] guard 优先处理“高概率失败”分支可减少执行成本.
| |
| * <span id="fn-9"></span> [9] while 和 gwhile 选型取决于条件反转成本.
| |
| * <span id="fn-10"></span> [10] 函数建议统一入参/出参/返回地址变量命名.
| |
| * <span id="fn-11"></span> [11] 非递归函数的返回地址常用 @counter+1.
| |
| * <span id="fn-12"></span> [12] 递归函数要保证栈平衡, 否则会读错返回地址.
| |
| * <span id="fn-13"></span> [13] 多处理器协作应先定协议再写代码.
| |
| * <span id="fn-14"></span> [14] 心跳变量建议做取模防止无限增长.
| |
| * <span id="fn-15"></span> [15] ACK 建议回写命令码本身, 便于无状态校验.
| |
| * <span id="fn-16"></span> [16] 单位控制需持续刷新, 否则控制会过期.
| |
| * <span id="fn-17"></span> [17] owner 校验可快速检测抢控.
| |
| * <span id="fn-18"></span> [18] 批处理策略是性能优化的第一手段.
| |
| * <span id="fn-19"></span> [19] 世界处理器高风险操作必须有硬开关.
| |
| * <span id="fn-20"></span> [20] 任何 setblock 类操作建议保留回滚信息.
| |
| * <span id="fn-21"></span> [21] setrate 只应短时升高, 长时高频会压垮整体.
| |
| * <span id="fn-22"></span> [22] flush 过频是常见卡顿源.
| |
| * <span id="fn-23"></span> [23] 输出日志尽量结构化, 便于排错脚本解析.
| |
| * <span id="fn-24"></span> [24] 命名规范是多人协作里性价比最高的质量手段.
| |
| * <span id="fn-25"></span> [25] 注释写“原因”优先于“动作”.
| |
| * <span id="fn-26"></span> [26] 编译器能显著降低复杂控制流的人肉错误率.
| |
| * <span id="fn-27"></span> [27] 版本迁移先做差异表再做迁移计划.
| |
| * <span id="fn-28"></span> [28] mod/emod 的负数行为不同, 算法里要明确选型.
| |
| * <span id="fn-29"></span> [29] 位运算要注意数值转换与范围精度.
| |
| * <span id="fn-30"></span> [30] strictEqual 与 equal 的语义差别在类型一致性.
| |
| * <span id="fn-31"></span> [31] 逻辑代数化简可减少 jump 数量和维护成本.
| |
| * <span id="fn-32"></span> [32] 先保证正确性再做局部性能优化.
| |
| * <span id="fn-33"></span> [33] 协议字段建议保留错误码便于远程诊断.
| |
| * <span id="fn-34"></span> [34] 调试逻辑与业务逻辑建议分离处理器.
| |
| * <span id="fn-35"></span> [35] 对外交互 (message/marker) 建议加频率限制.
| |
| * <span id="fn-36"></span> [36] 内存地址使用建议维护单独映射表.
| |
| * <span id="fn-37"></span> [37] 每次大改应维护 migration 日志.
| |
| * <span id="fn-38"></span> [38] 逻辑蓝图发布建议附最小测试图.
| |
| * <span id="fn-39"></span> [39] 复杂项目推荐 CI 自动导出并做语法检查.
| |
| * <span id="fn-40"></span> [40] 本教程若与将来版本冲突, 以新版本实测为准.
| |
|
| |
| ----
| |
|
| |
|
| |
| </div>
| |