欢迎光临散文网 会员登陆 & 注册

这玩意儿啾竟怎么刷的?刷线机原理探讨 - 含手动刷线机和【百万】无人刷线机

2022-09-12 08:08 作者:肥啾U_ruby  | 我要投稿

【请使用电脑查看 - 手机会出现排版错误】
这篇专栏是对刷线机的解释,对于知其然也想知其所以然的小伙伴,或许有所帮助。
观前提示:本特性适用于vanilla,对于修改过的paper/spigot服务端不保证适用性。
另外:1.19.2的paper服务器里可以直接使用1728k/h(安装前问问腐竹,小心被ban)
注意:剪刀剪绊线要轻,很容易一穿二,跟金镐子挖地狱岩一样都是秒破 很容易多挖


背景与手动刷线机

要想解释刷线机的原理,首先要知道它是如何工作的。


1. 常亮绊线

故事要从2021年1月讲起,当时在做依赖绊线的虚空交易所的时候(做村民出坑判定),偶然发现玩家在较短的时间内 [1] 朝特定方向 [2] 连续破坏两个绊线,只会掉落1个掉落物,另1个本该生成掉落物的绊线变成了1格能一直保持激活的绊线,这种线即使实体踩上去也不会熄灭,除非你打掉它,否则会一直亮着。在xekr红石显示资源包中,这种“powered=true”的绊线,会呈现一种亮红色,为了方便描述这种特殊状态的绊线,本着通(直)(白)(粗)(暴)的原则,在之后的探索中,神经元和我称之为:常亮绊线常亮绊线吞掉了原本该掉落的掉落物,并在原地生成了其本身,但因没想到该特性的实际用途,暂且搁置。

[1] 只要时间间隔小于10gt,该操作就可以复现出来。
[2] 经过多次实验发现,绊线与绊线钩为东西朝向时,玩家要站在东侧,先破坏东侧绊线再破坏西侧绊线;绊线与绊线钩为南北朝向时,玩家要站在北侧,先破坏北侧绊线再破坏南侧绊线。

玩家朝西  在10gt内  依次从东向西  打掉俩格绊线  会产生这样的常亮绊线


2. 万恶之源

时隔一年,2022年1月,在reddit的一篇报道中提到使用流水破坏绊线可以实现绊线复制,B站BV1US4y1T72E也对此有所报导。在尝试复现、使用G4mespeed降低tps观察流水的慢镜头时发现,西侧的线发生了复制。观察到水流破坏绊线存在先后顺序(中间绊线先破坏,西侧绊线后破坏),这与玩家制作常亮绊线的破坏顺序很类似

由此我们联想产生假设1:流水破坏绊线也会产生常亮绊线,但刚产生的常亮绊线一定也被水冲掉了。

网址(访问需要七根木棒的合成物):https://www.reddit.com/r/Minecraft/comments/razrv8/very_simple_string_duplication_glitch_118_java/ 

 

水流先破坏了中间的绊线,后破坏了另外两侧的绊线,可以明显看出右侧(西侧)的绊线位置掉落了俩掉落物


3.尝试观测到流水制造的常亮绊线

即使使用carpet指令 /tick freeze 和 /tick step,也无法观测到上图所示情况的任何常亮绊线。但我们认为可能和 tick freeze 的时机不对有关,总结玩家和单桶流水破坏绊线的异同,发现单筒流水的破坏间隔 和玩家打断绊线的时间间隔有所不同,实验证实,如果让玩家放置间隔不同于流水计划刻5gt的流水,便能正常观察到常亮绊线

流水破坏绊线不同于玩家破坏绊线
玩家破坏绊线,掉落物没正常生成,只是多了一根常亮绊线,绊线守恒;
流水破坏绊线,掉落物会正常生成,而且后续的流动还会把这根常亮绊线冲掉,绊线自加1。

当时的我们敏锐的意识到可以将这个特性利用起来,实现自动化,源源不断地产出绊线的AFK机器就此诞生了。

这就是我们设计的手动放线刷线机的核心特性。

间隔2gt放置水源,可以更加清楚的观测到常亮绊线的存在


4.总结和猜测

