<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[深入浅出制作全自动Mud机器人-数据与缓存]]></title><description><![CDATA[<p dir="auto">虽然很多客户端和教程介绍机器时，都是用触发来驱动机器。</p>
<p dir="auto">但是，要做一个稳定，功能强大的机器，被动的靠出发来驱动明显不可行，必须要依靠全面详尽的数据来运行。</p>
<p dir="auto">在Mud中，有很多指令会对应获取更新数据。常见比如"hp","score","i","skills"等。</p>
<p dir="auto">我们一般都会根据这些指令的结果来更新数据。</p>
<p dir="auto">但是，Mud又是动态的，这些数据往往又容易失效。</p>
<p dir="auto">做任何动作之前猛刷一通指令明显不科学，浪费服务器资源，还干扰用户使用。在这个情况下，我们肯定是要面对有时效性的数据来进行编码。</p>
<p dir="auto">也就是说，我们在收集数据时，不光光面对是一个采集的问题。还要把数据是做缓存，处理一个缓存失效的问题。</p>
<p dir="auto">那以缓存的角度来看看到数据的话，实际是要实现以下几个地方</p>
<ul>
<li>数据的有效期(ttl)</li>
<li>数据回源(发现过期后主动更新数据）</li>
<li>数据的强制更新(更新数据后更新数据和有效期)</li>
<li>数据强制失效</li>
</ul>
<p dir="auto">实现的方法其实有很多，我这里说说我的实现方法。</p>
<p dir="auto">以<a href="https://github.com/hellclient-scripts/newhelljs/blob/main/script/src/core/player.js" target="_blank" rel="noopener noreferrer nofollow ugc">我的代码</a>为例</p>
<p dir="auto">在处理数据时，我使用了这么一个结构</p>
<pre><code class="language-javascript">    let DefaultExecute = function (check) {
        return check.Command
    }
    class Check {
        constructor(id) {
            this.#id = id
        }
        #id = ""
        Interval = 0
        #last = 0
        Execute = DefaultExecute
        Command = null
        WithExecute(fn) {
            this.Execute = fn ? fn : DefaultExecute
        }
        ID() {
            return this.#id
        }
        WithCommand(cmd) {
            if (typeof (cmd) != "function") {
                this.Command = function () { App.Send(cmd) }
            } else {
                this.Command = cmd
            }
            return this
        }
        WithInterval(interval) {
            interval = interval - 0
            if (isNaN(interval)) {
                interval = 0
            }
            this.Interval = interval
            return this
        }
        InCooldown() {
            return (new Date()).getTime() - this.Interval &lt; this.#last
        }
        Reset() {
            this.#last = (new Date()).getTime()
        }
        Force() {
            this.#last = 0
        }
    }
</code></pre>
<p dir="auto">这个机构很明显。</p>
<ul>
<li>#last 最后一次更新时间</li>
<li>Interval 重新获取数据的间隔(ttl)</li>
<li>Execute,Command 更新数据的函数和指令</li>
<li>#id 缓存的 id,可以制定id进行更新</li>
</ul>
<p dir="auto">在使用时，我会以这样的形式来注册一个数据检查(更新)器</p>
<pre><code class="language-javascript">    let checkerSkills = App.Checker.Register("skills", "skills", 300000)
</code></pre>
<p dir="auto">这是注册一个 id为skills,指令为skills,数据有效期为300秒的检查器。</p>
<p dir="auto">在匹配skill最后的代码最后调用一下Reset</p>
<pre><code class="language-javascript">        function (result) {
                        checkerSkills.Reset()
                    })
</code></pre>
<p dir="auto">就能按一定的有效期来保存数据了。</p>
<p dir="auto">然后由于这个是获取技能数据的，所以我绑定了技能提升的触发事件，在技能重置时强制这个缓存数据失效</p>
<pre><code class="language-javascript">    //技能升级时重置相关的checker
    App.BindEvent("core.skillimproved", function () {
        checkerHPM.Force()
        checkerSkills.Force()
        checkerJifa.Force()
    })
</code></pre>
<p dir="auto">就能比较有效的处理缓存数据了。</p>
<p dir="auto">在可能需要处理状态的地方，我加入了<a href="https://github.com/hellclient-scripts/newhelljs/blob/main/script/src/core/prepare.js" target="_blank" rel="noopener noreferrer nofollow ugc">检查所有预设检查器的代码</a></p>
<pre><code class="language-javascript">    //检查的函数
    App.Check = () =&gt; {
        App.RaiseEvent(eventBeforeCheck)//触发检查发送指令
        let checks = App.Checker.Check()//获取需要执行的检查
        if (checks.length == 0) {//无需检查
            App.Next()
            return
        }
        App.PushCommands(//一次性执行所有检查
            App.Commands.NewFunctionCommand(function () {
                checks.forEach(check =&gt; {
                    check()
                });
                App.Next()
            }),
            App.NewSyncCommand(),
        )
        App.Next()
    }
    //准备函数，第一个函数时准备id,第二个时准备的上下文(环境变量)
    App.Prepare = function (id, context) {
        App.RaiseEvent(eventBeforeCheck)
        let checks = App.Checker.Check()
        if (checks.length == 0) {
            AfterCheck(id, context)
            return
        }
        App.PushCommands(
            App.Commands.NewFunctionCommand(function () {
                checks.forEach(check =&gt; {
                    check()
                });
                App.Next()
            }),
            App.NewSyncCommand(),
            App.Commands.NewFunctionCommand(function () {
                AfterCheck(id, context)
            }),
        )
        App.Next()
    }
</code></pre>
<p dir="auto">这样就能确保每次在需要数据进行决策(准备)时，使用的是最新的有效的数据。</p>
]]></description><link>https://forum.hellclient.com/topic/12/深入浅出制作全自动mud机器人-数据与缓存</link><generator>RSS for Node</generator><lastBuildDate>Thu, 16 Jul 2026 20:19:03 GMT</lastBuildDate><atom:link href="https://forum.hellclient.com/topic/12.rss" rel="self" type="application/rss+xml"/><pubDate>Thu, 08 Jan 2026 13:47:49 GMT</pubDate><ttl>60</ttl></channel></rss>