<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>如若不燃</title><description>酷爱蹦跶，穿梭堂狱</description><link>https://blog.armyja-online.uk/</link><item><title>主机游戏图形 API 移植中的契约重建问题——以《异度神剑3》的渲染适配为例</title><link>https://blog.armyja-online.uk/posts/xc3-graphics-api-contract-reconstruction/</link><guid isPermaLink="true">https://blog.armyja-online.uk/posts/xc3-graphics-api-contract-reconstruction/</guid><description>以《异度神剑3》的渲染适配为例，分析主机游戏跨图形 API 移植的真正难点：不在 API 调用的逐条翻译，而在重建编译期特化所丢失、必须在运行时显式表达的隐含契约。</description><pubDate>Wed, 21 Oct 2026 18:31:00 GMT</pubDate><content:encoded>&lt;h2&gt;一、问题背景与工作定义&lt;/h2&gt;
&lt;p&gt;将一款为主机固定硬件深度特化的游戏迁移到另一套图形 API 上，通常被理解为“翻译图形调用”或“重写渲染后端”。但在实际工程中，真正困难的部分并不是 API 调用的逐条映射，而是恢复原系统在编译期已经确定、在新环境中却不再自动成立的隐含契约。&lt;/p&gt;
&lt;p&gt;《异度神剑3》（Xenoblade Chronicles 3，社区常简称 XC3，亦有 XB3 的写法，指同一作品）是这类问题的典型样本。其渲染系统为 Switch 硬件做了深度特化，大量行为依赖离线编译的着色器产物、管线状态、整数渲染目标格式、Geometry Shader、Transform Feedback 以及绑定槽位等约定。翻译层需要把这些原本由固定硬件和离线工具链共同保证的约定，在运行时重新显式化。任何一条契约缺失，都可能导致管线状态对象无法创建、整个渲染通道输出异常，或特定特效完全失效。&lt;/p&gt;
&lt;p&gt;因此，这项工作更准确的描述是：在另一套图形 API 上重建一组可验证的运行时契约，使可观察渲染行为与原系统保持一致。&lt;/p&gt;
&lt;h2&gt;二、翻译层的核心任务：从编译期特化到运行时契约&lt;/h2&gt;
&lt;p&gt;原游戏运行于 Switch 的 NVN 图形接口。NVN 属于低层显式 API，接近 Metal 或 Vulkan 的设计模型。为了在固定硬件上获得稳定的帧时间，游戏会将大量决策提前固化，包括离线预编译的着色器产物、渲染目标格式、深度与混合状态、采样器配置、顶点布局、绑定槽位、GS/TF 状态、内存布局与同步语义。&lt;/p&gt;
&lt;p&gt;迁移到 Metal/MSL 环境后，翻译层需要回答的问题不再是“某个 API 是否被调用”，而是：该绘制调用在原始主机上使用何种附件格式，像素着色器应输出何种类型，绑定槽位如何映射，是否存在几何或变换反馈阶段，最终像素应满足何种约束。&lt;/p&gt;
&lt;p&gt;从程序结构上看，原平台相当于编译期特化：类型与配置作为模板参数在构建时确定；移植层则相当于运行时解释：这些参数必须转化为显式事实并逐项校验。实践中反复出现的失败，多数发生在契约校验环节，而非渲染循环本身的控制逻辑。&lt;/p&gt;
&lt;h2&gt;三、离线着色器产物的构成与度量误区&lt;/h2&gt;
&lt;p&gt;工程记录中反复出现的“645”，需要先说明它当前实际指代什么。&lt;/p&gt;
&lt;p&gt;XC3 的渲染系统在运行时按材质关键字、渲染目标格式、光照模式、阴影级别等条件，从预先生成的着色器产物中查表选择，而非现场编译。但“645”在当前审计口径下，指的是被审计的顶点与像素着色器 key 集合，不是原游戏的完整着色器库，也不覆盖计算着色器。每个 key 对应一条构建链下的产物，产物不是源代码，而是已经翻译到目标表示、可与宿主管线状态匹配的结果。&lt;/p&gt;
&lt;p&gt;这里需要区分两个层面。着色器 key 来自控制流与代码路径，即 ctl/code。profile 值、事实条目的变化通常改变的是构建链、着色器反射结果以及这些 key 对应的产物，但不自动改变 key 集合本身。也就是说，key 集合是审计对象，产物是构建成本；两者不能混为一谈。把“重建产物”说成“重建整库”，会掩盖真正需要追踪的东西。&lt;/p&gt;
&lt;p&gt;645 的构建属于验证手段，而非工作目标。目标是使 XC3 的渲染结果正确；着色器产物只是让宿主能够定位对应着色器。645 全部通过，只能说明当前 key 集合的产物被重新生成，不能说明运行时渲染问题得到解决。真正构成阻塞的是后续的运行时渲染子系统。&lt;/p&gt;
&lt;p&gt;因此，645 应逐步改为增量构建：仅重建受影响的产物，已确认事实写入持久化表。该指标应被视为成本指标，而非进度指标。它解决的是“宿主能不能找到 shader 产物”，不解决“找到的产物与附件格式、绑定契约、管线状态是否匹配”。&lt;/p&gt;
&lt;h2&gt;四、运行时阻塞的分类：参数、契约与实现&lt;/h2&gt;
&lt;p&gt;当前阻塞项并非同一类问题，至少应分为三类，其确认方式各不相同。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一类是参数值定义错误。&lt;/strong&gt; 纹理槽数量从 16 调整为 27 目前仍是候选事实，尚未作为已修复结论确认。若该候选成立，其性质是函数逻辑未变、传入的配置值不正确，导致大量绑定返回空槽位。此类问题属于参数数值层面，通过配置核对即可确认。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第二类是类型签名或接口契约缺失。&lt;/strong&gt; 整数渲染目标附件格式为 R8Uint、R32Uint 或 RG32Uint，而 MSL 默认生成 float4 输出。NVN 到 MTL 的映射关系本身没有错误，缺失的是一条事实，用于告知生成器该像素着色器的第二个颜色输出应返回 uint4。此类问题属于函数签名或接口契约层面。需要特别区分的是，管线状态能够创建，只证明该签名组合在宿主 API 下是合法的兼容性结果，不证明 bitcast 的数值语义正确。内容语义仍需像素级或数值级证据，不能由管线状态通过来替代。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第三类是函数实现缺失或仅有空壳。&lt;/strong&gt; 几何着色器有若干个未进入映射表，宿主缺少 GS 编码路径，顶点到几何再到像素的链路只能退化为顶点到像素，接口自然不匹配。变换反馈的绑定、开始与结束接口当前是空实现，调用返回成功但没有副作用。此处需要严格限定证据边界：TF 接口为空实现是已确认的事实；但同一次绘制中缓冲区生产与消费链是否因此读到陈旧数据，尚未取得只读证据。因此，不能断言“下游 draw 读到旧 buffer”，也不能将特定特效异常直接归因于 TF 缺失。正确的下一步是先取得同 draw 的生产/消费链只读证据，再决定是否进入实现。&lt;/p&gt;
&lt;p&gt;三类问题的区分很重要：参数值靠配置核对，契约靠格式约束与管线验证，实现靠补充引擎功能或选择性降级。混为一谈，容易把不同性质的困难叠加成“整体都难”的印象。&lt;/p&gt;
&lt;h2&gt;五、复杂度来源：耦合、掩盖与反馈稀缺&lt;/h2&gt;
&lt;p&gt;单项步骤往往并不复杂，整体推进缓慢来自四个因素的叠加。&lt;/p&gt;
&lt;p&gt;其一是契约空间大。格式、输出类型、槽位、采样器、几何与变换反馈、同步、对齐，每个维度都有取值与约束。&lt;/p&gt;
&lt;p&gt;其二是约束互相耦合。附件格式决定合法输出签名，签名决定管线状态能否创建，管线状态决定绘制能否执行。局部修改可能引发远端失败。&lt;/p&gt;
&lt;p&gt;其三是错误掩盖严重。上游槽位错误可能在管线创建阶段才报错；变换反馈空实现不会主动报错，但它的实际后果取决于同 draw 的生产/消费链证据，目前尚未确认；几何着色器静默降级时，日志可能只显示链接失败。&lt;/p&gt;
&lt;p&gt;其四是反馈带宽低。宿主运行通常一次性、不重试，按最小步骤推进并逐轮授权。同样的信息量，本地逆向工程可能数小时完成，此处需要数天。&lt;/p&gt;
&lt;p&gt;若按组合空间估算，朴素上界是各维度取值数量的乘积。但工程上不能按乘积穷举，因为真正需要验证的是约束剪枝后的有效组合，且大量组合属于同一等价类。以整数渲染目标为例，若干绘制对可能只对应两三种签名模式，验证对象应是模式而非单个对。可行做法是离线批量生成候选，利用编译器与管线验证器进行兼容性剪枝，进行差分聚类，再为每个等价类选取代表执行一次宿主确认。需要明确：编译器与管线验证器只是兼容性 oracle，它们可以排除非法组合，但不自动回写事实表；VLM 等视觉工具只辅助筛查，不替代数值或像素 oracle 的确认职能。&lt;/p&gt;
&lt;h2&gt;六、为什么“看到了机器码”仍不能快速复现原逻辑&lt;/h2&gt;
&lt;p&gt;一个常见的疑问是：逆向工程针对机器码进行静态重编译，机器码里包含了程序执行的全部指令，按理说所有逻辑都清清楚楚，为什么不能快速复现原系统的渲染行为？&lt;/p&gt;
&lt;p&gt;这个疑问触及了本项工作的核心难点。更准确的工程解释是：着色器指令流本身不足以恢复完整的执行环境。静态重编译能够把指令翻译成语义等价的宿主指令，但原系统运行所依赖的契约，分散在着色器指令流之外。&lt;/p&gt;
&lt;p&gt;具体而言，契约分布在四个位置。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一，CPU 侧的命令流。&lt;/strong&gt; 引擎在创建管线状态、绑定资源、设置渲染目标时，传递了大量元数据：附件格式、混合状态、深度测试模式、采样器描述、顶点布局。这些信息不在着色器指令里，而在 API 调用序列中。翻译层必须同时理解 CPU 侧命令的语义，才能知道某条着色器指令在何种上下文中执行。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第二，资源与元数据。&lt;/strong&gt; 着色器变体的选择键、材质参数、纹理格式、缓冲区布局，由引擎的材质系统和离线工具链共同维护。运行时只看到“选中了某个变体”，看不到“为什么选它”。这些元数据是契约的一部分，但不随指令流自动转移。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第三，硬件与驱动的隐式保证。&lt;/strong&gt; 格式转换、对齐规则、同步语义、管线状态合法性检查，在原平台上由固定硬件与驱动共同保证。静态重编译把指令搬到新环境后，这些保证不会自动跟随；翻译层必须用宿主 API 的显式规则重新表达它们。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第四，验证成本高于翻译成本。&lt;/strong&gt; 即使指令可翻译，要确认“翻译后的行为与原行为等价”，仍需覆盖契约组合。等价性不是单条指令的属性，而是管线状态、格式、绑定、同步共同作用的结果。&lt;/p&gt;
&lt;p&gt;需要澄清的是，实现一个兼容层并不要求知道原设计者的“设计意图”。行为等价也不是模拟器独有的策略：静态重编译与模拟器都需要重建环境语义，只是重建的位置和方式不同。模拟器在虚拟硬件层重建，静态重编译在宿主 API 层重建。两者的目标都是可观察行为一致，而不是还原设计文档。&lt;/p&gt;
&lt;p&gt;因此，静态重编译解决的是“指令级等价”，而渲染适配需要的是“契约级等价”。前者可以从机器码中获得，后者必须从 CPU 命令、资源元数据、硬件语义和运行观察中逐项重建。看到机器码，不等于看到了契约；翻译了指令，不等于重建了执行环境。这正是“逻辑清清楚楚”却仍不能快速复现原行为的根本原因。&lt;/p&gt;
&lt;h2&gt;七、与一般逆向工程的差异&lt;/h2&gt;
&lt;p&gt;一般逆向工程的目标多样，成功标准也因任务而异。有些逆向任务同样要求严格的全有或全无验收，不能一概而论为“宽松析取式”。但在本次渲染适配的语境下，验收结构确实有一个值得指出的特征。&lt;/p&gt;
&lt;p&gt;渲染适配的目标是两个系统在可观察行为上严格等价。它的验收逻辑是合取式的：即使九成绘制正确，剩余一成涉及几何着色器、变换反馈或整数渲染目标的问题仍可能导致黑屏或错色，必须全部满足。这与“找到一个关键算法或入口即可推进整体理解”的逆向任务在验收结构上不同，但这种差异应限定在本次任务的范围内，不应推广为“逆向都宽松、适配都严格”的二分。&lt;/p&gt;
&lt;p&gt;另一项值得注意的差异在于，原游戏的许多行为是编译期特化结果，类似模板参数已定死；翻译层必须把这些参数转化为运行时显式事实。遗漏一条不是“理解少一点”，而是契约不成立。此外，主机着色器产物与管线描述往往经过离线预编译、符号剥离，采用私有二进制格式，硬件语义未公开，可依赖的白盒信息更少，只能依靠约束推导与少量运行确认。&lt;/p&gt;
&lt;p&gt;因此，这项工作的难度不在于单个函数逻辑，而在于目标函数不同：它是约束满足与缺失功能实现的组合，且验收标准在本次任务中是全有或全无的。&lt;/p&gt;
&lt;h2&gt;八、契约敏感度的游戏间差异：2D、Unity 与深度特化引擎&lt;/h2&gt;
&lt;p&gt;同样涉及翻译或重编译，不同游戏的问题面差异显著。可以粗略认为，翻译层需要补充的契约数量，正比于引擎对硬件的特化深度、渲染管线复杂度与图形特性使用广度的乘积。任一因子增大，问题面都会放大。&lt;/p&gt;
&lt;p&gt;以《茶杯头》为例，其为 Unity 制作的 2D 游戏，渲染需求较窄：主要是精灵、背景、界面与少量粒子；不涉及几何着色器、变换反馈或整数渲染目标；管线状态组合少，着色器变体少。翻译层面对的是 Unity 已归一化的着色器，许多平台差异在引擎层已被抽象。其失败模式也较局部：某个精灵的顶点或纹理映射错误，表现为三角形碎条或个别元素变黑。由于 2D 渲染是独立元素的叠加，单点错误通常只影响局部画面，不阻断整体游玩。2D 的“正确”标准天然比 3D 宽松。&lt;/p&gt;
&lt;p&gt;Unity 3D 游戏则受益于引擎抽象层的兜底。ShaderLab 与多后端编译链本身面向跨平台设计，许多平台差异在引擎层已有标准化路径。翻译层面对的不是原生 NVN 特化着色器，而是 Unity 归一化后的产物，契约缺失较少。所谓“画面一下子就渲染出来”，并非翻译层做得完美，而是引擎层已经吸收了大量复杂度。&lt;/p&gt;
&lt;p&gt;XC3 采用 Monolith Soft 自研引擎，为 Switch 深度优化，几乎同时踩中三个因子。特化深：大量着色器变体、私有格式、符号剥离、绑定槽与格式对齐深度依赖硬件。管线复杂：多通道混合管线，涉及几何缓冲、光照、阴影、大气、水、植被、粒子、后处理与界面。特性广：几何着色器用于粒子、阴影与植被，变换反馈的使用范围与依赖程度仍需同 draw 证据确认，整数渲染目标用于几何缓冲、标识与深度相关输出，采样器与绑定布局复杂。每一项已确认的特性都是翻译层的硬契约点，缺失时不是局部瑕疵，而是管线无法创建、通道黑屏、特效消失或光照全错。&lt;/p&gt;
&lt;p&gt;失败模式的结构性差异正在于此：2D 是元素叠加，错一个只坏一个；3D 复杂管线是强耦合链，错一环可能整帧崩溃。&lt;/p&gt;
&lt;h2&gt;九、架构红利不等于管线简单：与《王国之泪》的对比&lt;/h2&gt;
&lt;p&gt;一个常见疑问是：《王国之泪》同样为 3D 游戏，为何其静态重编译进展看起来更快，是否说明其管线更容易逆向？&lt;/p&gt;
&lt;p&gt;需要修正一个容易产生的误解。ARM64 同构与直连 Metal 是所有 Switch 游戏静态重编译的共同优势，并非《王国之泪》独有。因此，不能仅以“抄近道”解释差异。更准确的说法是：其管线同样复杂，但复杂度更多落在翻译层已有处理能力的维度上；XC3 的复杂度则集中在翻译层最脆弱、最缺乏现成语义的硬契约上。&lt;/p&gt;
&lt;p&gt;《王国之泪》的几何缓冲格式相对常规，以标准 RGBA 与浮点格式为主，未像 XC3 那样为 NPR 数据设计大量非常规打包编码，翻译层对类型与格式的推断负担较小。公开报告显示相关静态重编译方案收集约 8,582 个着色器，而 XC3 在 yuzu 的进度报告中记录其管线缓存超过 15,000 条。这两个数字口径不同：一个是着色器数量，一个是管线缓存条目数，不能直接等同。即便按同口径比较，15,000 与 8,500 的比值约为 1.76 倍，不到一个数量级。更重要的是，着色器或管线数量本身不是契约搜索空间的直接度量；真正决定搜索空间的是格式组合、绑定模式、签名等价类的数量。数量更大只说明潜在组合更多，不自动等于“难一个量级”。&lt;/p&gt;
&lt;p&gt;《王国之泪》对变换反馈的依赖也非核心路径，未出现“缺失导致粒子完全消失”的已证案例，复杂度更多体现在通道调度与带宽优化上，通常表现为性能开销或局部画质瑕疵，而非整条管线无法创建。&lt;/p&gt;
&lt;p&gt;因此，《王国之泪》的管线并不简单，但其复杂度大部分落在翻译层已有处理能力内；XC3 的非标准几何缓冲、更大的管线集合与已确认的 GS/TF 接口缺口，则集中指向翻译层在类型系统、搜索空间与功能实现上的薄弱环节。&lt;/p&gt;
&lt;h2&gt;十、兼容层的环境语义重建策略&lt;/h2&gt;
&lt;p&gt;Yuzu 与 Ryujinx 在适配时是否理解了所有契约？答案是否定的。但它们也并非“不理解契约也能跑”的黑盒。更准确的描述是：它们同样需要重建环境语义，只是重建的方式与静态重编译不同。&lt;/p&gt;
&lt;p&gt;Ryujinx 将 Maxwell GPU 机器码解码为中间表示，再生成 GLSL 或 SPIR-V，本质是指令到指令的映射。它不需要知道指令组合的设计意图，但必须理解 NVN 与宿主 API 之间的语义对应关系，包括资源绑定模型、格式转换规则、管线状态映射。Yuzu 甚至不经过 GLSL，直接生成 SPIR-V 以提高速度，代价是更易出错。遇到不明确行为时，依赖启发式规则、转换优化与社区补丁。例如将几何着色器转换为计算着色器，只要最终效果一致即可。大量修复来自“运行游戏、触发缺陷、定位、打补丁”的循环。&lt;/p&gt;
&lt;p&gt;因此，模拟器与静态重编译并非“不重建契约”与“重建契约”的对立。两者都需要重建环境语义，区别在于重建的层次：模拟器在虚拟硬件与 API 转换层重建，静态重编译在宿主 API 的显式契约层重建。模拟器可以用启发式和近似绕过某些细节，静态重编译则要求这些细节被精确表达。这也解释了为何模拟器当年看似“能跑”，而推进静态重编译时仍会被几何着色器、变换反馈与整数渲染目标卡住。&lt;/p&gt;
&lt;h2&gt;十一、先行者的工作方式&lt;/h2&gt;
&lt;p&gt;这项任务并非 XC3 独有。Switch 静态重编译、兼容层开发和图形管线逆向的先行者，以不同的工作方式处理过同类问题。他们的共同点不是“不累”，而是将认知负荷外部化为不同的形式，而非依赖持续的实时监督循环。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Belmante 与《超级马里奥兄弟：惊奇》原生移植。&lt;/strong&gt; 项目基于静态预编译，将 Switch 的 ARM64 代码翻译为原生 C++，并自行实现 NVN 到 Vulkan 的转换层，直接对接驱动，不经过模拟器、JIT 或解释器。其工作方式是成果驱动的公开汇报：进展通过视频和社区公告同步，而不是逐轮提交给一个实时审批者。精力集中在攻克具体的转换层技术壁垒上。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;gdkchan 与 Ryujinx。&lt;/strong&gt; Ryujinx 以 C# 从零构建，对 Maxwell GPU 进行了高保真的软件级复现，GPU 定时器频率、采样器描述符结构、同步点等均基于硬件测试与 nvservices 逆向。更重要的是，项目自带基于指令集模拟器（Unicorn）的差分测试工程，用自动化 oracle 验证 ARM 到 x86 的翻译正确性。这意味着指令翻译的一致性检查不依赖人工逐条审查，而是由机器完成海量重复验证。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;realskyrin 与 Apple Silicon 移植 Skill。&lt;/strong&gt; 其工作不是亲自移植某一款游戏，而是将完整工作流——版本识别、AArch64 离线改写、Horizon 服务重建、NVN 到 Metal 转换、证据阶梯与记录模板——固化为一份结构化的 Agent Skill，供任何 AI 编程助手调用。这是一种将方法论本身工具化的路径：精力花在设计高效工作流上，而不是在每个具体任务中手动执行流程。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;ScanMountGoat 与《异度神剑》渲染研究。&lt;/strong&gt; 通过 &lt;code&gt;xc3_lib&lt;/code&gt; 工具库和专门的渲染研究网站，系统性地拆解了 XC1/2/3 的几何缓冲结构、材质类型、纹理布局等渲染主题。协作方式是异步的开源模式：贡献者提交 Pull Request 补充研究内容，维护者有时间和精力时审查。没有实时监督循环，产出是结构化的知识（文档、工具），而非逐轮工作报告。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;peiikai 与 LASRecomp（《织梦岛》静态重编译）。&lt;/strong&gt; 该项目将 Switch 版静态重编译到 Windows、macOS 和 Linux 原生平台。作者公开表示，几乎整个项目的代码、工具、逆向工程和文档都由 AI（Claude）完成，自身角色是指导、测试和审查，并承认该项目“超出了他个人的技术能力”。这最接近当前 AI 辅助移植的形态：AI 承担繁重的实现与探索，人类聚焦于方向设定和关键节点验收。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Wine 与 DXVK 的通用工程策略。&lt;/strong&gt; Wine 不反汇编 Windows，而是通过黑箱测试法编写必须在真实 Windows 上运行的一致性测试套件，以可观察行为等价为唯一标准。DXVK 则用精细的脏标记系统跟踪最多 21 个纹理/采样器槽位和 4 个同时渲染目标的状态，以参数化的状态模型覆盖 D3D9 到 Vulkan 的管线组合，而非枚举所有状态。两者的“主管”都是 CI 系统和测试套件，人类开发者的精力集中在编写能通过自动化验证的代码上。&lt;/p&gt;
&lt;p&gt;这些路径的共同逻辑是：将“该验证什么”“什么算通过”“哪些组合可以归并”这类元认知决策，尽可能固化为工具、清单、自动化测试或异步协作流程，而不是依赖监督者在每一轮中实时做出判断。&lt;/p&gt;
&lt;h2&gt;十二、AI 辅助的契约提取与验证流水线&lt;/h2&gt;
&lt;p&gt;传统流程是自动化粗筛加人工目视兜底，瓶颈在于人工反馈的带宽与主观性。AI 时代的方向不是让模型自由生成代码，而是分层自动化语义验证。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一层是契约自动提取。&lt;/strong&gt; 利用 AI 分析着色器字节码或中间表示，推断像素输出类型、绑定槽位、GS/TF 使用模式；以编译器与管线验证器作为兼容性 oracle，批量生成候选、自动剪枝、聚类；仅将等价类代表送入宿主确认。目标不是逐个对试错，而是批量生成加少量代表确认。再次强调：兼容性 oracle 的输出不自动写入事实表，确认仍然需要独立的证据。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第二层是视觉等价 oracle。&lt;/strong&gt; 以 LPIPS 等高容差指标过滤黑屏、白屏等灾难性失败；以 OCR 与界面检测确认文字可读、布局正确；以轻量分类器识别深度冲突、纹理丢失、光照错误、粒子异常；以视觉语言模型按布尔清单裁决。AI 在此只做筛选与语义裁决，不替代数值或像素 oracle 的精确确认。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第三层是选择性降级或重写。&lt;/strong&gt; 并非所有几何与变换反馈都必须原样实现。可分析每个阶段的实际用途：哪些可用计算着色器替代且视觉等价，哪些必须保留原实现。能替代的替代，不能替代的才补。此处的判断依据是证据，不是倾向。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第四层是跨游戏迁移与变异测试。&lt;/strong&gt; 从已知适配中提取契约模式，作为先验候选缩小搜索空间；同时以语义保持的微小变异运行验证流水线，检测契约或 oracle 是否存在漏洞。&lt;/p&gt;
&lt;p&gt;着色器翻译本身也应采用结构化约束加后置校验。不宜让大模型自由生成跨平台代码，因其容易忽略坐标系翻转、精度限定符、原子操作支持等硬件差异。更稳妥的方式是模型生成候选 MSL，再以跨平台语义映射规则表做后置校验与自动修正。&lt;/p&gt;
&lt;p&gt;需要明确边界：以上方法是工程选项，不是下一阶段 scope 的扩张提案。AI 方法应服务于既定的验证目标——先取得真实资源快照，先完成 TF 同 draw 生产/消费链的只读证据，整数 RT 保留已有候选与运行时管线证据——而不是另起炉灶。&lt;/p&gt;
&lt;h2&gt;十三、运行现场快照的可行性与工程折中&lt;/h2&gt;
&lt;p&gt;验证工作流中还有一项实际需求：能否保存整个运行现场，下次直接从目标帧继续，而非每次从头重放输入。&lt;/p&gt;
&lt;p&gt;首先需要区分三种保存。游戏内存档保存玩家进度、道具与位置，读档仍需重新加载场景，不能实现“打开即目标帧”。模拟器 save state 保存整个虚拟主机状态，包括 CPU、内存、GPU 与设备状态，可视为现场快照。静态重编译快照取决于实现，可能是引擎状态，也可能是进程内存加 GPU 资源，同样可以做到，但需要专门实现。&lt;/p&gt;
&lt;p&gt;模拟器较易实现，因为它控制整台虚拟 Switch，CPU、内存、GPU、输入与音频均在其管理之下，状态边界清晰，直接打包即可。GPU 状态也是虚拟设备的一部分，恢复时重建虚拟设备即可。&lt;/p&gt;
&lt;p&gt;静态重编译更难，因为游戏是宿主系统上的原生程序，状态分散于游戏堆、栈、全局变量、宿主线程、图形 API 对象、音频输入设备与动态库内部状态。GPU 资源句柄与宿主 API 对象通常不能直接序列化：Metal 的管线状态对象无法原样写入文件再读回，恢复时通常需要重建资源或重放少量命令。&lt;/p&gt;
&lt;p&gt;实现难度可分三档：模拟器快照相对简单，因其为虚拟整机管理者；有源码的静态重编译完整快照为中等，保存游戏世界状态，恢复时重建 GPU 资源；无源码的复杂 3D 游戏完整现场快照为困难，状态分散、GPU 资源不可直接序列化、流式加载与多线程同步均构成障碍。&lt;/p&gt;
&lt;p&gt;多线程的难点不在于线程数量，而在于无法在所有线程的同一物理时刻拍照，容易捕获撕裂状态；线程私有状态不在共享内存中，栈、寄存器、线程局部存储与同步原语均需处理；互斥锁持有者、等待队列与原子变量不能简单序列化；CPU 与 GPU 异步，快照时需决定等待 GPU 空闲还是保存“已提交未完成”状态。&lt;/p&gt;
&lt;p&gt;工程上通常不追求任意时刻完整快照，而采用帧边界快照：在一帧结束、下一帧开始前执行快照，此时工作线程已汇合、GPU 可等待空闲、逻辑状态完整。多线程难点被帧循环的同步点吸收。对验证工作流而言，更现实的是检查点加确定性重放：固定资源加载与输入序列，从检查点重放到目标帧。关注点是到达目标绘制，而非任意时刻恢复。&lt;/p&gt;
&lt;p&gt;Mac 上已有实际项目实现类似能力。Ship of Harkinian 的快捷键定义为 F5 保存状态、F6 切换状态槽、F7 读取状态，且 Metal 是其 macOS 支持的渲染后端之一。其他重编译项目也报告了 save state 功能。这些多为引擎级状态序列化，而非模拟器式完整虚拟机快照，但对“跳到目标帧”的验证工作流效果一致。&lt;/p&gt;
&lt;h2&gt;十四、路线选择：复刻、重写与分层混合&lt;/h2&gt;
&lt;p&gt;路线选择取决于目标，而非技术优劣的单一判断。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;路线 A 为原样复刻。&lt;/strong&gt; 重建原始 API 语义、管线状态、几何缓冲格式、绑定槽位与几何变换反馈行为，目标是行为等价。优点是能够运行原始内容、复用资产、验收标准明确；缺点是契约空间巨大、长尾极长，且复刻对象是为弱硬件优化的低效管线，迁移到强硬件不会自动变快。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;路线 B 为不理解契约、重写渲染。&lt;/strong&gt; 不追求 API 级等价，只追求最终画面或美术效果等价，利用现代硬件特性重新设计管线。优点是性能上限高、无需逆向私有格式；缺点是“视觉等价”难以定义与验收，需要重建资产管线、材质系统与光照模型，工作量可能更大，且容易丢失原始管线中的细节。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;路线 C 为混合。&lt;/strong&gt; 保留原始游戏逻辑、资产、动画与物理，仅替换渲染后端。这是静态重编译加翻译层的路线。优点是复用原始内容、验收比路线 B 明确；缺点是仍需补渲染契约长尾，性能上限受限于原始管线加翻译开销。&lt;/p&gt;
&lt;p&gt;更现实的做法是在路线 C 内部再分层：契约层保持等价，实现层选择性重写。契约层必须精确，包括像素输出类型、渲染目标格式、绑定槽位、几何与变换反馈接口、管线状态。实现层可以替换，例如以计算着色器替代部分几何或变换反馈、以 bindless 替代复杂绑定、以现代格式替代打包整数渲染目标。只要可观察行为等价即可。&lt;/p&gt;
&lt;p&gt;这样既不需要“理解所有契约才能重写”，也不需要“重写所有东西才能运行”；只需精确确认契约，再按实际用途决定哪些实现可以替换。&lt;/p&gt;
&lt;h2&gt;十五、进度度量：能力成熟度与证据覆盖&lt;/h2&gt;
&lt;p&gt;进度不应以“645 是否通过”“实现了几个 API”或“运行了多少轮”衡量。建议从四个层面观察。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;结果层&lt;/strong&gt;：管线状态可创建率、关键通道像素正确率、端到端场景通过率。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;能力层&lt;/strong&gt;：每个子系统按 L0 至 L5 衡量，分别为未识别、静态清单完成、离线候选完成、合成管线验证通过、真实绘制通过、像素与回归通过。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;证据层&lt;/strong&gt;：已确认事实数与已知未知项数之比，每条事实是否具备可复现证据，未解释差异数量。需要特别区分管线可建性与数值语义：管线状态通过只进入兼容性证据，不自动升级为内容正确性证据。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;吞吐与风险层&lt;/strong&gt;：每轮确认的独立事实数、每次宿主运行确认数、阻塞收敛速度、返工率，以及 645 重建次数。后者为成本指标，不是进度指标。&lt;/p&gt;
&lt;p&gt;概括而言，进度等于关键路径上达到 L4/L5 的能力数、已验证像素覆盖与事实表覆盖之和，除以剩余阻塞。645 全部通过只是当前 key 集合的产物健康度，不是进度。&lt;/p&gt;
&lt;h2&gt;十六、结论&lt;/h2&gt;
&lt;p&gt;当前工作的实质，是将主机游戏的离线着色器产物、管线状态、绑定契约、几何与变换反馈语义，在 Metal 宿主上显式重建，使可观察渲染行为尽量严格等价。&lt;/p&gt;
&lt;p&gt;难度在于：单个函数逻辑大多正确，难在补充参数值、补充类型签名契约、补充缺失函数实现；难在约束耦合、错误掩盖与反馈稀缺；难在验收是合取式，长尾是引擎级功能。&lt;/p&gt;
&lt;p&gt;它比一般逆向工程更难，但这一判断应限定在本次任务的验收结构上，而不是将逆向整体简化为宽松任务。逆向工程同样有严格验收的场景。本次任务的特殊性在于：行为等价要求契约级重建，而机器码只提供指令级等价；契约分散在 CPU 命令、资源元数据、硬件语义与运行观察中，不会随指令翻译自动转移。宿主运行稀缺且逐轮授权，进一步压低了反馈带宽。&lt;/p&gt;
&lt;p&gt;并非所有游戏更换 API 都如此困难。只有深度特化、复杂管线与广泛图形特性三者叠加的游戏才会如此。XC3 正属于这一类。《王国之泪》看起来更快，是因为其复杂度更多落在翻译层已有处理能力内；Yuzu 与 Ryujinx 能够运行，是因为它们同样在重建环境语义，只是选择在虚拟硬件与 API 转换层以启发式和近似方式完成，而非在显式契约层精确表达。&lt;/p&gt;
&lt;p&gt;因此，问题不在于游戏渲染“设计得绕”，而在于主机游戏将大量复杂度压入离线工具链与固定硬件契约；翻译层当前所做的，是把这部分复杂度重新显式化。其难度来源，是一项在验收结构上比一般逆向工程更严格的工程任务。先行者的经验表明，将元认知决策工具化、流程化、异步化，而非依赖持续的实时监督循环，是让这类探索得以持续的关键路径。&lt;/p&gt;
&lt;h2&gt;参考链接&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;realskyrin, &lt;em&gt;ns-game-apple-arm-port: Agent skill for native Nintendo Switch game porting to Apple Silicon macOS, iPadOS and iOS with Rust and Metal&lt;/em&gt;. &lt;a href=&quot;https://github.com/realskyrin/ns-game-apple-arm-port&quot;&gt;https://github.com/realskyrin/ns-game-apple-arm-port&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ScanMountGoat, &lt;em&gt;xc3_lib: Rust libraries and tools for Xenoblade Chronicles rendering formats&lt;/em&gt;. &lt;a href=&quot;https://github.com/ScanMountGoat/xc3_lib&quot;&gt;https://github.com/ScanMountGoat/xc3_lib&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;ScanMountGoat, &lt;em&gt;Xenoblade Rendering Research&lt;/em&gt;. &lt;a href=&quot;https://scanmountgoat.github.io/xenoblade-rendering-research/&quot;&gt;https://scanmountgoat.github.io/xenoblade-rendering-research/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;peiikai, &lt;em&gt;LASRecomp: Static recompilation of Link&apos;s Awakening (Switch) to native macOS, Windows and Linux&lt;/em&gt;. &lt;a href=&quot;https://github.com/peiikai/LASRecomp&quot;&gt;https://github.com/peiikai/LASRecomp&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;gdkchan, &lt;em&gt;Ryujinx: Experimental Nintendo Switch emulator written in C#&lt;/em&gt;. &lt;a href=&quot;https://ryujinx.app/&quot;&gt;https://ryujinx.app/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Belmante, &lt;em&gt;Super Mario Bros. Wonder 原生移植相关报道&lt;/em&gt;. Notebookcheck / XDA Developers, 2026.&lt;/li&gt;
&lt;li&gt;WineHQ, &lt;em&gt;Wine Conformance Test Suite 相关讨论&lt;/em&gt;. Wine mailing list / WineHQ.&lt;/li&gt;
&lt;li&gt;doitsujin, &lt;em&gt;DXVK: Vulkan-based D3D9/D3D10/D3D11 implementation for Linux/Wine&lt;/em&gt;. &lt;a href=&quot;https://github.com/doitsujin/dxvk&quot;&gt;https://github.com/doitsujin/dxvk&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;yuzu, &lt;em&gt;Progress Report 2022-08&lt;/em&gt;. yuzu 模拟器进度报告（XC3 管线数量与 shader 重编译器修复记录）.&lt;/li&gt;
&lt;/ol&gt;
</content:encoded><author>Armyja</author></item><item><title>拼图任务的价值：为什么AI无法完美拼图？</title><link>https://blog.armyja-online.uk/posts/ai-puzzle-np-complete/</link><guid isPermaLink="true">https://blog.armyja-online.uk/posts/ai-puzzle-np-complete/</guid><description>从拼图任务出发，探讨视觉大模型的空间推理能力，以及NP完全问题与AI能力的深层关系</description><pubDate>Tue, 17 Feb 2026 15:17:00 GMT</pubDate><content:encoded>&lt;blockquote&gt;
&lt;p&gt;这是一篇与 Kimi AI 探讨拼图任务价值的对话记录整理。通过这个看似简单的问题，我们触及了视觉大模型的核心局限、计算复杂性理论的本质，乃至于AI能力的边界。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;问题的起点：视觉大模型能否完成拼图？&lt;/h2&gt;
&lt;p&gt;一切起源于这个看似简单的问题：现在的视觉大模型可以完成拼拼图的任务吗？为什么现在的顶尖测试都没有把拼拼图列进去呢？是太简单了还是太难了呢？&lt;/p&gt;
&lt;p&gt;这确实是一个非常敏锐的观察。当我们谈论视觉语言模型（VLM）的能力时，往往关注的是图像分类、目标检测、视觉问答（VQA）等任务，却很少听到有人提及&quot;拼图&quot;这个看似基础的能力。&lt;/p&gt;
&lt;h3&gt;空间推理是公认的短板&lt;/h3&gt;
&lt;p&gt;多项2024-2025年的研究一致表明，空间推理是VLMs的系统性弱点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;基础空间关系识别困难&lt;/strong&gt;：在What&apos;sUp基准测试中，18个主流VLM（包括BLIP、CLIP、LLaVA等）在区分&quot;左/右&quot;、&quot;上/下&quot;等基本空间关系时，准确率仅56%，而人类达到99%&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;心理旋转能力薄弱&lt;/strong&gt;：SpatialEval基准显示，VLMs在物体旋转、折叠等任务上经常表现不如随机猜测&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;缺乏真正的空间理解&lt;/strong&gt;：模型往往依赖语言先验（如&quot;杯子通常在桌子上&quot;）而非视觉分析来做判断&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;拼图任务的特殊挑战&lt;/h3&gt;
&lt;p&gt;拼图任务对VLMs来说既不太简单，也不仅仅是难，而是涉及多重能力缺陷：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;拼图所需能力&lt;/th&gt;
&lt;th&gt;VLM现状&lt;/th&gt;
&lt;th&gt;具体困难&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;边缘匹配&lt;/td&gt;
&lt;td&gt;❌ 极弱&lt;/td&gt;
&lt;td&gt;无法精确比对形状轮廓的连续性&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;纹理/图案衔接&lt;/td&gt;
&lt;td&gt;⚠️ 中等&lt;/td&gt;
&lt;td&gt;可以识别图案，但难以判断&quot;是否对齐&quot;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;全局空间布局&lt;/td&gt;
&lt;td&gt;❌ 弱&lt;/td&gt;
&lt;td&gt;缺乏整体构图的3D理解&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;旋转对齐&lt;/td&gt;
&lt;td&gt;❌ 极弱&lt;/td&gt;
&lt;td&gt;心理旋转任务表现差&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;试错与回溯&lt;/td&gt;
&lt;td&gt;❌ 弱&lt;/td&gt;
&lt;td&gt;长程规划能力不足&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;最新的研究（2025年3月）指出，VLMs存在&lt;strong&gt;语义-几何错位&lt;/strong&gt;（semantic-geometric misalignment）问题——模型能识别物体，但无法建立一致的3D空间表征。这正是拼图任务的核心要求。&lt;/p&gt;
&lt;h2&gt;为什么顶尖测试不包含拼图？&lt;/h2&gt;
&lt;p&gt;主流基准（如MMMU、MMBench、SEED-Bench等）没有将拼图列为评测项，不是因为太简单，而是因为：&lt;/p&gt;
&lt;h3&gt;1. 任务设计层面的&quot;不公平性&quot;&lt;/h3&gt;
&lt;p&gt;拼图是一种&lt;strong&gt;低语义、高几何&lt;/strong&gt;的任务：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;主流VLM架构（CLIP-like）本质上是语义对齐的——将图像映射到语言概念空间&lt;/li&gt;
&lt;li&gt;拼图需要的纯几何匹配与当前训练目标（图像-文本对比学习）脱节&lt;/li&gt;
&lt;li&gt;测试拼图会被批评为&quot;架构偏见&quot;而非&quot;能力缺陷&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. 评测的可操作性难题&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;答案格式不标准化&lt;/strong&gt;：拼图结果是一个空间排列，难以像VQA那样自动评分&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;难度梯度难以控制&lt;/strong&gt;：3片 vs 300片拼图是完全不同的复杂度&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;与核心能力关联性争议&lt;/strong&gt;：拼图能力是否反映&quot;智能&quot;存在学术争议&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. 更根本的原因：空间推理评测已被&quot;分解&quot;&lt;/h3&gt;
&lt;p&gt;学术界不是不关注拼图类能力，而是将其拆解为更基础的子任务分别测试：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SpatialEval&lt;/strong&gt;：测试关系推理、导航、心理旋转、物体计数&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SRBench&lt;/strong&gt;：涵盖空间关系、方向导航、心理旋转、空间可视化&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;What&apos;sUp&lt;/strong&gt;：严格控制的物体位置关系识别&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VSI-Bench&lt;/strong&gt;：视频空间推理&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些基准比传统拼图更严格地测试空间认知，且避免了拼图任务的工程复杂性。&lt;/p&gt;
&lt;h2&gt;拼图的经济价值与战略意义&lt;/h2&gt;
&lt;p&gt;你的追问触及了AI研发中一个核心的战略选择问题。&lt;/p&gt;
&lt;h3&gt;拼图作为任务的&quot;死亡&quot;，拼图作为能力的&quot;重生&quot;&lt;/h3&gt;
&lt;p&gt;传统拼图（把碎片拼成完整图片）确实在消退，但拼图背后的空间推理能力正成为万亿级市场的核心：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;市场领域&lt;/th&gt;
&lt;th&gt;2025-2030年规模&lt;/th&gt;
&lt;th&gt;核心能力需求与拼图的关系&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;具身智能（Embodied AI）&lt;/td&gt;
&lt;td&gt;$230.6亿（CAGR 39%）&lt;/td&gt;
&lt;td&gt;实时空间导航、物体操作——拼图=静态版机器人操作&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;视觉语言模型（VLM）&lt;/td&gt;
&lt;td&gt;$417.5亿（CAGR 26.95%）&lt;/td&gt;
&lt;td&gt;视觉-语言-行动（VLA）对齐——拼图=空间理解的基础测试&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;工业质检&lt;/td&gt;
&lt;td&gt;缺陷减少30%，效率提升20%&lt;/td&gt;
&lt;td&gt;微观对齐、模式匹配——拼图=宏观版边缘匹配&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;空间计算/数字孪生&lt;/td&gt;
&lt;td&gt;高速增长&lt;/td&gt;
&lt;td&gt;3D环境理解——拼图=简化版场景重建&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;关键洞察：&lt;strong&gt;拼图任务本身没有商业价值，但拼图所要求的&quot;几何-语义对齐&quot;能力正在制造、物流、医疗等领域创造数百亿美元的增量价值。&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;为什么基准测试&quot;回避&quot;拼图？——技术路线的分歧&lt;/h3&gt;
&lt;p&gt;主流基准不测试拼图，不是因为没价值，而是因为拼图暴露了当前架构的根本局限：&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;当前VLM的&quot;作弊&quot;能力&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;在VQA任务中，模型可以通过语言先验（&quot;天空在上方&quot;）回答空间问题&lt;/li&gt;
&lt;li&gt;在拼图任务中，这种作弊完全失效——必须真正理解几何关系&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;学术界的&quot;鸵鸟策略&quot;&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;测试拼图 = 承认当前架构（CLIP+LLM）存在不可修复的缺陷&lt;/li&gt;
&lt;li&gt;这会导致投资信心下降（VLM市场正在爆发期）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;所以，不是拼图不重要，而是测试拼图会打断商业叙事。&lt;/p&gt;
&lt;h2&gt;视频生成与拼图的深层联系&lt;/h2&gt;
&lt;p&gt;你的观察非常敏锐——视频生成中的&quot;不合情理&quot;确实与拼图能力共享同一个底层缺陷。&lt;/p&gt;
&lt;h3&gt;视频生成的&quot;幻觉&quot;与拼图的同源性&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;1. 共同的失败模式：几何-语义错位&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当前视频生成模型（Sora、Runway、Pika等）的&quot;不合情理&quot;现象，与VLM在拼图任务上的失败共享同一个根源：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;视频生成中的问题&lt;/th&gt;
&lt;th&gt;拼图任务中的对应&lt;/th&gt;
&lt;th&gt;共同根源&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;物体变形/闪烁（如手突然多手指）&lt;/td&gt;
&lt;td&gt;碎片边缘无法对齐&lt;/td&gt;
&lt;td&gt;缺乏精确的几何约束&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;物理违反（如穿墙、反重力）&lt;/td&gt;
&lt;td&gt;强迫不匹配的碎片拼接&lt;/td&gt;
&lt;td&gt;缺乏物理先验的显式建模&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;时序不一致（人物服装突然变色）&lt;/td&gt;
&lt;td&gt;图案纹理不连续&lt;/td&gt;
&lt;td&gt;跨帧/跨碎片对应关系学习不足&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;镜面反射错误&lt;/td&gt;
&lt;td&gt;无法处理对称/重复图案&lt;/td&gt;
&lt;td&gt;缺乏多视角一致性理解&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;2. 架构层面的同构性&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;视频生成和拼图任务在技术上高度同源：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;视频生成 = 时序维度上的&quot;拼图&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每一帧是一个&quot;碎片&quot;&lt;/li&gt;
&lt;li&gt;时序一致性 = 边缘匹配&lt;/li&gt;
&lt;li&gt;长程依赖 = 全局布局&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;拼图 = 空间维度上的&quot;视频生成&quot;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;每个碎片是一帧&quot;关键帧&quot;&lt;/li&gt;
&lt;li&gt;边缘匹配 = 帧间一致性&lt;/li&gt;
&lt;li&gt;完整图像 = 视频序列&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;为什么视频生成&quot;看起来&quot;更成功？&lt;/h3&gt;
&lt;p&gt;关键区别：&lt;strong&gt;容错率与幻觉容忍度&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;维度&lt;/th&gt;
&lt;th&gt;拼图任务&lt;/th&gt;
&lt;th&gt;视频生成&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;错误可见性&lt;/td&gt;
&lt;td&gt;极高（错位一目了然）&lt;/td&gt;
&lt;td&gt;中等（人眼对时序不一致有容忍度）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;评估标准&lt;/td&gt;
&lt;td&gt;精确几何匹配（硬约束）&lt;/td&gt;
&lt;td&gt;感知合理性（软约束）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;幻觉空间&lt;/td&gt;
&lt;td&gt;极小（必须严丝合缝）&lt;/td&gt;
&lt;td&gt;较大（只要&quot;看起来像&quot;即可）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;商业应用&lt;/td&gt;
&lt;td&gt;低&lt;/td&gt;
&lt;td&gt;极高&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;这就是为什么视频生成可以&quot;作弊&quot;——它不需要真正的3D理解，只需要统计上的时序平滑，而拼图无法作弊——要么对齐，要么不对齐。&lt;/p&gt;
&lt;h2&gt;解决了视频生成，拼图更容易？&lt;/h2&gt;
&lt;p&gt;这是一个非常反直觉的问题。&lt;strong&gt;恰恰相反：视频生成更容易，拼图更难。&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;核心悖论：维度与约束的权衡&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;维度&lt;/th&gt;
&lt;th&gt;视频生成&lt;/th&gt;
&lt;th&gt;拼图&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;信息丰富度&lt;/td&gt;
&lt;td&gt;高（时序连续性提供线索）&lt;/td&gt;
&lt;td&gt;低（静态碎片，无上下文）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;约束类型&lt;/td&gt;
&lt;td&gt;软约束（统计平滑即可）&lt;/td&gt;
&lt;td&gt;硬约束（必须精确匹配）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;容错空间&lt;/td&gt;
&lt;td&gt;大（微小错位人眼难察觉）&lt;/td&gt;
&lt;td&gt;零（错位即失败）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;评估标准&lt;/td&gt;
&lt;td&gt;主观（&quot;看起来对&quot;）&lt;/td&gt;
&lt;td&gt;客观（&quot;确实对齐&quot;）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;为什么视频生成&quot;解决&quot;了，拼图反而更难？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;1. 视频生成的&quot;作弊&quot;本质&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当前视频模型依赖的是统计平滑，而非几何理解：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;视频生成的成功公式：
海量数据 + 扩散模型 + 时序注意力 = &quot;看起来像真的&quot;