大量实践后,我们尝试总结这种特性:
绊线与绊线钩朝向为东西/南北,以第1格绊线被破坏为0时计,10gt内 [3] 由流水破坏这格空缺西侧/南侧的绊线,string++
10gt后,无论是流水还是玩家再行破坏绊线都不会产生上述状态。我们称这 10gt 为 绊线 - 绊线钩 结构的不稳定状态。
[3] 10gt 是绊线钩发出红石信号的长度,也是绊线钩添加计划刻的延迟长度

直观的理解:因为mojang当初设计丛林神庙的时候是打算用绊线+绊线钩坑玩家的,玩家必须用mojang指定的道具:剪刀,剪掉绊线,才不会触发绊线钩发出红石信号,才能免于发射器的万箭齐发。除了剪刀以外,无论是玩家直接破坏绊线,还是玩家用流水冲掉绊线,都会触发绊线钩的10gt红石信号,都会挨几箭。
mojang可能认为,玩家/流体拆掉1格绊线应该和玩家踩上绊线都一样,绊线钩都该激活。为了将这俩情况加以区别,mojang可能让绊线钩10gt后再观察一下这条线路中到底是断了个口,还是被玩家踩线了。
如果是断了个口子,那就是破坏行为,绊线钩就不发出信号,10gt的红石信号就完事儿了;如果有实体在上面踩着,那就继续亮。如果我们在绊线钩打算10gt后才反应的这段时间里,趁绊线钩不注意,干点儿别的勾当(比如让流水/玩家再破坏一格绊线),那可能会有意想不到的收获(常亮绊线get√)

于是手动防线的刷线机就这么诞生了。



 更进一步的探索

2022年1月以来,手动刷线机虽然经过改进,效率由6k/h,上升至14.4k/h,再到玩家手长极限放置的86.4k/h,效率达到了瓶颈,但我们没有停下对机制的探索。对于常亮绊线的出现,我们还处于一种“知其然而不知其所以然”的朦胧状态,想搞清楚“mojang到底为什么会放置常亮绊线”的好奇心的驱使下,向 Youmiel、Fallen_breath 学习了反混淆源码的相关知识,获取了 TripWireBlock.java 和 TripWireHookBlock.java 文件,并尝试在这坨东西里找到答案。
注:本文参考代码使用1.18官方mapping进行反混淆

不过在介绍我们找到的判定条件之前,请补充以下知识方便阅读理解:


1. 补充知识

    绊线钩和线在复制中牵扯了三个重要的方块状态:
        一个是绊线钩的attached
            attached=true,绊线钩处于连接状态
            attached=false,绊线钩处于非连接态

        另一个是绊线的disarmed
            disarmed=true,绊线被剪刀剪过
            disarmed=false,绊线是正常的

        第三个是绊线的attached
            attached=true,绊线处于连接状态,扁扁的,距离底部方块有悬空的1像素高的空档
            attached=false,绊线处于非连接态,会膨胀起来,碰撞箱和台阶一样

    玩家破坏绊线、流水破坏绊线,都会激活绊线钩,被剪刀剪过的绊线(剪刀左键绊线)是不会触发绊线的。
  
  | 毕竟麻将头一开始设计这玩意儿就是打算在丛林神庙设置机关坑玩家的,不用剪刀直接拆线会挨箭矢。

    玩家如果不使用连点器,右键放置物品是4gt一次


2. 常亮绊线的制备条件

    常亮绊线是绊线钩自检时calculateState被制造出来的副产物,查阅代码辅以实践我们总结出了常亮绊线的出现条件:

        定义事件A:一对绊线钩之间有更新源以外的非绊线方块(比如空气),1是有,0是无
       
定义事件B:更新源(一般是绊线)的disarmed值,1是被剪了,0是没被剪
      
  定义事件H:绊线钩的attached值,1是连接状态,0是非连接态
        那么,只有
H==(A∨B)时, 才会放置出“常亮绊线”,也是钩子更新绊线连接状态的条件
       | 这里H == A || B代码里的实现其实是H != !A && !B ,是绊线钩calculateState中比较靠下的一段


我们理解的mojang设计目的是:
    线被破坏时,游戏设计上来说要求激活绊线钩激活丛林神庙里的发射器偷袭玩家;这种表现和线被踩踏时的反应是一致的,区别在于线被破坏后的绊线钩只输出这一次红石信号(长度10gt),而被踩踏的绊线应该让绊线钩持续输出红石信号(直到实体消失为止)。