拼图需要的公式：
几何约束求解 + 全局优化 + 精确边缘匹配 = &quot;确实是对的&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;2. 拼图是&quot;纯几何&quot;任务，剥离了所有语义拐杖&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;当前VLM的强项是语义-视觉对齐（&quot;这是猫&quot;），弱项是纯几何推理（&quot;这两块边缘曲率一致&quot;）。&lt;/p&gt;
&lt;p&gt;拼图恰好是去语义化的：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;你不能说&quot;这是天空碎片，应该放上面&quot;（语义捷径）&lt;/li&gt;
&lt;li&gt;你必须说&quot;这块边缘的曲率是y=0.3x²，与那块匹配&quot;（几何硬算）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这正是为什么VLM在What&apos;sUp基准（空间关系识别）只有56%准确率，而人类99%——&lt;strong&gt;几何推理与语言理解是不同的认知模块。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;3. 视频生成的&quot;解决方案&quot;不迁移到拼图&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;2024-2025年视频生成的突破确实引入了3D约束，但这些方法：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;视频生成方法&lt;/th&gt;
&lt;th&gt;拼图适用性&lt;/th&gt;
&lt;th&gt;原因&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;时序一致性损失&lt;/td&gt;
&lt;td&gt;❌ 不适用&lt;/td&gt;
&lt;td&gt;拼图无时间维度&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;多帧光流约束&lt;/td&gt;
&lt;td&gt;❌ 不适用&lt;/td&gt;
&lt;td&gt;单张静态图像&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3D高斯溅射&lt;/td&gt;
&lt;td&gt;⚠️ 部分适用&lt;/td&gt;
&lt;td&gt;需多视角，拼图只有单视角&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;物理引擎约束&lt;/td&gt;
&lt;td&gt;❌ 不适用&lt;/td&gt;
&lt;td&gt;拼图是2D几何，非物理模拟&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;视频生成解决的是&quot;时序连贯性&quot;，拼图需要的是&quot;空间精确性&quot;——两者正交。&lt;/p&gt;
&lt;h3&gt;更深层的认知科学视角&lt;/h3&gt;
&lt;p&gt;你的问题假设了一个线性进步模型：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;解决视频生成（难） → 拼图（易）自然解决
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;但实际情况是&lt;strong&gt;能力解耦&lt;/strong&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;人类认知：
视觉理解 ─┬─→ 语义识别（这是什么）
         └─→ 几何推理（这在哪里、如何旋转）