mojang的程序员当时可能是这么想的:
    那么就让破坏的绊线,也向绊线钩报告自己处于“powered=true”的状态好了。直接复用实体站在绊线上powered=true这段代码,懒得再写了。但为了区分“到底是绊线被敲了还是被压着了”,那就再加条件判定下:
    于是这位神仙写道:钩子在收到绊线的report之后,马不停蹄地开始判断自己 calculateState
    ① 绊线钩这个检测方向是从南往北,或者从西往东开始的
    ② 绊线钩会挨个挨个捋过去两个钩子之间的所有方块,挨个判断它们,让我康康你们正不正常,
同时更新绊线状态。

问题就出在这儿,绊线钩更新绊线状态不是改状态,而是直接 setblock.TripWire 直接放置一个新的方块替换掉原本的方块而且由绊线钩直接赋予给线的方块状态不只有 TripWire.attached = false也就是线是否膨胀(false的线和下板砖一样的碰撞箱,true的线就是那种扁扁的)绊线其余的状态都来自它们自身原本的状态
因为 被破坏的绊线,向绊线钩报告的自己处于“powered=true”,绊线钩就信了,所以哪怕这格绊线刚刚报告完,线就无了,绊线钩也会认为它是powered=true”,所以 setblock.TripWire时,在这块之后被破坏的绊线所在格子里,出现了一个状态为 TripWire.attached = false, powered=true 的常亮绊线。


注意: calculateState不是边检查边更新绊线,而是先检查一遍,
            确定线路状态之后更新对面绊线钩,再更新自己,最后才设置绊线的状态


这位神仙当时具体考虑了什么东西呢?

    给钩子报告情况的绊线(更新源)是不是被剪刀剪过啊?
                
如果是一剪子下去了,其余的地方还都是线,那就是玩家正常用剪刀剪线,绊线钩就不该发出信号
                                绊线钩不发出信号的话,TripWireHook.attached 应该是 false,
                                如果 TripWireHook.attached 原本就是 false 那不用动,总之先Lazy,现在不急10gt后再说
                                如果 TripWireHook.attached 原本是 true,
                                        那就把 TripWireHook.attached 设定为 false(目的是先让绊线钩歇菜不发出信号)
                                        挨个捋,从南到北从西向东把绊线状态重新设置一遍 可能程序员觉得钩子false 线该就是松的
                                        然后把捋到的绊线 TripWire.attached = false 其余状态不变

   给钩子报告情况的绊线(更新源)没被剪刀咔嚓过,那它是不是被破坏了吖?
                如果是被破坏,那其余地方还都是线吗?
                        如果都是线那就激活绊线钩(正常被打掉),而且也懒得再更新一遍绊线状态了,10gt后再说
                        如果除报告情况的绊线(更新源)外还有其他不是线的方块 
                                        这说明绊线应该没和钩子连上,整条线路中存在断路,线该是松弛膨胀
                                        那就得挨个捋把绊线状态重新设置一遍
                                        把捋到的绊线 TripWire.attached = false 其余状态不变


逻辑蛮清晰的?的个鬼吖!这有机可乘w~
 不信我们逐步分析下手动刷线中,比较简单的初代机;
如果你对微时序不熟悉,可以看看这个视频临时补课:


3. 手动刷线初代机案例分析

   gt 0 - NU 
        玩家放下第1个绊线,这时水被绊线替换掉,水添加了计划刻准备5gt后冲掉这个绊线(现在一切正常)

gt 0 - NU


    gt 4 - NU 

        玩家放下第2个绊线,水又被替换掉,然后5gt后准备冲掉脚下这个绊线,这时绊线已经连接,状态很正常。

gt 4 - NU


    gt 5 - NTE 

        玩家放下的第一格绊线被水冲掉了,形成了1个掉落物
        这个时候,被破坏的绊线会将自己被破坏这件事情,告诉绊线钩(一种特殊的更新机制)
        而这格被破坏的绊线告诉绊线钩的是,自己 powered=on 
       
| 这和绊线被实体压住激活时,绊线告诉绊线钩的一样都是powered on

        绊线钩开始自检
       | 这对绊线钩中间的方块,会在这个时候,从西往东从南到北,被绊线钩挨个捋一遍,并更新它们的状态
           
H:tripwirehook.attached = true  绊线钩是连接态的
          
  A:false 这对绊线钩之间出了这个更新源(被破坏的绊线)以外,所有方块都是线
         
  B:tripwire.disarmed = false 这个更新源(被破坏的绊线)没被剪刀剪过
      
      (A∨B) = false 没被剪刀剪过,整个线路还都是闭合的(毕竟其余的都是线)
            (A∨B) ≠ H 所以可以Lazy一下,不用着急忙慌的挨个更新绊线,10gt后再说
            所以不会放出常亮绊线
            
| 绊线钩还是连接态不变,只是发出了红石信号

        这时开始,绊线钩进入了一个为期为10gt的不稳定态

gt 5 - NTE


    gt 8 - NU 

        玩家视线对着底下平滑石头的边缘像素块,现在准星在脚下这格绊线上,上面有告示牌,玩家是放不出任何方块。

gt 8 - NU 


    gt 9 - NTE 

      水流破坏掉玩家脚底的线,形成另1个掉落物,这时投入的绊线(2个)已回收,被破坏的绊线将打报告给绊线钩
        告诉绊线钩自己
powered=on

        绊线钩开始自检
            H:tripwirehook.attached = true  绊线钩是连接态的
         
  A:true 这对绊线钩之间出了这个更新源(被破坏的绊线)以外,有一格刚刚冲来的水
         
  B:tripwire.disarmed = false 这个更新源(被破坏的绊线)没被剪刀剪过
   
        (A∨B) = true 没被剪刀剪过,线路是开路(有一格水)
         (A∨B) = H 那绊线钩怎么回事啊,不该是连接态,也不该有红石信号发出!应该马上松弛下来!所以
            绊线钩会从西往东捋,挨个检查绊线钩之间的所有方块,并从西往东逐个setblock所有绊线(更新状态),到这个刚刚被破坏了的绊线,setblock了这个被破坏的绊线上报的powered=true,以及自检中判断出的tripwire.attached=false,所以放出了常亮的松弛膨胀的绊线
        绊线钩自检完成,更新自己的状态,停掉红石信号输出

gt 9 - NTE 


    gt 10 - NTE

        流水在5gt前添加的计划刻,这个时候冲掉了常亮绊线,线成功的多了1,有了盈余,刷线成功!

gt 10 - NTE


    gt 12 - NU

        因为绊线都被清理了,没有阻挡准星的东西了,所以玩家放下了绊线,刷线的下一周期开始。
        因此,初代机的刷线周期是12gt,理论效率为20/12*3600=6000/h



进一步思考

    刚刚我们提到了,放出常亮绊线的几个条件:
        
事件 A:一对绊线钩之间有更新源以外的非绊线方块(比如空气),1是有,0是无
       
事件 B:更新源(一般是绊线)的disarmed值,1是被剪了,0是没被剪
        
事件 H:绊线钩的attached值,1是连接状态,0是非连接态
        那么,只有 
H==(A∨B) 时, 才会放置出“常亮绊线”

    我们的初代机利用了事件 A,那么线被剪刀剪过的 事件 B 能不能也运用起来?
    答案是可行的。拜此所赐我们做出了自动刷线机的雏形。

被剪刀剪过的绊线