当前AI：
视觉理解 ─┬─→ 语义识别 ✅（CLIP、DINO很强）
         └─→ 几何推理 ❌（仍是盲区）
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;计算机能否完美解决拼图问题？&lt;/h2&gt;
&lt;p&gt;这是一个触及计算本质的问题。&lt;/p&gt;
&lt;h3&gt;理论答案：不能（在一般情况下）&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;核心结论：拼图是NP完全问题&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;根据MIT、斯坦福等机构的最新理论研究：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;定理（Demaine et al., 2025）：即使是最简单的拼图变体——1×n的边匹配拼图（edge-matching puzzle）——也是强NP完全的。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这意味着：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;没有已知的多项式时间算法能在所有情况下完美求解&lt;/li&gt;
&lt;li&gt;如果P ≠ NP（计算机科学最核心的未解猜想），那么不存在高效精确算法&lt;/li&gt;
&lt;li&gt;即使允许近似解，近似到0.999999762以内也是NP难的&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;为什么NP完全性如此致命？&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;问题规模&lt;/th&gt;
&lt;th&gt;穷举搜索时间&lt;/th&gt;
&lt;th&gt;实际意义&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;10片&lt;/td&gt;
&lt;td&gt;10! × 4^10 ≈ 1.2亿种&lt;/td&gt;
&lt;td&gt;计算机可处理&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;25片&lt;/td&gt;
&lt;td&gt;25! × 4^25 ≈ 10^40种&lt;/td&gt;
&lt;td&gt;超过宇宙原子数&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100片&lt;/td&gt;
&lt;td&gt;100! × 4^100 ≈ 10^200种&lt;/td&gt;
&lt;td&gt;绝对不可解&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;实践答案：可以（在特定条件下）&lt;/h3&gt;
&lt;p&gt;虽然理论上是NP完全的，但实际算法在受限场景下表现良好：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;方法&lt;/th&gt;
&lt;th&gt;适用场景&lt;/th&gt;
&lt;th&gt;成功率&lt;/th&gt;
&lt;th&gt;关键限制&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;OpenCV传统算法&lt;/td&gt;
&lt;td&gt;方形、规则边缘、25片以下&lt;/td&gt;
&lt;td&gt;80-95%&lt;/td&gt;
&lt;td&gt;需要特定摄影条件、背景对比度高&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;深度学习+形状匹配&lt;/td&gt;
&lt;td&gt;标准拼图、已知模板&lt;/td&gt;
&lt;td&gt;90%+&lt;/td&gt;
&lt;td&gt;依赖参考图像（hint）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;纯几何求解&lt;/td&gt;
&lt;td&gt;无提示、仅边缘形状&lt;/td&gt;
&lt;td&gt;60-80%&lt;/td&gt;
&lt;td&gt;对噪声敏感、无法处理模糊匹配&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;三种&quot;完美&quot;的定义&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;完美级别&lt;/th&gt;
&lt;th&gt;定义&lt;/th&gt;
&lt;th&gt;可实现性&lt;/th&gt;
&lt;th&gt;技术路线&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;L0：理论完美&lt;/td&gt;
&lt;td&gt;对所有可能的拼图输入都正确&lt;/td&gt;
&lt;td&gt;❌ 不可实现（除非P=NP）&lt;/td&gt;
&lt;td&gt;需要指数时间算法&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;L1：工程完美&lt;/td&gt;
&lt;td&gt;对真实世界拼图（有唯一解、标准形状）100%正确&lt;/td&gt;
&lt;td&gt;⚠️ 接近可实现&lt;/td&gt;
&lt;td&gt;深度学习+约束求解+传感器融合&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;L2：感知完美&lt;/td&gt;
&lt;td&gt;人类无法察觉错误&lt;/td&gt;
&lt;td&gt;✅ 已实现&lt;/td&gt;
&lt;td&gt;当前商业软件可达到&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2&gt;NP完全问题到底是什么？&lt;/h2&gt;
&lt;h3&gt;通俗定义（用拼图解释）&lt;/h3&gt;
&lt;p&gt;想象你在解决一个1000片的拼图：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;问题类型&lt;/th&gt;
&lt;th&gt;定义&lt;/th&gt;
&lt;th&gt;拼图对应&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;P问题&lt;/td&gt;
&lt;td&gt;能快速解决的问题&lt;/td&gt;
&lt;td&gt;验证拼图是否完成（看一眼就知道）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NP问题&lt;/td&gt;
&lt;td&gt;能快速验证解的问题&lt;/td&gt;
&lt;td&gt;有人给你拼好的图，你能快速检查对错&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NP完全问题&lt;/td&gt;
&lt;td&gt;所有NP问题都能归约到它&lt;/td&gt;
&lt;td&gt;找到拼图的解法&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;核心悖论：&lt;strong&gt;验证容易，求解困难&lt;/strong&gt;。如果你有一个拼好的拼图，很容易验证它是否正确。但如果没有参考图，自己拼出来就极其困难。&lt;/p&gt;
&lt;h3&gt;形式化定义&lt;/h3&gt;
&lt;p&gt;一个问题是NP完全的，当且仅当：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;属于NP：解可在多项式时间内验证&lt;/li&gt;
&lt;li&gt;NP-hard：所有NP问题都能归约到它（多项式时间转换）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;关键性质：&lt;strong&gt;如果任何一个NP完全问题有多项式时间算法，那么所有NP问题都有，即P=NP&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;围棋 vs 拼图：谁更难？&lt;/h2&gt;
&lt;h3&gt;复杂度层级对比&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;问题&lt;/th&gt;
&lt;th&gt;复杂度类&lt;/th&gt;
&lt;th&gt;难度定位&lt;/th&gt;
&lt;th&gt;关键特征&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;拼图（边匹配）&lt;/td&gt;
&lt;td&gt;NP完全&lt;/td&gt;
&lt;td&gt;极难，但可验证&lt;/td&gt;
&lt;td&gt;解存在时，验证快；搜索空间大&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;围棋（日式规则）&lt;/td&gt;
&lt;td&gt;EXPTIME完全&lt;/td&gt;
&lt;td&gt;更难&lt;/td&gt;
&lt;td&gt;需要指数时间，且需要指数空间&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;围棋（中式规则）&lt;/td&gt;
&lt;td&gt;猜想：EXPSPACE完全&lt;/td&gt;
&lt;td&gt;极难&lt;/td&gt;
&lt;td&gt;可能需指数空间&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;为什么围棋比拼图&quot;更难&quot;？&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;1. 交互性 vs 静态性&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;维度&lt;/th&gt;
&lt;th&gt;拼图&lt;/th&gt;
&lt;th&gt;围棋&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;信息完全性&lt;/td&gt;
&lt;td&gt;完全信息（所有碎片可见）&lt;/td&gt;
&lt;td&gt;不完全信息（对手策略未知）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;动态性&lt;/td&gt;
&lt;td&gt;静态（一次性求解）&lt;/td&gt;
&lt;td&gt;动态（双方交替，路径爆炸）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;解的长度&lt;/td&gt;
&lt;td&gt;固定（拼好即可）&lt;/td&gt;
&lt;td&gt;不固定（可能无限对弈）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;验证方式&lt;/td&gt;
&lt;td&gt;几何匹配&lt;/td&gt;
&lt;td&gt;胜负判断需模拟至终局&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;2. 计算复杂度的本质差异&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;拼图 = 组合优化问题
     = &quot;找到满足所有约束的排列&quot;
     → NP完全（验证解容易）

围棋 = 博弈树搜索问题
     = &quot;在对手干扰下找到必胜策略&quot;
     → EXPTIME完全（验证策略本身需要指数时间）
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;关键区别：拼图的解是一个静态配置，验证只需检查边缘匹配；围棋的解是一个策略（函数），验证需要模拟所有可能的对手应对，这可能需要指数时间。&lt;/p&gt;
&lt;h3&gt;为什么AlphaGo能击败人类，但拼图算法不完美？&lt;/h3&gt;
&lt;p&gt;这是一个深刻的反差：&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;领域&lt;/th&gt;
&lt;th&gt;人类水平&lt;/th&gt;
&lt;th&gt;AI水平&lt;/th&gt;
&lt;th&gt;原因&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;围棋&lt;/td&gt;
&lt;td&gt;职业九段&lt;/td&gt;
&lt;td&gt;超越人类（AlphaGo）&lt;/td&gt;
&lt;td&gt;虽理论EXPTIME难，但启发式搜索+深度学习可有效逼近&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;拼图&lt;/td&gt;
&lt;td&gt;轻松完成&lt;/td&gt;
&lt;td&gt;不完美（尤其无提示时）&lt;/td&gt;
&lt;td&gt;NP完全问题的组合爆炸更难以启发式规避&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;悖论解释&lt;/strong&gt;：&lt;/p&gt;
&lt;p&gt;围棋虽复杂度更高，但具有结构化启发式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;局部模式（定式）可学习&lt;/li&gt;
&lt;li&gt;价值函数可近似（神经网络评估局面）&lt;/li&gt;
&lt;li&gt;蒙特卡洛树搜索可剪枝&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;拼图虽&quot;仅&quot;NP完全，但缺乏有效启发式：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;边缘匹配是硬约束（要么对，要么错，无中间状态）&lt;/li&gt;
&lt;li&gt;局部决策（两片是否匹配）无法独立评估（需全局一致性）&lt;/li&gt;
&lt;li&gt;深度学习学到的是统计相关性，而非几何精确性&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;核心洞察：复杂度 ≠ 实际难度&lt;/h3&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;复杂度类&lt;/th&gt;
&lt;th&gt;典型问题&lt;/th&gt;
&lt;th&gt;实际求解难度&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;P&lt;/td&gt;
&lt;td&gt;排序、最短路径&lt;/td&gt;
&lt;td&gt;容易&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;NP完全&lt;/td&gt;
&lt;td&gt;拼图、SAT、旅行商&lt;/td&gt;
&lt;td&gt;启发式可处理中等规模&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PSPACE完全&lt;/td&gt;
&lt;td&gt;广义象棋（n×n棋盘）&lt;/td&gt;
&lt;td&gt;更难，但有限内存可处理&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EXPTIME完全&lt;/td&gt;
&lt;td&gt;围棋（标准19×19）&lt;/td&gt;
&lt;td&gt;理论极难，但特定规模可被AI攻克&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;EXPSPACE完全&lt;/td&gt;
&lt;td&gt;围棋（中式规则，理论上）&lt;/td&gt;
&lt;td&gt;几乎不可解&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;关键结论：围棋的EXPTIME完全性是针对&quot;任意大棋盘&quot;的渐近结论。对于固定的19×19棋盘，实际复杂度被常数因子限制，使得深度学习+大规模计算可逼近最优解。拼图的NP完全性则意味着：即使对于固定规模（如100片），只要碎片形状足够复杂，就不存在通用高效算法。&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;问题&lt;/th&gt;
&lt;th&gt;复杂度&lt;/th&gt;
&lt;th&gt;核心难点&lt;/th&gt;
&lt;th&gt;AI现状&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;拼图&lt;/td&gt;
&lt;td&gt;NP完全&lt;/td&gt;
&lt;td&gt;组合爆炸、硬几何约束&lt;/td&gt;
&lt;td&gt;不完美（尤其无提示）&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;围棋&lt;/td&gt;
&lt;td&gt;EXPTIME完全&lt;/td&gt;
&lt;td&gt;博弈树深度、对手不确定性&lt;/td&gt;
&lt;td&gt;超越人类（特定规模）&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;你的直觉需要反转：&lt;strong&gt;围棋虽理论复杂度更高，但其结构化特性使深度学习有效；拼图虽&quot;仅&quot;NP完全，但其纯组合本质和硬约束使当前AI难以完美求解。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这也是为什么拼图仍是计算复杂性理论的经典案例，而围棋已成为AI工程的胜利——&lt;strong&gt;理论难度与实际可解性并不总是一致的。&lt;/strong&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;strong&gt;最终答案&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;在理论上&lt;/strong&gt;：不能（除非P=NP，这将颠覆整个计算机科学基础）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;在工程上&lt;/strong&gt;：可以接近（对标准拼图达到99%+成功率，但无法保证100%）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;在哲学上&lt;/strong&gt;：这揭示了计算复杂性与人类直觉的深刻差异——人类解决拼图依赖模式识别和物理直觉（&quot;这块感觉应该在这里&quot;），而计算机被限制在离散组合搜索的框架中&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;拼图问题之所以重要，正是因为它是NP完全问题的物理化身&lt;/strong&gt;——谁能高效解决它，谁就能解决蛋白质折叠、密码破解、物流优化等无数实际问题。这也是为什么Eternity II拼图（256片边匹配）曾悬赏200万美元，至今未被完全解决。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;拼图只是表象，几何-语义对齐才是核心战场。&lt;/p&gt;
&lt;/blockquote&gt;
</content:encoded><author>Armyja</author></item><item><title>Windows WSL2 部署 OpenClaw 全攻略</title><link>https://blog.armyja-online.uk/posts/openclaw-wsl2-deployment/</link><guid isPermaLink="true">https://blog.armyja-online.uk/posts/openclaw-wsl2-deployment/</guid><description>详细介绍如何在 Windows WSL2 环境下部署和配置 OpenClaw AI 助手，并集成 Telegram 频道。</description><pubDate>Sun, 08 Feb 2026 13:40:00 GMT</pubDate><content:encoded>&lt;h2&gt;引言&lt;/h2&gt;
&lt;p&gt;在 Windows 环境下想要运行一个强大的 AI 助手，又不想放弃 Linux 的命令行体验？WSL2（Windows Subsystem for Linux 2）是最佳选择。本文将详细介绍如何在 WSL2 中部署 OpenClaw，并配置 Telegram 频道进行交互。&lt;/p&gt;
&lt;h2&gt;WSL2 环境准备&lt;/h2&gt;
&lt;h3&gt;1. 启用 WSL2 功能&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# 以管理员身份运行 PowerShell
wsl --install
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这会自动安装 Ubuntu（默认发行版）和 WSL2。安装完成后需要重启系统。&lt;/p&gt;
&lt;h3&gt;2. 解决 WSL 启动错误（踩坑 💥）&lt;/h3&gt;
&lt;p&gt;如果启动 WSL 时出现错误代码 &lt;code&gt;0xc03a0014&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Installing, this may take a few minutes...
WslRegisterDistribution failed with error: 0xc03a0014
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;解决方案：&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;打开 Windows &lt;strong&gt;设备管理器&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;找到 &lt;strong&gt;Microsoft 虚拟驱动器枚举器&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;右键 → 启用设备&lt;/li&gt;
&lt;li&gt;重新进入 WSL，输入用户名和密码即表示成功&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;3. 更新系统&lt;/h3&gt;
&lt;p&gt;⚠️ &lt;strong&gt;重要：&lt;/strong&gt; WSL 里的基础软件默认装不了，必须先更新软件源！&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt update &amp;amp;&amp;amp; sudo apt upgrade -y
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. 安装必要工具&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# 安装 curl、git、nodejs 等
sudo apt install -y curl git wget build-essential
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5. WSL 网络模式配置（踩坑 💥）&lt;/h3&gt;
&lt;p&gt;如果主机使用了 V2RayN 等代理软件，&lt;strong&gt;NAT 模式下 WSL 无法直接访问主机的代理&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;解决方案：启用镜像模式 + 自动代理&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;编辑 Windows 用户目录下的 &lt;code&gt;.wslconfig&lt;/code&gt; 文件（如果没有就创建）：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;# C:\Users\你的用户名\.wslconfig
[wsl2]
networkingMode=mirrored
autoProxy=true
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;然后重启 WSL：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;wsl --shutdown
# 重新打开 WSL 终端
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;效果：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;WSL 可以直接使用主机 IP &lt;code&gt;127.0.0.1&lt;/code&gt; 访问代理&lt;/li&gt;
&lt;li&gt;Telegram 等需要代理的 channel 收发消息正常&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;安装 OpenClaw&lt;/h2&gt;
&lt;h3&gt;1. 使用 npm 全局安装&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;sudo npm install -g openclaw
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 启动引导程序&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;openclaw onboard
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;引导程序会引导你完成以下配置：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;工作区目录&lt;/strong&gt;：选择存放配置和文件的目录&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;模型配置&lt;/strong&gt;：配置 AI 模型提供商（如 MiniMax、OpenAI 等）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Telegram 集成&lt;/strong&gt;：配置 Telegram Bot Token&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. 配置 Telegram Bot&lt;/h3&gt;
&lt;h4&gt;3.1 创建 Bot&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;在 Telegram 中搜索 &lt;code&gt;@BotFather&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;发送 &lt;code&gt;/newbot&lt;/code&gt; 创建新 Bot&lt;/li&gt;
&lt;li&gt;按照提示设置 Bot 名称和用户名&lt;/li&gt;
&lt;li&gt;获取 Bot Token&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;3.2 配置 OpenClaw&lt;/h4&gt;
&lt;p&gt;编辑配置文件：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;nano ~/.openclaw/openclaw.json
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;关键配置项：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;channels&quot;: {
    &quot;telegram&quot;: {
      &quot;botToken&quot;: &quot;你的Bot Token&quot;,
      &quot;dmPolicy&quot;: &quot;pairing&quot;,
      &quot;groupPolicy&quot;: &quot;allowlist&quot;
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h4&gt;3.3 配对用户&lt;/h4&gt;
&lt;p&gt;用户需要在 Telegram 中与 Bot 对话，然后管理员批准配对请求：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;openclaw telegram pair
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;配置详解&lt;/h2&gt;
&lt;h3&gt;基础配置示例&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;agents&quot;: {
    &quot;defaults&quot;: {
      &quot;model&quot;: {
        &quot;primary&quot;: &quot;minimax-portal/MiniMax-M2.1&quot;
      },
      &quot;verboseDefault&quot;: &quot;on&quot;,
      &quot;workspace&quot;: &quot;/home/用户名/.openclaw/workspace&quot;
    }
  },
  &quot;commands&quot;: {
    &quot;bash&quot;: true
  },
  &quot;channels&quot;: {
    &quot;telegram&quot;: {
      &quot;dmPolicy&quot;: &quot;pairing&quot;,
      &quot;groupPolicy&quot;: &quot;allowlist&quot;,
      &quot;streamMode&quot;: &quot;partial&quot;,
      &quot;groups&quot;: {
        &quot;群ID&quot;: {
          &quot;requireMention&quot;: false,
          &quot;groupPolicy&quot;: &quot;open&quot;
        }
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;命令配置&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;commands&quot;: {
    &quot;native&quot;: &quot;auto&quot;,
    &quot;nativeSkills&quot;: &quot;auto&quot;,
    &quot;bash&quot;: true
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;开启 &lt;code&gt;bash&lt;/code&gt; 命令后，可以在对话中直接执行 Shell 命令。&lt;/p&gt;
&lt;h2&gt;常用工具配置&lt;/h2&gt;
&lt;h3&gt;1. VS Code 连接 WSL（推荐）&lt;/h3&gt;
&lt;h4&gt;1.1 安装步骤&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;在 Windows 上安装 VS Code&lt;/strong&gt;（不是 WSL 里！）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;下载地址：https://code.visualstudio.com/download&lt;/li&gt;
&lt;li&gt;安装时勾选 &lt;strong&gt;&quot;添加到 PATH&quot;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;安装远程开发扩展包&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;打开 VS Code&lt;/li&gt;
&lt;li&gt;按 &lt;code&gt;Ctrl+Shift+X&lt;/code&gt; 打开扩展面板&lt;/li&gt;
&lt;li&gt;搜索并安装 &lt;strong&gt;&quot;Remote - WSL&quot;&lt;/strong&gt;（属于 ms-vscode-remote 扩展包）&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;WSL 里先更新软件源&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo apt update
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;1.2 打开 WSL 项目&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;方式一：命令行（推荐）&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;cd /你的项目目录
code .
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;方式二：VS Code 里连接&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;Ctrl+Shift+P&lt;/code&gt; 打开命令面板&lt;/li&gt;
&lt;li&gt;输入 &lt;code&gt;WSL&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;选择 &quot;WSL: Reopen Folder in WSL&quot;&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;1.3 扩展安装注意事项&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;只需装一次&lt;/strong&gt;（主题、UI 扩展）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;需要单独装&lt;/strong&gt;（Python、调试器、linting 等）- 在 WSL 里装&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;⚠️ 如果 WSL 里没装扩展，VS Code 会显示 ⚠️ 图标，点击 &quot;在 WSL 中安装&quot; 即可。&lt;/p&gt;
&lt;h3&gt;安装 GitHub CLI&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;sudo apt install gh -y
gh auth login --web
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;OpenClaw 高级配置&lt;/h2&gt;
&lt;h3&gt;1. 配置系统代理（踩坑 💥）&lt;/h3&gt;
&lt;p&gt;如果使用了 V2RayN 等代理软件，需要让 OpenClaw Gateway 服务使用代理，否则 Telegram 无法收发消息。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;方案一：编辑 systemd 服务文件&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl edit openclaw-gateway.service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;添加以下内容：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[Service]
Environment=&quot;HTTP_PROXY=http://127.0.0.1:代理端口&quot;
Environment=&quot;HTTPS_PROXY=http://127.0.0.1:代理端口&quot;
Environment=&quot;ALL_PROXY=http://127.0.0.1:代理端口&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;方案二：直接编辑服务文件&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo nano /etc/systemd/system/openclaw-gateway.service
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;在 &lt;code&gt;[Service]&lt;/code&gt; 段落下添加：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Environment=&quot;HTTP_PROXY=http://127.0.0.1:端口&quot;
Environment=&quot;HTTPS_PROXY=http://127.0.0.1:端口&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;重启服务使配置生效：&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;sudo systemctl daemon-reload
sudo systemctl restart openclaw-gateway.service
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. 验证代理是否生效&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# 查看服务环境变量
sudo systemctl show openclaw-gateway.service | grep Environment=
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. Telegram 群聊配置&lt;/h3&gt;
&lt;p&gt;在群聊中无需 @ 提及即可自动回复：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;channels&quot;: {
    &quot;telegram&quot;: {
      &quot;groupAllowFrom&quot;: [&quot;*&quot;],
      &quot;groups&quot;: {
        &quot;-100123456789&quot;: {
          &quot;requireMention&quot;: false,
          &quot;groupPolicy&quot;: &quot;open&quot;
        }
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;内存搜索&lt;/h3&gt;
&lt;p&gt;启用长期记忆功能：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;agents&quot;: {
    &quot;defaults&quot;: {
      &quot;memorySearch&quot;: {
        &quot;enabled&quot;: true,
        &quot;sources&quot;: [&quot;memory&quot;, &quot;sessions&quot;]
      }
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;测试与使用&lt;/h2&gt;
&lt;h3&gt;1. 启动 OpenClaw&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;openclaw
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. Telegram 交互&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;私聊&lt;/strong&gt;：直接发送消息&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;群聊&lt;/strong&gt;：无需 @ 提及（配置后）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;命令&lt;/strong&gt;：使用 &lt;code&gt;/help&lt;/code&gt; 获取帮助&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. 常用命令&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# 查看状态
openclaw status

# 重启服务
openclaw restart

# 查看日志
openclaw logs
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;常见问题&lt;/h2&gt;
&lt;h3&gt;Q1: WSL2 与 Windows 文件互通&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;# 在 WSL 中访问 Windows 文件
cd /mnt/c/Users/你的用户名/

# 将 WSL 项目链接到 Windows 桌面
ln -s ~/.openclaw/workspace /mnt/c/Users/你的用户名/Desktop/openclaw
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Q2: 代理配置&lt;/h3&gt;
&lt;p&gt;如果需要代理：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;export HTTP_PROXY=&quot;http://代理地址:端口&quot;
export HTTPS_PROXY=&quot;http://代理地址:端口&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Q3: Telegram 连接问题&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;检查 Bot Token 是否正确&lt;/li&gt;
&lt;li&gt;确认网络可以访问 Telegram API&lt;/li&gt;
&lt;li&gt;检查 &lt;code&gt;dmPolicy&lt;/code&gt; 和 &lt;code&gt;groupPolicy&lt;/code&gt; 配置&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;通过 WSL2，我们可以在 Windows 上享受完整的 Linux 开发和运维体验，同时通过 OpenClaw 获得强大的 AI 助手能力。配合 Telegram 频道，可以实现随时随地的智能交互。&lt;/p&gt;
&lt;h2&gt;参考资源&lt;/h2&gt;
&lt;h3&gt;OpenClaw 官方资源&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.openclaw.ai&quot;&gt;OpenClaw 官方文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/openclaw/openclaw&quot;&gt;OpenClaw GitHub&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;WSL2 官方文档&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://docs.microsoft.com/windows/wsl&quot;&gt;WSL2 官方文档&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://blog.csdn.net/m0_52329284/article/details/147005298&quot;&gt;WSL 启动错误 0xc03a0014 解决方案&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/zh-cn/windows/wsl/networking&quot;&gt;WSL 网络配置（NAT/镜像模式）&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://learn.microsoft.com/zh-cn/windows/wsl/tutorials/wsl-vscode&quot;&gt;VS Code 连接 WSL 教程&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Armyja</author></item><item><title>网易云音乐工具[安卓]</title><link>https://blog.armyja-online.uk/posts/netease-tool/</link><guid isPermaLink="true">https://blog.armyja-online.uk/posts/netease-tool/</guid><description>网易云音乐工具</description><pubDate>Sat, 26 Oct 2024 02:10:00 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;meting-js id=&quot;2610226440&quot; type=&quot;song&quot; server=&quot;netease&quot; fixed=&quot;false&quot; mini=&quot;false&quot; autoplay=&quot;false&quot; theme=&quot;#255579&quot;&amp;gt;&amp;lt;/meting-js&amp;gt;&lt;/p&gt;
&lt;h2&gt;软件说明&lt;/h2&gt;
&lt;p&gt;开发这个软件的初衷，是因为笔者习惯在手机下载音乐，遇到了几个痛点：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;网页版的NCM转换工具，不支持给音乐加上封面；&lt;/li&gt;
&lt;li&gt;从一些第三方音源下载下来的音乐文件没有标签，手动添加标签太麻烦。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;软件特性&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;把ncm里面的图片url下载内嵌到音乐标签，最后再导出音乐文件。只要选择一个文件夹 就将该目录下的所有ncm文件做处理，原地保存新文件。&lt;/li&gt;
&lt;li&gt;修改标签功能支持手动和半自动。半自动的意思是：先在APP打开歌曲的修改tag弹框，接着点击网易云音乐的分享歌曲链接按钮，然后回到APP，APP会自动监听剪贴板里的网址并自动解析（或者手动点击读取剪贴板按钮），一键填写标签和封面。&lt;/li&gt;
&lt;li&gt;在APP点开修改弹窗后会自动播放歌曲，这样在播放过程中就可以切到网易云音乐APP听歌识曲，通过识曲的结果定位音乐，从而得到分享链接。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;软件BUG&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;如果既通过剪贴板导入封面，又马上修改图片，可能出现图片不符合预期的情况。返回主界面，重新扫描 重新导入本地图片即可。&lt;/li&gt;
&lt;li&gt;ncm转换后的文件名，可能和原文件的文件名不一致。如果不一致，会重复生成如同(1) (2)的音乐文件。建议只生成一次 然后手动迁移或删除已处理的ncm文件。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;应用截图&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;https://bucket.armyja-online.uk/armyja/1729910567283.png&quot; alt=&quot;1729910567283.png&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://bucket.armyja-online.uk/armyja/1729910567334.jpg&quot; alt=&quot;1729910567334.jpg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://bucket.armyja-online.uk/armyja/1729910567314.jpg&quot; alt=&quot;1729910567314.jpg&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://bucket.armyja-online.uk/armyja/1729910567297.jpg&quot; alt=&quot;1729910567297.jpg&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;下载方式&lt;/h2&gt;
&lt;p&gt;https://www.ilanzou.com/s/qdgys29f&lt;br /&gt;
提取码：orck&lt;br /&gt;
解压密码：52pojie&lt;/p&gt;
</content:encoded><author>Armyja</author></item><item><title>洞洞谱制作器</title><link>https://blog.armyja-online.uk/posts/tin-whistle-tabs-creator/</link><guid isPermaLink="true">https://blog.armyja-online.uk/posts/tin-whistle-tabs-creator/</guid><pubDate>Thu, 09 May 2024 16:04:41 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;head&amp;gt;
&amp;lt;title&amp;gt;洞洞谱制作器&amp;lt;/title&amp;gt;
&amp;lt;meta name=viewport content=&quot;width = device-width, initial-scale = 1&quot;&amp;gt;
&amp;lt;style&amp;gt;
.l {
writing-mode: vertical-rl;
letter-spacing: 0.2ch;
}
#p_title {
font-size: 1.2em;
font-weight: bold;
}
#box&amp;gt;input,#box&amp;gt;button,#box&amp;gt;textarea {
border: 1px solid #ccc;
}
&amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;body&amp;gt;
&amp;lt;div id=box&amp;gt;
&amp;lt;select id=&quot;type&quot;&amp;gt;
&amp;lt;option value=&quot;5&quot;&amp;gt;全按作5&amp;lt;/option&amp;gt;
&amp;lt;option value=&quot;1&quot;&amp;gt;全按作1&amp;lt;/option&amp;gt;
&amp;lt;/select&amp;gt;
标题：&amp;lt;input type=&quot;text&quot; id=&quot;title&quot;&amp;gt;
&amp;lt;br /&amp;gt;
简谱（1、(5)、[3]、[[1]]...）
&amp;lt;br /&amp;gt;
&amp;lt;textarea id=content&amp;gt;&amp;lt;/textarea&amp;gt;
&amp;lt;button id=&apos;btn&apos;&amp;gt;生成&amp;lt;/button&amp;gt;
&amp;lt;br /&amp;gt;
&amp;lt;br /&amp;gt;
&amp;lt;div id=p&amp;gt;
&amp;lt;div id=&quot;p_title&quot;&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;div id=&quot;p_type&quot;&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;br /&amp;gt;
&amp;lt;div id=&quot;preview&quot;&amp;gt;&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;script&amp;gt;
normal = {
&apos; &apos;: &apos;&amp;lt;span class=&quot;l&quot;&amp;gt; &amp;lt;/span&amp;gt;&apos;,
&apos;\n&apos;: &apos;&amp;lt;br/&amp;gt;&amp;lt;br/&amp;gt;&apos;
}
one = {
&apos;1&apos;: &apos;bbbbbb&apos;,
&apos;2&apos;: &apos;bbbbbw&apos;,
&apos;3&apos;: &apos;bbbbww&apos;,
&apos;4&apos;: &apos;bbbwww&apos;,
&apos;5&apos;: &apos;bbwwww&apos;,
&apos;6&apos;: &apos;bwwwww&apos;,
&apos;7&apos;: &apos;wwwwww&apos;,
&apos;[1]&apos;: &apos;wbbbbb+&apos;,
&apos;[2]&apos;: &apos;bbbbbw+&apos;,
&apos;[3]&apos;: &apos;bbbbww+&apos;,
&apos;[4]&apos;: &apos;bbbwww+&apos;,
&apos;[5]&apos;: &apos;bbwwww+&apos;,
&apos;[6]&apos;: &apos;bwwwww+&apos;,
&apos;[7]&apos;: &apos;wwwwww+&apos;,
&apos;[[1]]&apos;: &apos;wbbbbb+&apos;,
}
five = {
&apos;(5)&apos;: &apos;bbbbbb&apos;,
&apos;(6)&apos;: &apos;bbbbbw&apos;,
&apos;(7)&apos;: &apos;bbbbww&apos;,
&apos;1&apos;: &apos;bbbwww&apos;,
&apos;2&apos;: &apos;bbwwww&apos;,
&apos;3&apos;: &apos;bwwwww&apos;,
&apos;4&apos;: &apos;wbbwww&apos;,
&apos;5&apos;: &apos;wbbbbb+&apos;,
&apos;6&apos;: &apos;bbbbbw+&apos;,
&apos;7&apos;: &apos;bbbbww+&apos;,
&apos;[1]&apos;: &apos;bbbwww+&apos;,
&apos;[2]&apos;: &apos;bbwwww+&apos;,
&apos;[3]&apos;: &apos;bwwwww+&apos;,
&apos;[4]&apos;: &apos;hwwwww+&apos;,
&apos;[5]&apos;: &apos;wbbbbb+&apos;,
}
const c_h = &apos;◐&apos;
const c_b = &apos;●&apos;
const c_w = &apos;○&apos;
for (let k in one) {
one[k] = one[k].replaceAll(&apos;b&apos;, c_b).replaceAll(&apos;w&apos;, c_w)
if (one[k].length &amp;lt; 7) {
one[k] += &apos;  &apos;
}
}
for (let k in five) {
five[k] = five[k].replaceAll(&apos;b&apos;, c_b).replaceAll(&apos;w&apos;, c_w).replaceAll(&apos;h&apos;, c_h)
if (five[k].length &amp;lt; 7) {
five[k] += &apos;  &apos;
}
}
btn.onclick = function () {
updateContent()
updateTitle()
updateType()
}
function updateTitle() {
p_title.textContent = title.value
}
title.onchange = updateTitle
function updateType() {
p_type.textContent = type.options[type.selectedIndex].text
}
type.onchange = updateType;
function updateContent() {
let str = content.value.trim()
let arr = parse(str)
let html = gen(arr)
}
content.onchange = updateContent
function gen(arr) {
let ret = &apos;&apos;
for (let s of arr) {
if (s in normal) {
ret += normal[s]
continue
}
let current = type.value === &apos;1&apos; ? one : five;
if (s in current) {
ret += &lt;code&gt;&amp;lt;span class=&quot;l&quot;&amp;gt;${current[s]}&amp;lt;/span&amp;gt;&lt;/code&gt;
}
}
preview.innerHTML = ret;
}
function parse(str) {
let arr = [];
for (i = 0; i &amp;lt; str.length; i++) {
if (str[i] === &apos;[&apos;) {
if (str[i + 1] === &apos;[&apos;) {
arr.push(str.substr(i, 5));
i += 4;
continue;
}
arr.push(str.substr(i, 3));
i += 2;
continue;
}
if (str[i] === &apos;(&apos;) {
arr.push(str.substr(i, 3));
i += 2;
continue;
}
arr.push(str[i])
}
return arr;
}
&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;&lt;/p&gt;
&lt;p&gt;&amp;lt;/html&amp;gt;&lt;/p&gt;
</content:encoded><author>Armyja</author></item><item><title>QueryDSL源码阅读</title><link>https://blog.armyja-online.uk/posts/querydsl-code-reading/</link><guid isPermaLink="true">https://blog.armyja-online.uk/posts/querydsl-code-reading/</guid><description>QueryDSL是一个强大的框架,它使Java开发人员能够以类型安全的方式构建SQL查询。</description><pubDate>Thu, 04 Apr 2024 14:32:00 GMT</pubDate><content:encoded>&lt;h2&gt;导语&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/querydsl/querydsl&quot;&gt;QueryDSL&lt;/a&gt;是一个强大的框架,它使Java开发人员能够以类型安全的方式构建SQL查询。以下是我喜欢QueryDSL的一些原因：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;QueryDSL让我们摆脱了编写原始SQL字符串的麻烦,这种做法容易出错且难以维护。相反,QueryDSL提供了一个优雅的API,让我们可以像在Java代码中一样构建查询。这不仅提高了代码的可读性,还消除了SQL注入的风险。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;QueryDSL支持多种持久层框架,如JPA、SQL、MongoDB和Lucene等。无论使用何种持久层技术,QueryDSL都能提供统一的查询API,这极大地简化了跨框架的代码移植。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;QueryDSL查询是完全类型安全的,编译器会检查错误,避免了许多运行时错误。这使得重构变得更加容易和安全。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;QueryDSL查询也更易于维护。相比晦涩的SQL字符串,QueryDSL查询的代码结构更清晰,注释也更易于编写和理解。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;总之,QueryDSL让我们能够以一种现代、类型安全和面向对象的方式来构建查询,极大地提高了生产力和代码质量。它是Java持久层编程中非常有价值的工具。&lt;/p&gt;
&lt;p&gt;关于QueryDSL的使用示例，可以参考 Jay Kim 的&lt;a href=&quot;https://jskim1991.medium.com/spring-boot-exploring-spring-boot-3-with-querydsl-part-2-7b563c382192&quot;&gt;文章&lt;/a&gt; 和&lt;a href=&quot;https://github.com/jskim1991/spring-boot-querydsl-sample&quot;&gt;代码仓库&lt;/a&gt;。&lt;/p&gt;
&lt;h2&gt;模块分析&lt;/h2&gt;
&lt;p&gt;从 &lt;code&gt;querydsl-core&lt;/code&gt; 开始看起，关注 &lt;code&gt;DSL expression types&lt;/code&gt;。&lt;code&gt;com.querydsl.core.types.dsl&lt;/code&gt; 包含了Querydsl核心类型的定义和实现。Querydsl是一个用于构建类型安全的SQL查询的框架,这些类型定义了Querydsl查询中使用的各种表达式和操作的接口和实现。&lt;/p&gt;
&lt;p&gt;一些主要的类型包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Expression: 定义了通用的类型化表达式接口。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Constant: 表示常量表达式。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Operation: 表示常见的操作和函数调用。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Path: 表示变量、属性和集合成员访问。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;FactoryExpression: 用于基于行的结果处理。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这些接口和类为Querydsl提供了构建查询的基础抽象和实现。通过这些类型,Querydsl能够以类型安全的方式构造复杂的查询,并将其翻译为不同的查询语言(如SQL、MongoDB查询等)。&lt;/p&gt;
&lt;p&gt;总的来说,这个目录定义了Querydsl查询构造的核心模型,是整个Querydsl框架的基础。&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;ToStringVisitor.java&lt;/code&gt; 代码片段&lt;/h3&gt;
&lt;p&gt;对于 &lt;code&gt;FactoryExpression&lt;/code&gt; 类型,构造一个新对象的字符串表示,包括类名和参数列表。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Override
public String visit(FactoryExpression&amp;lt;?&amp;gt; e， Templates templates) {
  final StringBuilder builder = new StringBuilder();
  builder.append(&quot;new &quot;).append(e.getType().getSimpleName()).append(&quot;(&quot;);
  boolean first = true;
  for (Expression&amp;lt;?&amp;gt; arg : e.getArgs()) {
    if (!first) {
      builder.append(&quot;, &quot;);
    }
    builder.append(arg.accept(this, templates));
    first = false;
  }
  builder.append(&quot;)&quot;);
  return builder.toString();
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;对于 &lt;code&gt;Operation&lt;/code&gt; 类型,根据操作符查找对应的模板,并按模板的元素顺序拼接字符串,处理操作数的优先级。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;@Override
public String visit(Operation&amp;lt;?&amp;gt; o, Templates templates) {
  final Template template = templates.getTemplate(o.getOperator());
  if (template != null) {
    final int precedence = templates.getPrecedence(o.getOperator());
    final StringBuilder builder = new StringBuilder();
    for (Template.Element element : template.getElements()) {
      final Object rv = element.convert(o.getArgs());
      if (rv instanceof Expression) {
        if (precedence &amp;gt; -1 &amp;amp;&amp;amp; rv instanceof Operation) {
          if (precedence &amp;lt; templates.getPrecedence(((Operation&amp;lt;?&amp;gt;) rv).getOperator())) {
            builder.append(&quot;(&quot;);
            builder.append(((Expression&amp;lt;?&amp;gt;) rv).accept(this, templates));
            builder.append(&quot;)&quot;);
            continue;
          }
        }
        builder.append(((Expression&amp;lt;?&amp;gt;) rv).accept(this, templates));
      } else {
        builder.append(rv.toString());
      }
    }
    return builder.toString();
  } else {
    return &quot;unknown operation with operator &quot; + o.getOperator().name() + &quot; and args &quot; + o.getArgs();
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Constant&lt;/h3&gt;
&lt;p&gt;Constant接口代表一个通用的常量表达式。它继承自 Expression 接口,并定义了一个 getConstant() 方法来获取包装的常量值。&lt;/p&gt;
&lt;p&gt;与之相关的主要类有:&lt;/p&gt;
&lt;p&gt;&lt;code&gt;ConstantImpl&lt;/code&gt;&lt;br /&gt;
这是 Constant 接口的实现类,它包装了实际的常量值。在 ConstantImpl 中,有一个泛型字段 constant 用于存储常量值。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;Expressions&lt;/code&gt;&lt;br /&gt;
这是一个工具类,提供了创建常量表达式的静态方法 constant(T value)。它内部调用了 ConstantImpl.create(value) 来构造常量表达式。&lt;/p&gt;
&lt;p&gt;一些测试用的常量类&lt;br /&gt;
在测试代码中,有一些继承自 &lt;code&gt;ConstantImpl&lt;/code&gt; 的常量类,如 &lt;code&gt;TimeConstant&lt;/code&gt;、&lt;code&gt;DateConstant&lt;/code&gt;、&lt;code&gt;StringConstant&lt;/code&gt;、&lt;code&gt;NumberConstant&lt;/code&gt; 等,用于测试不同类型的常量表达式。&lt;/p&gt;
&lt;p&gt;总的来说,&lt;code&gt;Constant&lt;/code&gt; 接口定义了常量表达式的契约,&lt;code&gt;ConstantImpl&lt;/code&gt; 是其实现,而 &lt;code&gt;Expressions&lt;/code&gt; 工具类提供了创建常量表达式的便捷方法。在查询DSL中,常量表达式可以用于构建查询条件、投影等。&lt;/p&gt;
&lt;h3&gt;Path&lt;/h3&gt;
&lt;p&gt;Path接口代表一个路径表达式。路径表达式指的是对变量、属性和集合成员的访问。它继承自 Expression 接口。&lt;/p&gt;
&lt;p&gt;Path 接口定义了以下几个主要方法:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;getMetadata()：获取该路径的元数据。&lt;/li&gt;
&lt;li&gt;getRoot()：获取该路径的根路径。&lt;/li&gt;
&lt;li&gt;getAnnotatedElement()：获取与该路径相关的注解元素。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;与 Path 接口相关的主要类有:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;PathMetadata：封装了路径的元数据信息,如路径类型、父路径等。&lt;/li&gt;
&lt;li&gt;PathImpl：Path 接口的默认实现类。&lt;/li&gt;
&lt;li&gt;一些具体的路径类,如 SimplePath、BeanPath、CollectionPath、MapPath 等,分别代表不同类型的路径。&lt;br /&gt;
这些具体的路径类通常作为查询的起点,例如:&lt;pre&gt;&lt;code&gt;QEmployee employee = QEmployee.employee;
employee.firstName // 代表 employee 对象的 firstName 属性路径
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在查询DSL中,路径表达式用于构建查询条件、投影等。通过路径表达式,可以方便地访问对象的属性、集合元素等。Path 接口定义了路径表达式的基本契约,而具体的路径类型由不同的实现类来表示。&lt;/p&gt;
</content:encoded><author>Armyja</author></item><item><title>Cody介绍</title><link>https://blog.armyja-online.uk/posts/cody-introduction/</link><guid isPermaLink="true">https://blog.armyja-online.uk/posts/cody-introduction/</guid><description>Cody 是一个 AI 编码助手，负责编写、修复和维护您的代码。它使用 AI 和对代码库的深刻理解来收集上下文，帮助您更快地编写和理解代码。</description><pubDate>Thu, 04 Apr 2024 13:12:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://sourcegraph.com/docs/cody&quot;&gt;Cody&lt;/a&gt; 是一个 AI 编码助手，负责编写、修复和维护您的代码。它使用 AI 和对代码库的深刻理解来收集上下文，帮助您更快地编写和理解代码。&lt;/p&gt;
&lt;p&gt;它是 Sourcegraph 旗下的产品。&lt;a href=&quot;https://sourcegraph.com&quot;&gt;Sourcegraph&lt;/a&gt; 是一个代码智能平台，可以深入理解您的代码，无论代码有多大或托管在何处，都能为现代开发人员体验提供支持。&lt;br /&gt;
1、AI 代码助手：使用 Cody 更快地读取、写入和理解整个代码库&lt;br /&gt;
2、代码搜索：搜索所有分支和所有代码主机的所有存储库&lt;br /&gt;
3、代码智能：导航代码、查找引用、查看代码所有者、跟踪历史记录等&lt;br /&gt;
4、修复和重构：跨存储库同时推出和跟踪大规模更改和迁移&lt;/p&gt;
&lt;p&gt;我使用 Cody 的原因，是以前习惯在 Sourcegraph 看 Github 网站的源码，浏览比较方便。并且每月会员 Cody 比 Copilot 便宜一点。&lt;br /&gt;
在 &lt;code&gt;VSCode&lt;/code&gt; 安装 &lt;code&gt;Cody AI&lt;/code&gt; 后，推荐两个配置：&lt;br /&gt;
1、自定义输出的语言&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
    &quot;cody.chat.preInstruction&quot;: &quot;Answer all my questions in Chinese.&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2、配置用户级别的自定义指令。在 &lt;code&gt;~/.vscode/cody.json&lt;/code&gt; 设置&lt;a href=&quot;https://sourcegraph.com/docs/cody/capabilities/commands#custom-commands&quot;&gt;自定义指令&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;{
  &quot;commit-message&quot;: {
    &quot;description&quot;: &quot;Commit message for current changes&quot;,
    &quot;prompt&quot;: &quot;Suggest an informative commit message by summarizing code changes from the shared command output. The commit message should follow the conventional commit format and provide meaningful context for future readers.&quot;,
    &quot;context&quot;: {
      &quot;selection&quot;: false,
      &quot;command&quot;: &quot;git diff --cached&quot;
    }
  },
  &quot;current-dir&quot;: {
    &quot;description&quot;: &quot;Explain current directory&quot;,
    &quot;prompt&quot;: &quot;At a high level, explain what this directory is used for.&quot;,
    &quot;context&quot;: {
      &quot;currentDir&quot;: true,
      &quot;selection&quot;: false
    }
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;做了如上配置后，可以在 &lt;code&gt;VSCode&lt;/code&gt; 使用预置命令用中文解释代码、用自定义命令解释当前文件夹的代码、生成提交说明，体验非常好。&lt;/p&gt;
</content:encoded><author>Armyja</author></item><item><title>2024 第一篇博客</title><link>https://blog.armyja-online.uk/posts/2024-first-blog/</link><guid isPermaLink="true">https://blog.armyja-online.uk/posts/2024-first-blog/</guid><pubDate>Sun, 31 Mar 2024 15:17:00 GMT</pubDate><content:encoded>&lt;h2&gt;加油&lt;/h2&gt;
&lt;p&gt;你好棒&lt;/p&gt;
&lt;p&gt;来听音乐吧
&amp;lt;meting-js id=&quot;2118754864&quot; type=&quot;song&quot; server=&quot;netease&quot; fixed=&quot;false&quot; mini=&quot;false&quot; autoplay=&quot;false&quot; theme=&quot;#255579&quot;&amp;gt;&amp;lt;/meting-js&amp;gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://bucket.armyja-online.uk/blog/1711948205956.jpg&quot; alt=&quot;GMA全球音乐奖获奖&quot; /&gt;&lt;/p&gt;
</content:encoded><author>Armyja</author></item><item><title>GAMES104 笔记</title><link>https://blog.armyja-online.uk/posts/games104-note/</link><guid isPermaLink="true">https://blog.armyja-online.uk/posts/games104-note/</guid><description>本课程将介绍现代游戏引擎所涉及的系统架构，技术点，引擎系统相关的知识。 通过该课程，你能够对游戏引擎建立起一个全面且完整的了解。 如果你动手能力足够强，你将能够跟随课程，从0到1搭建起一个完整的迷你游戏引擎。如本课程适合相关专业领域的学生、研究者，以及所有对游戏引擎设计和开发感兴趣的人。</description><pubDate>Mon, 30 May 2022 07:23:59 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;meting-js id=&quot;33367012&quot; type=&quot;song&quot; server=&quot;netease&quot; fixed=&quot;false&quot; mini=&quot;false&quot; autoplay=&quot;false&quot; theme=&quot;#255579&quot;&amp;gt;&amp;lt;/meting-js&amp;gt;&lt;/p&gt;
&lt;h2&gt;GAMES104 课程简介&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Pilot Engine&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;本课程将介绍现代游戏引擎所涉及的系统架构，技术点，引擎系统相关的知识。 通过该课程，你能够对游戏引擎建立起一个全面且完整的了解。 如果你动手能力足够强，你将能够跟随课程，从 0 到 1 搭建起一个完整的迷你游戏引擎。如本课程适合相关专业领域的学生、研究者，以及所有对游戏引擎设计和开发感兴趣的人。&lt;/p&gt;
&lt;p&gt;课程网址：&lt;a href=&quot;https://games104.boomingtech.com/&quot;&gt;https://games104.boomingtech.com/&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;作业&lt;/h2&gt;
&lt;h3&gt;PA01:Build and Run Pilot Engine&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://cdn.boomingtech.com/games104_static/upload/GAMES104_PA01.pdf&quot;&gt;作业说明 PDF&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;作业说明：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Build and run Pilot ✔️&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;笔者安装 Visual Studio 2022，安装选项附带了 CMake，所以为了在命令行使用 CMake，添加用户环境变量：&lt;code&gt;X:\Program Files\Microsoft Visual Studio\2022\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Execute the &lt;strong&gt;build_windows.bat&lt;/strong&gt;, and then open &lt;strong&gt;Pilot.sln&lt;/strong&gt; with Visual Studio&lt;/p&gt;
&lt;p&gt;错误提示：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;fatal: unsafe repository (&apos;D:/project/Pilot&apos; is owned by someone else)
To add an exception for this directory, call:

    git config --global --add safe.directory D:/project/Pilot
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个问题似乎与 &lt;a href=&quot;https://github.blog/2022-04-12-git-security-vulnerability-announced/&quot;&gt;https://github.blog/2022-04-12-git-security-vulnerability-announced/&lt;/a&gt; 相关。暂时不理会。&lt;/p&gt;
&lt;h3&gt;PA02:Rendering&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://cdn.boomingtech.com/games104_static/upload/PA02%EF%BC%9ARendering%20.pdf&quot;&gt;作业说明 PDF&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;作业说明：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;在 Pilot 小引擎代码中找到
&lt;code&gt;pilot/engine/shader/glsl/color_grading.frag&lt;/code&gt;，补充此 &lt;code&gt;shader&lt;/code&gt; 代码中的
&lt;code&gt;main&lt;/code&gt; 函数，以实现 &lt;code&gt;ColorGrading&lt;/code&gt; 功能。若代码编译成功且实现方法正确，则可
以看到进行 &lt;code&gt;ColorGrading&lt;/code&gt; 渲染之后的结果。 ✔️&lt;/li&gt;
&lt;li&gt;使用自定义的 &lt;code&gt;LUT&lt;/code&gt; 图，并修改相应代码，实现具有个性的 &lt;code&gt;ColorGrading&lt;/code&gt; 的
效果。 ✔️&lt;/li&gt;
&lt;li&gt;（提高项，可选）添加一个新的 &lt;code&gt;Pass&lt;/code&gt; 实现某个自己感兴趣的后处理效果 ❌
&lt;ul&gt;
&lt;li&gt;调整 PMainCameraPass::setupRenderPass 添加一个新的 Vulkan Subpass。&lt;/li&gt;
&lt;li&gt;调整 PVulkanManager::initializeDescriptorPool 增加相关 Descriptor 的数量。&lt;em&gt;【这里用了 Magic Number，不清楚如何统计，可能和 Vulkan 相关】&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;LUT 贴图路径：&lt;code&gt;engine\asset\texture\lut&lt;/code&gt;，默认配置为&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&quot;color_grading_map&quot;: &quot;asset/texture/lut/color_grading_lut_01.png&quot;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;配置文件在 &lt;code&gt;engine\asset\global\rendering.global.json&lt;/code&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/mortenblaa/lut-generator/&quot;&gt;LUT Table Texture Generator&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Python script for generating neutral LUT tables of different sizes. It supports both Unreal Engine style LUT (top down) and the Unity style LUT (bottom up).&lt;/p&gt;
&lt;p&gt;Based on a GitHub gist by Koki Ibukuro.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Samples&lt;/strong&gt;&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;th&gt;Unreal Engine&lt;/th&gt;
&lt;th&gt;Unity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;256x16&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;https://github.com/mortenblaa/lut-generator/raw/master/samples/unreal/lut_strip_16_256x16.png&quot; alt=&quot;strip 256x16&quot; /&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;https://github.com/mortenblaa/lut-generator/raw/master/samples/unity/lut_strip_16_256x16.png&quot; alt=&quot;lut_strip_16_256x16&quot; /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;1024x32&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;https://github.com/mortenblaa/lut-generator/raw/master/samples/unreal/lut_strip_32_1024x32.png&quot; alt=&quot;strip 1024x32&quot; /&gt;&lt;/td&gt;
&lt;td&gt;&lt;img src=&quot;https://github.com/mortenblaa/lut-generator/raw/master/samples/unity/lut_strip_32_1024x32.png&quot; alt=&quot;strip 1024x32&quot; /&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Pilot 使用 Unreal Engine 的格式。&lt;/p&gt;
&lt;p&gt;修改 &lt;code&gt;engine\shader\glsl\color_grading.frag&lt;/code&gt;，参考 &lt;a href=&quot;https://www.zhihu.com/people/wang-jun-yang-5-82&quot;&gt;V1tozzZ&lt;/a&gt; 的实现：&lt;a href=&quot;https://zhuanlan.zhihu.com/p/508156645&quot;&gt;GAMES104 作业 2 基础部分&lt;/a&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#version 310 es

#extension GL_GOOGLE_include_directive : enable

#include &quot;constants.h&quot;

layout(input_attachment_index = 0, set = 0, binding = 0) uniform highp subpassInput in_color;

layout(set = 0, binding = 1) uniform sampler2D color_grading_lut_texture_sampler;

layout(location = 0) out highp vec4 out_color;

void main()
{
    // 这里的 LUT 贴图为单行排列
    highp ivec2 lut_tex_size = textureSize(color_grading_lut_texture_sampler, 0);
    // 纵向值，同时表示格子的数量，一般取值 16，32，64
    highp float _COLORS      = float(lut_tex_size.y);
    // 横向值，为纵向值的平方
    highp float xsize        = float(lut_tex_size.x);

    // rgba 的取值范围: 0 ~ 1.0
    highp vec4 color       = subpassLoad(in_color).rgba;

    // 先得到 rgb 在 lut 颜色数量上的映射（可以理解为在单个格子里的偏移量）
    highp float bluemapped          = (_COLORS-1.0)*color.b;
    highp float redmapped           = (_COLORS-1.0)*color.r;
    highp float greenmapped         = (_COLORS-1.0)*color.g;

    // 用蓝色确定从左至右第几个颜色格子，加上红色确定格子上x坐标 取得u坐标
    // 映射后的蓝色可能是小数 那么就取小数前后两个格子
    highp float rbmapped1 = redmapped + floor(bluemapped)*_COLORS;
    highp float rbmapped2 = redmapped + ceil(bluemapped)*_COLORS;
    highp float u1 = rbmapped1/xsize;
    highp float u2 = rbmapped2/xsize;

    // 用绿色取v坐标
    highp float v = greenmapped/_COLORS;
    highp vec2 uv1 = vec2(u1,v);
    highp vec2 uv2 = vec2(u2,v);
    highp vec3 mappedcolor1  =   texture(color_grading_lut_texture_sampler, uv1).xyz;
    highp vec3 mappedcolor2  =   texture(color_grading_lut_texture_sampler, uv2).xyz;

    //混合两个格子的颜色 fract(bluemapped)表示用小数部分决定两个格子占比权重
    highp vec3 mixedcolor   =   mix(mappedcolor1,mappedcolor2,fract(bluemapped));

    out_color = vec4(mixedcolor,color.a);

}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Pilot 引擎技术点&lt;/h2&gt;
&lt;h3&gt;反射&lt;/h3&gt;
&lt;p&gt;Pilot 引擎使用静态反射框架，用户通过 &lt;strong&gt;定义数据结构&lt;/strong&gt; 与提供对应的 &lt;strong&gt;配置文件&lt;/strong&gt;，框架利用元编程技术生成读取接口。&lt;/p&gt;
&lt;p&gt;可以在 &lt;code&gt;engine\source\_generated\serializer\all_serializer.ipp&lt;/code&gt; 看到序列化/反序列化代码，由 &lt;code&gt;engine\source\precompile\precompile.cmake&lt;/code&gt; 定义的预编译流程生成。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;#include &quot;D:/project/Pilot/engine/source/_generated/serializer/global_rendering.serializer.gen.h&quot;
namespace Pilot{
    // ...
    template&amp;lt;&amp;gt;
    PJson PSerializer::write(const GlobalRenderingRes&amp;amp; instance){
        PJson::object  ret_context;
        ret_context.insert_or_assign(&quot;skybox_irradiance_map&quot;, PSerializer::write(instance.m_skybox_irradiance_map));
        ret_context.insert_or_assign(&quot;skybox_specular_map&quot;, PSerializer::write(instance.m_skybox_specular_map));
        ret_context.insert_or_assign(&quot;brdf_map&quot;, PSerializer::write(instance.m_brdf_map));
        ret_context.insert_or_assign(&quot;color_grading_map&quot;, PSerializer::write(instance.m_color_grading_map));
        ret_context.insert_or_assign(&quot;sky_color&quot;, PSerializer::write(instance.m_sky_color));
        ret_context.insert_or_assign(&quot;ambient_light&quot;, PSerializer::write(instance.m_ambient_light));
        ret_context.insert_or_assign(&quot;camera_config&quot;, PSerializer::write(instance.m_camera_config));
        ret_context.insert_or_assign(&quot;directional_light&quot;, PSerializer::write(instance.m_directional_light));
        return  PJson(ret_context);
    }
    template&amp;lt;&amp;gt;
    GlobalRenderingRes&amp;amp; PSerializer::read(const PJson&amp;amp; json_context, GlobalRenderingRes&amp;amp; instance){
        assert(json_context.is_object());
        if(!json_context[&quot;skybox_irradiance_map&quot;].is_null()){
        PSerializer::read(json_context[&quot;skybox_irradiance_map&quot;], instance.m_skybox_irradiance_map);
        }
        if(!json_context[&quot;skybox_specular_map&quot;].is_null()){
        PSerializer::read(json_context[&quot;skybox_specular_map&quot;], instance.m_skybox_specular_map);
        }
        if(!json_context[&quot;brdf_map&quot;].is_null()){
        PSerializer::read(json_context[&quot;brdf_map&quot;], instance.m_brdf_map);
        }
        if(!json_context[&quot;color_grading_map&quot;].is_null()){
        PSerializer::read(json_context[&quot;color_grading_map&quot;], instance.m_color_grading_map);
        }
        if(!json_context[&quot;sky_color&quot;].is_null()){
        PSerializer::read(json_context[&quot;sky_color&quot;], instance.m_sky_color);
        }
        if(!json_context[&quot;ambient_light&quot;].is_null()){
        PSerializer::read(json_context[&quot;ambient_light&quot;], instance.m_ambient_light);
        }
        if(!json_context[&quot;camera_config&quot;].is_null()){
        PSerializer::read(json_context[&quot;camera_config&quot;], instance.m_camera_config);
        }
        if(!json_context[&quot;directional_light&quot;].is_null()){
        PSerializer::read(json_context[&quot;directional_light&quot;], instance.m_directional_light);
        }
        return instance;
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;相关分析：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.zhihu.com/people/ban-tang-96-14&quot;&gt;鹏 wp&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://zhuanlan.zhihu.com/p/502729373&quot;&gt;C++反射-Pilot 引擎的反射实现&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.zhihu.com/people/netcan&quot;&gt;netcan&lt;/a&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://zhuanlan.zhihu.com/p/165993590&quot;&gt;如何优雅的实现 C++编译期静态反射
&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://zhuanlan.zhihu.com/p/388454455&quot;&gt;C++静态反射框架：ConfigLoader&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content:encoded><author>Armyja</author></item><item><title>Edge 浏览器复制粘贴 URL 显示网站标题</title><link>https://blog.armyja-online.uk/posts/edge-url-paste/</link><guid isPermaLink="true">https://blog.armyja-online.uk/posts/edge-url-paste/</guid><description>与预料的不同，当把 Edge 浏览器地址栏中的 https://collection.armyja.cn/v/front-end/ 粘贴到 Notion 时，显示的是超链接 【前端笔记 - Collection (armyja.cn)】。这是为什么呢？</description><pubDate>Wed, 27 Apr 2022 15:04:41 GMT</pubDate><content:encoded>&lt;p&gt;&amp;lt;meting-js id=&quot;1922188998&quot; type=&quot;song&quot; server=&quot;netease&quot; fixed=&quot;false&quot; mini=&quot;false&quot; autoplay=&quot;false&quot; theme=&quot;#255579&quot;&amp;gt;&amp;lt;/meting-js&amp;gt;&lt;/p&gt;
&lt;h2&gt;问题描述&lt;/h2&gt;
&lt;p&gt;与预料的不同，当把 Edge 浏览器地址栏中的 https://collection.armyja.cn/v/front-end/ 粘贴到 Notion
时，显示的是超链接 【前端笔记 - Collection (armyja.cn)】。这是为什么呢？&lt;/p&gt;
&lt;p&gt;把 https://collection.armyja.cn/v/front-end/ 粘贴到记事本，再粘贴回
Notion，发现只显示超链接 https://collection.armyja.cn/v/front-end/ ，符合预期。&lt;/p&gt;
&lt;h2&gt;分析过程&lt;/h2&gt;
&lt;p&gt;打开 Chrome Debugger，添加事件侦听器断点，勾选 paste，如下图所示。粘贴网址，进断点。由于 js
文件是混淆过的，挤在一行不好分析，于是点击下图左下角的【{}】按钮，展示为 format
后的代码内容。
&lt;img alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;首先进入到 injectGlobalHook.js，如下图所示。因为 _intercept 变量值为 false，所以函数没有做任何操作。所以这里不需要分析。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;接着跳到下一个断点监听，如下图所示。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;到这里就比较难推进了，因为每在函数内部调用一次函数就要手动定位函数位置并打断点。有没有更快的办法呢？注意到
clipboardData 有 3 个 type。参考 https://developer.mozilla.org/en-US/docs/Web/API/ClipboardEvent/clipboardData 、
https://developer.mozilla.org/en-US/docs/Web/API/DataTransfer/getData ，提到 clipboardData 的类型为 DataTransfer，有方法 getData(format)。
format 为 data types。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Example data types are &lt;code&gt;text/plain&lt;/code&gt; and &lt;code&gt;text/uri-list&lt;/code&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;于是在控制台尝试拿到粘贴内容。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&amp;gt; i[0].clipboardData.getData(&apos;text/html&apos;)
&amp;lt; &apos;&amp;lt;html&amp;gt;\r\n&amp;lt;body&amp;gt;\r\n\x3C!--StartFragment--&amp;gt;&amp;lt;a href=&quot;https://collection.armyja.cn/v/front-end/&quot;&amp;gt;前端笔记 - Collection (armyja.cn)&amp;lt;/a&amp;gt;\x3C!--EndFragment--&amp;gt;\r\n&amp;lt;/body&amp;gt;\r\n&amp;lt;/html&amp;gt;&apos;

&amp;gt; i[0].clipboardData.getData(&apos;text/link-preview&apos;)
&amp;lt; &apos;&apos;

&amp;gt; i[0].clipboardData.getData(&apos;text/plain&apos;)
&amp;lt; &apos;&apos;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;顺藤摸瓜，既然粘贴的内容类型是 &lt;code&gt;text/html&lt;/code&gt;，那么 js 一定有针对这一类型做特殊处理。在这个文件搜索
&lt;code&gt;text/html&lt;/code&gt;，打上断点，果然程序停在这里，距离上个分析点直接越过 10 余个堆栈元素，如下图所示。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;回溯到中间的堆栈可以看到返回有语义的 json 结构，如下图所示。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;总结&lt;/h2&gt;
&lt;p&gt;当把 Edge 浏览器地址栏中的网址粘贴到 Notion 时，js 存储的粘贴内容由浏览器决定， data type 为 &lt;code&gt;text/html&lt;/code&gt;。&lt;br /&gt;
从记事本拷贝链接，js 存储的粘贴内容 data type 为 &lt;code&gt;text/plain&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;在 Edge 浏览器的 &lt;strong&gt;设置 - 共享、复制和粘贴&lt;/strong&gt; 里说明了，默认 Ctrl-V 是粘贴链接，
Ctrl-Shift-V 为粘贴纯文本，详细说明参见 https://go.microsoft.com/fwlink/?linkid=2136809 。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&quot;&quot; /&gt;&lt;/p&gt;
</content:encoded><author>Armyja</author></item><item><title>Undertale 传说之下</title><link>https://blog.armyja-online.uk/posts/undertale/</link><guid isPermaLink="true">https://blog.armyja-online.uk/posts/undertale/</guid><description>第一次了解 Undertale，是在网易云音乐听到其 OST「Stronger Than You」。这是一款打破常规的另类 RPG，且乐评率在 Steam 排名第一，是 2015 Steam 最佳游戏之一。好奇心促使我对它一探究竟。</description><pubDate>Wed, 18 Jan 2017 15:16:22 GMT</pubDate><content:encoded>&lt;p&gt;第一次了解 Undertale，是在网易云音乐听到其 OST「Stronger Than You」。这是一款打破常规的另类 RPG，且乐评率在 Steam 排名第一，是 2015 Steam 最佳游戏之一。好奇心促使我对它一探究竟。&lt;/p&gt;
&lt;p&gt;「Stronger Than You」&lt;/p&gt;
&lt;p&gt;第一遍没看攻略，走了中立路线。一路上杀了所有主要人物，除了羊爸。我饶恕了他，最后等到的却是 Flowey 大魔王的奸笑。Flowey 吸收了羊爸先前占有的 6 个人类灵魂，变身绿巨怪发射全屏弹幕，这里我被折磨 n 遍才通关，想屎的心都有了。&lt;/p&gt;
&lt;p&gt;第二遍开始走善良路线，幻想着自己可以绝对完美地走完一切，然后迎来 happy ending。然而路途上，npc 居然记得你曾经杀过它，纳闷为什么你看它的眼神像在看一个灵魂。它会戳穿你没有穿 Old Tutu 的谎言。总之，你的言行不一，都会被敏锐的 npc 察觉到，可谓本游戏细思恐极之处。一般而言，玩家觉得自己是游戏的主宰，而在这里，你的人性仿佛被游戏看穿。&lt;/p&gt;
&lt;p&gt;另外，尽管最后没有变态绿巨怪 Flowey 出现，但是前面小 Boss 们的脱战方式的难度也不小。因为你不能杀死他们，每个 Boss 的脱战方式需要自己摸索好久……也只有唯有 stay determined（无限复活），不断提升自己的躲避技巧，才能战胜他们。&lt;/p&gt;
&lt;p&gt;除了中立路线与和平路线，还存在第三种屠杀路线：你必须杀光所有随机遇到的小怪，神挡杀神，佛挡杀佛。若如此作，所有普民包括商店老板会逃跑，你能毫不费力获得回复道具及强力武器。最后，你终于走进「Stronger Than You」的情节：Sans 了解你厌倦了一次次地走和平路线，企图杀戮所有人的决心，决定誓死也要阻止你。虽然屠杀能使你获得大量 LOVE，能毫不费力的升满 19 级并获得最强武器，但面对攻击力和防御力均为 1 的 Sans，你只能感受到绝望。相比之前，你失去了受伤后的无敌时间，若稍显失误，你就挂在他的连续攻击之下，接着 stay determined，重新开始战斗。而他每次都能 Miss 你的攻击，令人抓狂。个人觉得这样过于残忍，着实不敢走这条路。&lt;/p&gt;
&lt;p&gt;开全屏玩这款游戏，听 BGM ，场景代入感十分强烈。每个小怪都有自己的性格、故事和其对应风格的曲子，讨人欢喜。尤其是和羊妈重逢的时候再次响起和羊妈在一起时的 BGM，有种游子归家的感动。若是重玩这款游戏，有趣的 BGM 依然值得回味。&lt;/p&gt;
&lt;p&gt;羊妈家 BGM&lt;/p&gt;
</content:encoded><author>Armyja</author></item></channel></rss>