自动刷线机的雏形

    这个自动架构中,活版门对着的线,被剪刀剪过,变成了disarmed = true拿剪刀左键线的时候轻点儿,别把剪出来的线给敲掉了(就像金镐子一不小心点掉几块地狱岩一样,毕竟都是瞬间破坏

    这里有一个比较巧妙的点,盔甲架站在地毯上,在绊线处于连接态 attached=true,连接态的绊线底部的1像素高正好让盔甲架碰不到绊线,也无法激活绊线。但如果绊线处于非连接态 attached=false,那么盔甲架正好可以碰到膨胀的绊线。我们来看微时序:



    gt 0 - NU

        玩家打开活版门,水流准备5gt后顺势而下(添加计划刻)

gt0-NU


    gt 5 - NTE

        流水破坏了这个被剪了一剪子的绊线,绊线告诉绊线钩,自己 powered = on,disarmed = true,
            绊线钩开始自检
            H:tripwirehook.attached = true  绊线钩是连接态的
          
  A:false 这对绊线钩之间出了这个更新源(被破坏的绊线)以外都是线
        
    B:tripwire.disarmed = true 这个更新源(被破坏的绊线)被剪刀剪过
           
(A∨B) = true 那不对劲啊,你看,被剪过,绊线线路是闭合的,你绊线钩凭什么是连接态啊?
            (A∨B) = H 所以绊线钩应该马上松弛下来,线也应该马上松弛下来,不该有信号输出w!

        这个时候绊线钩setblock了这个被破坏的绊线上报的powered=true和disarmed=true,以及自检中判断出的tripwire.attached=false,放出了仍然是被剪断的常亮绊线。
        因为是被剪断的,所以这一瞬间绊线钩认为自己应该是 H:tripwirehook.attached = false 
        绊线钩和绊线都呈现非连接态
(能看到绊线钩瞬间的愣神,线没跟钩子连在一起)

gt5-NTE

            这个时候盔甲架刚巧能碰到非连接态的膨胀的绊线,盔甲架头顶这个绊线成了新的激活源
                这引起绊线钩的另一轮自检,绊线钩发现自己应该变成连接态,还顺带添加了个计划刻,10gt后再看看情况
                于是绊线钩状态改变 H:tripwirehook.attached = true 

gt5-NTE 绊线膨胀 盔甲架触发

gt5-NTE 绊线因为刚刚的膨胀而被盔甲架触发引起绊线钩自检,并被绊线钩更新了自己的状态


    gt 10 - NTE 下一个周期

        流水继续冲掉这个刷出来的被剪过的常亮绊线

        绊线钩开始自检
         
  H:tripwirehook.attached = true  绊线钩是连接态的
        
    A:false 这对绊线钩之间出了这个更新源(被破坏的绊线)以外都是线
            
B:tripwire.disarmed = true 这个更新源(被破坏的绊线)被剪刀剪过
       
    (A∨B) = true 那绊线钩大兄弟你不对劲啊,你看,被剪过,绊线线路是闭合的,你绊线钩凭什么是连接态啊?
         (A∨B) = H 所以绊线钩应该马上松弛下来,线也应该马上松弛下来,
        这个时候绊线钩setblock出了被剪断的常亮绊线
        因为是被剪断的,所以这一瞬间绊线钩认为自己应该是 H:tripwirehook.attached = false 
        绊线钩和绊线都呈现非连接态
        但绊线钩因为5gt前已经添加计划刻了所以没有再添加成功计划刻
        盔甲架仍然碰到非连接态的膨胀的绊线,但是绊线由于还是
powered=on(5gt前已经激活了),绊线自己的10gt的冷却还没结束,所以绊线没有再添加成功计划刻,绊线钩还是处于 H:tripwirehook.attached = false

gt10-NTE


    gt 15 - NTE 

        头一开始先执行了绊线钩在 gt 5 时添加的计划刻,绊线钩同时自检,setblock了所有的绊线让他们 tripwire.attached = true,同时绊线钩恢复自身状态 H:tripwirehook.attached = true

        盔甲架头顶的那格绊线在 gt 5 时添加的计划刻,这个时候也开始执行,先把自己tripwire.attached = false,再给绊线钩添加个计划刻(10gt后的)

        然后才是水冲掉常亮绊线,重复 gt 5 时的样子

gt15-NTE

    这东西的周期是5gt,轻易达到了14400/h,效率破万。

    有个缺点,刷线机正在刷着的时候卸载区块,绊线钩、绊线、水的计划刻可能会乱。




丐版 自动刷线机

    经过一番探索我们发现可以去掉盔甲架,进一步简化机器本身。让我们来分析一下它是怎么运作的:
    注意:展示框下的绊线被剪刀剪过

    gt 0 -NU

        玩家拉回拉杆,活版门收起,流水打算冲掉面前的线,首先被冲出去的水应该是平滑石头下面的水源(拉杆附着的先被收起),而后才是拉杆下面的活版门(拉杆毗邻的后更新)

gt0-NU


    gt 5 - NTE

        流水冲掉被剪了一刀的绊线,这个绊线报告给绊线钩

        绊线钩开始自检

            H:tripwirehook.attached = true  绊线钩是连接态的
           
A:false 这对绊线钩之间出了这个更新源(被破坏的绊线)以外都是线
           
B:tripwire.disarmed = true 这个更新源(被破坏的绊线)被剪刀剪过
           
 (A∨B) = true 那不对劲啊,你看,被剪过,绊线线路是闭合的,你绊线钩凭什么是连接态啊?
            (A∨B) = H 所以绊线钩应该马上松弛下来,线也应该马上松弛下来,不该有信号输出w!
            这时绊线钩setblock了这个被破坏的绊线上报的powered=true和disarmed=true,
            以及自检中判断出的tripwire.attached=false,放出了仍然是被剪断的常亮绊线
            因为是被剪断的线,所以这一瞬间绊线钩认为自己应该是 H:tripwirehook.attached = false
            绊线钩和绊线都呈现非连接态

        流水冲掉另一边的没有激活的绊线,这个绊线报告给绊线钩

        绊线钩再次自检

            H:tripwirehook.attached = false  绊线钩是非连接态的
         
  A:false 这对绊线钩之间出了这个更新源(被破坏的绊线)以外都是线(刚刚的空被常亮绊线填上了)
        
    B:tripwire.disarmed = false 这个更新源(被破坏的绊线)没被剪刀剪过
   
         (A∨B) = false 没被剪刀剪过,线路是闭合的
         (A∨B) = H 那绊线钩怎么回事啊,明明是闭合的线路你却不是连接态,赶紧干活!
            这个时候绊线钩setblock了这个被破坏的绊线上报的powered=true,放出了正常的常亮绊线,
            这时绊线钩已经更新了自己的状态,认为又没被剪过所以自己应该是 H:tripwirehook.attached = true 
            绊线钩和绊线都呈现连接态

        绊线喜+2

gt5-NTE

    gt 10 - NTE 

        又是一次循环,又是一个新的周期……

          这个全自动刷线机小巧可爱,周期5gt,每个周期产出两个绊线。所以效率比雏形翻了一番,达到了惊人的28800/h,接近3万的产量需要4个漏斗收集。而且你想怼多少个单元都可以,效率飙升到百万的阵列也不是不可能。

          而且卸载也坏不了。



一些发散思维


    刷出的“常亮绊线”不见得都是“常亮的”
        如果绊线里有实体,绊线有计划刻,可以取消激活态


    关于为啥这个自动刷线机把拉杆和被剪绊线反向之后不能刷线的解释:
        这样子,东面的水(平滑石头下面的)会先流动,被剪的绊线会率先被破坏,绊线钩从西往东捋线,挨个对线setblock,正好到西面水面前绊线的时候更新到了西面的水,给西面的水强行加了一个计划刻,东面的水要再加计划刻得等到绊线钩捋到它面前的时候(常亮绊线放出来的时候)。
        在这1gt内东面的水添加计划刻慢了,导致5gt后(下个循环)东面的水一定会晚于西面的水,所以时序坏掉了。

方向不对导致计划刻不对劲的刷线机


那这种刷线机可以扩展吗?毕竟一对钩子之间可以最多放40根线呢?
        当然可以,  你只要交叉着堆叠,并且保证流水都是先冲剪过的线
      【东 -
[ 正常线 剪过的线 ][ 正常线 剪过的线 ]……[ 正常线 剪过的线 ]- 西】
        效率就能成比例提升,比如这个576k/h的刷线机。
        着刷线效率大概每小时333盒,刷沙机才108k/h(一般来说)
        那么再翻一番,直接破百万也是很合理的叭(576k*2=1152k/h)

        一些连接:
        桃桃呜龙椛喵茶的动态-哔哩哔哩 (bilibili.com)
        Aircraft飞翼之心的动态-哔哩哔哩 (bilibili.com)
        https://t.bilibili.com/705205845988737029


嗯,双向刷线,只是让水流两边冲过来,效率就破百万了


破坏绊线还可以用什么?

        源码里看,玩家移除绊线 playerWillDestroy 是不能复制的,但是水和爆炸可以。        活塞呢?活塞会吞掉常亮绊线,所以我们把活塞直接排除了。
        
【特定版本】22w13o(22w13oneBlockAtATime),激活发射器,它就会把面前的绊线射出去,这玩意儿稍微快一些,是4gt一周期

【特定版本】22w13o(22w13oneBlockAtATime)



这玩意儿啾竟怎么刷的?刷线机原理探讨 - 含手动刷线机和【百万】无人刷线机的评论 (共 条)

分享到微博请遵守国家法律