乐于分享
好东西不私藏

UE6 新编程模型源码级全拆解:Epic 同时换掉你的语言和对象模型,到底想干什么?

UE6 新编程模型源码级全拆解:Epic 同时换掉你的语言和对象模型,到底想干什么?

2026 年 6 月 17 日,Epic 引擎开发负责人 Marcus Wassmer 发了一篇博客,确认 UE6 将在 Q4 2027 进入 Early Access。里面有一句话被大家反复引用:「UE6 将逐步废弃 Actor 和 Blueprint 体系,转向 Scene Graph 实体和 Entity Component System。」

但这句话只说了故事的一半。

另一半藏在一行更不起眼的文字里:UE6 把 Verse 从 Fortnite 创作工具(UEFN)的脚本语言,升级为整个引擎的一级编程语言

两件事加在一起,意思就完全不同了——Epic 不是在做一次架构升级,是在同时换掉整个编程语言和你的对象模型。C++ 退居引擎底层,Actor/Component 体系逐步废弃,取而代之的是一套从语言到运行时的全新技术栈。

这套技术栈在 UE6 公开仓库里已经可以编译运行,我花了几天终于把源码整理清楚,最后用例子说明 Verse 和 Scene Graph 是怎么咬合。

说明:本文所引用的行数、文件路径、opcode 名称等均来自 UE6 公开仓库(ue6-main 分支)当前快照。Epic 仍在快速迭代,Early Access 之前这些数字与命名都可能变动。文中给出的具体数字只用于说明「这套系统的体量与设计意图」。

Verse 编译器:约 5.4 万行 C++ 在做什么

Verse 编译器的代码在 Engine/Source/Runtime/VerseCompiler/。管线分四步。

Parser 是一个手写的 PEG 解析器,入口在 VerseGrammar.h。Epic 没用 Bison/Yacc,而是用 C++ 模板实现了一套零依赖的语法组合子框架:

// VerseGrammar.h - 每个语法规则返回 Result<T>,失败就短路
#define ULANG_GRAMMAR_RUN(e)               \
    {                                      \
        auto GrammarTemp = (e);            \
        if (!GrammarTemp)                  \
            return GrammarTemp.GetError(); \
    }

严格地说,PEG(Parsing Expression Grammar)是一种形式文法,parser combinator 是一种实现手法。Epic 这里的做法是「用 C++ 模板写的、语义上等价于 PEG 的递归下降组合子」。这套组合子让 ParserPass.cpp 只用了约 3000 行就处理了完整的 Verse 语法——包括 race{}spawn{}branch{} 等并发原语的语法。

Desugarer(约 2080 行)把语法糖展开为核心 AST。for 循环被展开为迭代器协议调用,if 表达式被展开为 decides 效应上的分支。同时,Desugarer 运行 Tarjan 强连通分量算法处理包依赖的拓扑排序——Verse 的模块系统天然支持循环依赖检测,编译器在编译前就知道哪些包形成了环。

Tarjan SCC 在这里做的不只是「检测环」,更关键的是「分组」:把互相循环依赖的包归到同一个强连通分量里,让编译器对「环内」整体编译、对「环间」按拓扑序编译。这正是支持「合法的循环依赖」(而不是一概报错)的算法基础——这一点和 Rust 的 crate 之间禁止循环依赖形成了鲜明对比。

SemanticAnalyzer 是整个编译器最大的单文件——约 2.1 万行。它负责类型检查、效应推断、并发语义验证。效应系统的核心逻辑就在这里:

// SemanticAnalyzer.cpp - spawn 表达式允许 suspends 效应
if (ExprCtx.ResultContext == ResultIsSpawned)
{
    AllowedEffects |= EEffect::suspends;
}

IRGenerator(约 2992 行)把类型检查后的 AST 转换成 Verse VM 字节码。生成字节码所用的 opcode 定义,由 VerseVMBytecodeGenerator.cs(C# 写的 UBT 工具)产出——它在编译期自动生成 C++ 的 opcode 结构体、分发器、内联实现。

为什么用代码生成器?opcode 的「枚举值、操作数布局、解释器分发分支、序列化逻辑」这四份代码必须严格一一对应,手写极易因为漏改某一处而产生隐蔽 bug。用单一的 opcode 描述生成全部四份,是把「一致性」从人的纪律变成编译期保证——这和 Verse 效应系统「把约束从约定变成编译期检查」是同一种工程哲学。

Effects System:Verse 跟所有主流语言的分界线

翻开 Effects.h,编译器内部用一组枚举定义了 Verse 的效应边界。这里需要区分两个层面:面向用户的效应说明符(specifier)编译器内部的效应枚举——它们不是同一份清单。

面向 Verse 程序员、写在函数签名里的说明符主要是这几个:

说明符 含义
<computes> 纯计算,无副作用,保证终止
<converges> 保证终止(可能读不可变状态)
<varies> 相同输入未必产生相同输出
<transacts> 读写可变状态,且这些写入可被事务回滚(函数默认效应)
<decides> 函数可能失败(failure context,类似 Result<T,E> 的「失败即回滚」)
<suspends> 函数可能暂停、等待异步结果
<no_rollback> 函数的副作用不可回滚(例如真正的 I/O)

而编译器内部的细粒度效应枚举更接近这一组:

// Effects.h(编译器内部枚举,非用户书写的说明符)
#define VERSE_ENUM_EFFECTS(v) \
    v(suspends)     \  // 可能暂停等待

    v(decides)      \  // 可能失败
    v(diverges)     \  // 可能不终止
    v(reads)        \  // 读取可变状态
    v(writes)       \  // 写入可变状态
    v(allocates)    \  // 分配内存
    v(dictates)     \  // 定义类型级约束
    v(no_rollback)  \  // 不可回滚

用户写的 <transacts> 在内部会被拆解成 reads | writes | allocates | diverges | dictates 这类细粒度效应的组合——用户说明符是「打包」的,编译器内部是「拆开」的。这是初学者最容易混淆的地方。

效应可以组合成效应集(EffectSet),用位掩码实现:

// Effects.h - 预定义的效应组合
constexpr SEffectSet Transacts =
    EEffect::diverges | EEffect::reads |
    EEffect::writes | EEffect::allocates | EEffect::dictates;

constexpr SEffectSet FunctionDefault = Transacts | EEffect::no_rollback;

这组词不是注释,是编译器强制检查的约束。一个没有声明 suspends 的函数不能调用会暂停的函数;一个没有声明 decides 的函数不能使用可能失败的操作。且效应会沿调用栈向上传播——你无法把一个 suspends 函数包一层「干净」的外壳来隐藏它的效应,调用者的签名必须如实反映被调用者的效应。所有检查发生在编译期,零运行时开销。

Verse 的默认策略是「默认允许(可回滚的)副作用,但默认不允许暂停和失败」。跟 Haskell 的纯函数默认相反,跟 Rust 的 Result<T,E> 显式错误处理也不同。这是一种务实的折中:游戏逻辑天然充满副作用(读写 Transform、播放音效、生成粒子),强制纯函数会让游戏程序员疯掉;但「暂停」和「失败」需要显式标注,因为它们改变控制流。

为什么效应系统对游戏引擎特别重要? 因为游戏代码最大的可扩展性瓶颈往往不是单点算法,而是并行化;而并行化最大的障碍不是硬件,是程序员(和编译器)不知道两个函数能不能同时跑。效应系统让编译器替你回答这个问题——reads/writes 标注让编译器在编译期就能判断两个函数是否存在数据竞争,从而决定能否并行,不需要程序员手动加锁。

Verse VM:基于寄存器的字节码解释器

Verse 运行时在 CoreUObject/Private/VerseVM/,核心是 VVMInterpreter.cpp(约 6541 行)。

值表示:64 位 NaN-boxing。 所有 Verse 值都用 64 位表示,借助 IEEE 754 双精度浮点的 NaN 编码空间来区分类型:

// VVMValue.h - 值标签
static constexpr uint64 Int32Tag          = 0xffff'0000'0000'0000ull;
static constexpr uint64 PlaceholderTag    = 0x1ull;  // 惰性求值占位符
static constexpr uint64 UObjectTag        = 0x3ull;  // C++ UObject 指针
static constexpr uint64 CharTag           = 0x4ull;
static constexpr uint64 TransparentRefTag = 0x6ull;

NaN-boxing 的原理一句话:双精度浮点里有一大片「永远不会被正常浮点运算产生」的 NaN 位模式,可以拿来藏「这不是浮点数,而是一个带标签的指针/整数」。好处是浮点数本身零成本(直接就是浮点),代价是非浮点值要做位运算解包。这一思路和 Lua 5.x、JavaScriptCore 同源,但 Verse 额外加了 PlaceholderTransparentRef 两个标签来支撑并发语义。

Placeholder 是惰性求值的占位符——一个 Task 读另一个 Task 尚未产生的值时,读到的是 Placeholder,读操作挂起,等值就绪后被唤醒。这是 Verse 把「异步等待」做成语言级原语、而非回调地狱的关键。

帧与寄存器。 Verse VM 是寄存器式而非栈式。每个函数调用创建一个 VFrame,包含固定数量的寄存器:

// VVMFrame.h - 寄存器约定
// Register 0 = Self
// Register 1 = Scope(泛型/闭包捕获)
// Register 2+ = 参数

这个约定是硬编码的——FRegisterIndex::SELF = 0FRegisterIndex::SCOPE = 1FRegisterIndex::PARAMETER_START = 2

为什么选寄存器式而非栈式?栈式 VM(如 JVM、CPython 的字节码)指令更紧凑、生成更简单;寄存器式 VM(如 Lua 5.x、Dalvik)指令条数更少、更利于在解释器层做窥孔优化与减少冗余 load/store,通常解释执行更快。Epic 选寄存器式,是把「解释执行的吞吐」放在了「字节码体积」之前——对每帧都要跑大量逻辑的游戏运行时来说,这个权衡是合理的。

Suspend/Resume。 当字节码遇到需要等待的操作(比如读一个尚未就绪的 Placeholder),VM 创建一个 VBytecodeSuspension 对象,保存当前 PC、帧、效应令牌,然后挂起。当被等待的值就绪后,挂起点被重新调度执行。这就是 Verse 的 suspends 效应在运行时的实现——编译器生成的字节码中可能包含会挂起的 opcode,VM 在遇到这些 opcode 时自动保存和恢复执行上下文。

并发模型:五种原语,一个协作式调度器

Verse 的并发不是抢占式线程——它是基于 Task 的协作式并发。五种原语在 Expression.h 中定义:

原语 语义 类比
sync {A; B} 顺序执行 普通代码块
race {A; B} 并行执行,第一个完成的结果被采用,其余取消 Promise.race
rush {A; B} 并行执行,等全部完成后继续 Promise.all
branch {A; B} 并行执行,第一个完成后返回,其余继续后台运行 竞速+后台
spawn {A} 启动后立即继续,不等结果 fire-and-forget

每种原语还有迭代版本:race(Item:Container) { ... } 对容器中每个元素启动一个并发任务。

在 VM 层面,每个并发块创建一个 VTask:

// VVMTask.h
struct VTask : VValueObject
{
    bool bRunning{true};
    enum class EPhase : int8 {
        Active, CancelRequested, CancelStarted,
        CancelUnwind, Canceled
    };
    EPhase Phase{EPhase::Active};
    FOp* ResumePC{nullptr};            // 恢复执行的位置
    TWriteBarrier<VFrame> ResumeFrame; // 恢复时的帧(带 GC 写屏障)
};

TWriteBarrier<> 包裹 ResumeFrame 不是随便加的——它告诉 GC「这里存了一个堆对象引用,赋值时要记录到屏障」,这是并发 + 增量 GC 能正确工作的前提。

Task 之间通过 Placeholder 同步——这套机制让 Verse 的并发模型在协作式调度下实现了类似 Goroutine 的体验。需要说明的是:Goroutine 由 Go 运行时跨 OS 线程做 M:N 抢占式调度,而 Verse Task 是协作式的(在挂起点让出)。两者「写起来都很轻」,但调度模型本质不同。

事务与回滚。 Verse 的事务系统建立在 AutoRTFM(Automatic Rollback Transactions for Failure Memory)之上。当一个 decides 函数执行失败时,VM 通过 Trail(变更日志)回滚所有在事务内的写入。Trail 记录了每次赋值的旧值,回滚时逆向恢复。这个过程对 Verse 程序员完全透明——你只需要声明函数是 decides,编译器自动生成事务边界代码。

关于 AutoRTFM 的两点澄清:

  • 它的全称是 Automatic Rollback Transactions for Failure Memory(自动「为失败而回滚的事务」),不是 Runtime Transactional Memory。它的设计目标是「失败回滚」,不是用来做多线程并发控制。
  • 实现上,Epic 维护了一个 Clang 的分支,由编译器自动把 C++ 代码改写成「能精确登记 undo 操作」的形式,从而让 C++ 和 Verse 共享同一套事务语义。这也是为什么 no_rollback 这个效应必须存在——真正的 I/O(写文件、发网络包)是回滚不掉的,必须被显式隔离在事务之外。

Scene Graph:Actor 死后,谁来接管你的游戏世界

上面拆解了 Verse 的语言层。现在翻到 Engine/Plugins/EntityFramework/——约 12 万行 C++、638 个文件、6 个模块。这是 Verse 代码实际运行的「操作系统」。

Entity:空容器

打开 Entity.hverse::entity 继承自 UBaseEntity,核心成员只有两个数组:

// Entity.h - UBaseEntity 的核心数据
UPROPERTY()
TArray<TObjectPtr<UObject>> Components;     // Component 列表

UPROPERTY()
TArray<TObjectPtr<UObject>> OwnedEntities;  // 子 Entity 列表

就这两个数组。Entity 本身没有 Transform、没有 Tick、没有渲染逻辑。它只做两件事:持有 Component 列表和持有子 Entity 列表。这跟 Unity 的 GameObject(持有 Component 列表,且 Transform 是强制内建的)不同——在 UE6 里,连 Transform 都是一个可选的 Component。

这个区别为什么重要:在 Unity 里,哪怕一个纯逻辑的、不存在于 3D 空间中的对象,也被迫携带一个 Transform,这是历史包袱。UE6 把 Transform 降级为可选 Component,意味着「一个纯数据/纯逻辑节点」可以零空间开销地存在于场景图中。这种设计让 Entity 可以表示任何东西——一个光源、一段声音、一棵 AI 行为树、一个 UI 元素——而不需要继承不同的基类。Entity 是纯粹的「场景图节点」,所有行为由 Component 提供。

Component:六阶段生命周期

Component.h 定义了 Component 的完整生命周期,六个阶段,严格有序:

// Component.h - Component 生命周期
//  1. OnInitialized
//  2. OnAddedToScene
//  3. OnBeginSimulation
//  4. OnEndSimulation
//  5. OnRemovingFromScene
//  6. OnUninitializing

源码里用 EEntityNotificationState 枚举追踪每个 Entity 和 Component 当前处于哪个阶段——从 Created 到 TearedDown 共 20 个状态。如果你在 Initializing 阶段添加 Component,引擎会确保这个新 Component 也走完 Initialized → AddedToScene → BeginSimulation,跟宿主 Entity 同步到同一个状态。

在 UE5 里,你在 BeginPlay 里加一个 Component,它可能要等到下一帧才被 Tick,状态会「慢半拍」追上来。在 UE6 里,这种状态同步是引擎层保证的,新加入的 Component 会被「补齐」到与宿主一致的生命周期阶段。

Entity 树与事件传播

Entity 形成一棵树。每个 Entity 有 Parent 和 Children。这棵树决定了场景事件的传播方向:

// Entity.h - 场景事件传播
bool SendUp(TInterfaceInstance<verse::scene_event> SceneEvent);    // 冒泡
bool SendDown(TInterfaceInstance<verse::scene_event> SceneEvent);  // 广播

SendUp 沿 Parent 链向上冒泡,SendDown 沿 Children 链向下广播。这跟 Web 的 DOM 事件模型在「树形传播」这一点上高度相似——子 Entity 上的 OnDamage 事件可以冒泡到父 Entity,父 Entity 可以广播 OnPause 事件到所有子 Entity,不需要手写遍历代码。

一个提醒:DOM 事件有「捕获→目标→冒泡」三段式,还有 stopPropagation/preventDefault 等一整套机制。Scene Graph 的 SendUp/SendDown 是两个方向明确的 API,语义上更简单直接,不应理解为「完整复刻了 DOM 事件模型」。类比有助于建立直觉,但精确语义以源码为准。

执行引擎:Tick 死了,DAG 活了

UE5 的 AActor::Tick(float DeltaTime) 有一个致命问题:所有 Actor 的 Tick 顺序是隐式的。你靠 TickGroup 和 AddTickPrerequisiteActor 手动管理依赖,稍不注意就会出现「物理还没算完,动画就开始读位置」的竞态。

UE6 用 Execution Engine 彻底重写了这个模型。核心在 ExecutionPhase.h

// ExecutionPhase.h - 执行阶段是一个有向无环图
class FExecutionPhase final
{
    // 同步节点(无回调,纯依赖排序)
    FUpdateConnector RegisterSyncNode(FName Name, bool Conditional,
        const FUpdateDependencies& Dependencies)
;

    // 函数节点(每帧/按间隔调用)
    FUpdateConnector RegisterFunction(TExecuteFn Function,
        const FUpdateDependencies& Dependencies, float Interval = 0.0f)
;

    // 对象节点(支持多线程批处理)
    FUpdateConnector RegisterObject(UObject* Object,
        TUObjectExecuteFn Function,
        const FUpdateDependencies& Dependencies,
        float Interval = 0.0f, uint8 MaxThreadWidth = 1)
;
};

一个 FExecutionPhase 内部是一个有向无环图(DAG)。每个节点通过 RunAfter/RunBefore 声明依赖关系,引擎在运行时自动拓扑排序。UE6 预定义了 6 个 Phase:PrePhysics → StartPhysics → DuringPhysics → EndPhysics → PostPhysics → EndFrame。

跟 UE5 Tick 的本质区别:

维度 UE5 Tick UE6 Execution Phase
依赖管理 隐式(TickGroup + Prerequisite) 显式(RunAfter/RunBefore DAG)
并行化 手动(TaskGraph) 自动(Object 节点 MaxThreadWidth)
条件执行 手动 bool 判断 内置 Conditional Sync Node
动态注册 BeginPlay 里绑定 运行时 Register/Unregister

最关键的区别:依赖是显式的。 在 UE5 里,同组两个 Actor 的执行顺序不确定;在 UE6 里,你写 B.RunAfter(A),引擎保证 B 一定在 A 之后。这把「靠经验和 TickGroup 微调出来的顺序」变成了「编译/注册期就能验证的依赖图」——一旦出现环(A 依赖 B、B 又依赖 A),拓扑排序会立刻暴露问题,而不是在运行时随机崩。

SceneGraphAPI:操作 Entity 的唯一入口

UE6 源码里有一个明确的约定:不要直接调用 Entity 的方法来修改场景结构,要通过 UE::SceneGraphAPI 命名空间。原因在注释里写得很清楚——直接调用不会触发编辑器刷新(Undo/Redo 栈、Outliner 更新、视口重绘)。

// Entity.h - SceneGraphAPI 的核心操作
namespace UE::SceneGraphAPI
{
    TNotNull<verse::entity*> CreateEntity(...);
    bool AddEntity(...);
    bool RemoveOwnedEntity(...);
    verse::component* CreateComponent(...);
    verse::component* GetOrCreateComponentByType(...);

    void BeginBatchOperation(TNotNull<UWorld*> InWorld);  // 冻结编辑器刷新
    void EndBatchOperation(TNotNull<UWorld*> InWorld);    // 一次性刷新
}

BeginBatchOperation/EndBatchOperation 这对方法特别重要——当你需要一次性创建大量 Entity(例如数千个)时,把它们包在 Batch 里,编辑器只刷新一次,避免「每加一个就重绘一次 Outliner」的灾难性开销。

桥梁:Verse 和 Scene Graph 怎么咬合

上面拆了两套系统。现在看它们怎么接在一起——这是整个 UE6 新架构最核心的设计。

ECS 基础:Fragment、Archetype、Processor

UE6 的 ECS 实现在 Runtime/MassEntity/——Mass Entity 框架,最初由 Epic 的 AI 团队为大规模人群/交通模拟开发,最早在 2021 年的《The Matrix Awakens》Demo 中亮相。三个核心概念:

Fragment——纯数据,替代 Actor Component:

// EntityFragments.h
USTRUCT()
struct FTransformFragment : public FMassFragment
{
    GENERATED_BODY()
    UPROPERTY()
    FTransform Transform;
};

USTRUCT()
struct FHealthFragment : public FMassFragment
{
    GENERATED_BODY()
    UPROPERTY()
    float CurrentHealth = 100.0f;
};

Archetype——Fragment 的组合模板。同一个 Archetype 的所有实体共享相同的内存布局,让 Processor 可以连续遍历、对 CPU cache 友好。这正是 ECS 相对 OOP「逐对象虚调用」的核心性能优势来源。

Processor——纯逻辑,替代 Actor::Tick:

// MassProcessor.h
UCLASS(abstract, ...)
class UMassProcessor : public UObject
{
    UE_API virtual void ConfigureQueries(...);
    UE_API virtual void Execute(FMassEntityManager& EntityManager,
        FMassExecutionContext& Context)
;
};

一句话说清 ECS 为什么快:传统 OOP 是「对象数组,每个对象自带数据和虚函数表,遍历时不断 cache miss + 间接跳转」;ECS 是「同类数据连续排布,一个 Processor 像流水线一样扫过去」。当实体数量从几百涨到几万、几十万时,这个差距是数量级的。这也是 UE6 敢把 Actor 体系退役的底气——新模型在「海量同质实体」场景下天生更能扩展。

从零搭建一个 NPC:四步走完 Verse → ECS 全链路

上面拆的是原理。但架构图再漂亮,不如一段能跑的代码有说服力。下面用一个 NPC 的完整生命周期——从数据定义到并发调度——走一遍 Verse 和 Scene Graph 是怎么协作的。

第一步:定义 Fragment(C++ 侧)

在 Actor/Component 体系下,一个 NPC 需要继承 ACharacter、挂载 UHealthComponent、UBehaviorTreeComponent、重写 Tick。在 ECS 体系下,NPC 只是几个 Fragment 的组合:

// NPCFragments.h - C++ 侧定义纯数据
USTRUCT()
struct FHealthFragment : public FMassFragment
{
    GENERATED_BODY()
    UPROPERTY()
    float CurrentHealth = 100.0f;
    UPROPERTY()
    float MaxHealth = 100.0f;
};

USTRUCT()
struct FBehaviorStateFragment : public FMassFragment
{
    GENERATED_BODY()
    UPROPERTY()
    int32 State = 0;  // 0=Idle, 1=Patrol, 2=Combat, 3=Fleeing
};

FTransformFragment 引擎已经内置。几个 Fragment 组合成一个 Archetype,引擎自动分配连续内存布局。注意这里没有继承、没有虚函数、没有 Tick——Fragment 是纯 struct,所有字段都是 UPROPERTY(),可以直接序列化和网络复制。

第二步:在 Verse 中创建实体

UE6 的代码生成器自动为每个 FMassFragment 生成 Verse 类型绑定。OpNewObject 指令在运行时判断 Verse 类是否有 NativeRepresentation 标志,如果有就创建 C++ UObject 而非纯 Verse 堆对象。这意味着 Verse 代码可以直接操作 ECS 实体:

# NPC.verse - Verse 侧创建 NPC 实体
# <decides> 表示可能失败(比如空间被占用)
# <transacts> 表示有(可回滚的)副作用(修改 ECS 状态)
InitNPC<decides><transacts>(Position:vector3, PatrolPath:[]vector3):entity =
    var NPC:entity = CreateEntity(
        FTransformFragment{Transform := MakeTransform(Position)},
        FHealthFragment{CurrentHealth := 100.0, MaxHealth := 100.0},
        FBehaviorStateFragment{State := 1}  # 1 = Patrol
    )
    # 如果创建失败(空间被占用等),decides 自动触发事务回滚
    # 不需要手动写 if-failed-then-cleanup
    NPC

注意 <decides> 标注——如果 CreateEntity 因为空间被占用而失败,Verse 的事务系统自动回滚所有在该事务内的副作用。在 UE5 里你需要手动写 if (SpawnActorFailed) { DestroyActor(); RefundResources(); };在 Verse 里,「失败即回滚」是语言原语。

第三步:定义 Processor(Verse 侧)

Processor 就是带有效应标注的 Verse 函数,被 ECS 调度器按帧调用:

# NPCBehavior.verse - Verse 侧定义 Processor 逻辑
# <reads> + <writes> 告诉编译器这个函数会读写哪些 Fragment
# 编译器据此验证:两个 Processor 如果都 writes 同一个 Fragment,不能并行
PatrolProcessor<reads(TransformFragment, BehaviorStateFragment),
                writes(TransformFragment)>
    (Entities:[]entity, DeltaTime:float):void =

    for (NPC : Entities):
        var State = GetFragment[NPC, FBehaviorStateFragment].State
        var Transform = GetFragment[NPC, FTransformFragment].Transform

        if (State = 1):  # Patrol 状态
            var NewPos = MoveAlongPath(Transform.Position, DeltaTime)
            SetFragment[NPC, FTransformFragment]{
                Transform := MakeTransform(NewPos)
            }

这里 readswrites 不只是文档注释——编译器会检查:如果另一个 Processor 也声明了 writes(TransformFragment),并且调度器试图让它们并行,编译器/调度器会拒绝这种不安全的并行。

第四步:并发编排

最后一步,用 Verse 的并发原语把多个 Processor 组织成一帧的执行计划:

# WorldTick.verse - 每帧的顶层调度
TickWorld(DeltaTime:float):void =
    # rush: 三个 Processor 并行跑在不同实体组上
    # 效应系统确保它们操作不同 Fragment 时不会冲突
    rush:
        PatrolProcessor(PatrolEntities, DeltaTime)
        CombatProcessor(CombatEntities, DeltaTime)
        PhysicsProcessor(AllPhysicsEntities, DeltaTime)

    # 上面三个全部完成后,再跑依赖它们的 Processor
    # sync 块内的 Processor 可以读上面三个的结果
    sync:
        AnimationProcessor(AllNPCs, DeltaTime)
        AudioProcessor(AllNPCs, DeltaTime)

rush 直接映射到 ECS 的多 Processor 并行执行,sync 映射到依赖链。这四步走下来,一个 NPC 从数据定义到每帧调度,没有继承链、没有虚函数调用、没有手动加锁——Fragment 是纯数据,Processor 是纯逻辑,并发安全由效应系统在编译期/调度期保证。

效应系统 = ECS 并行安全的编译期保证

这是 Verse 效应系统和 Scene Graph 之间最深层的联系:

  • reads(Fragment) → 编译器知道这个 Processor 只读某个 Fragment,可以跟其他「只读同 Fragment」的 Processor 并行
  • writes(Fragment) → 编译器知道这个 Processor 会写某个 Fragment,不能跟任何「读或写同 Fragment」的 Processor 并行
  • allocates → 编译器知道这个函数会创建新实体(分配 Archetype 内存),需要写屏障配合 GC
  • suspends → 编译器知道这个函数可能等待异步操作,调度器可以挂起它而不阻塞整帧

这跟 Rust 的 borrow checker 同源但不同路——Rust 用所有权和生命周期在「单个数据」粒度上防数据竞争,Verse 用效应标注在「函数对 Fragment 集合」的粒度上判断可并行性。两者都实现了编译期的并行安全,但 Verse 的方案更接近「声明意图,编译器/调度器验证」,粒度更粗、更贴合 ECS 的批处理模型。

MCP:AI 进入 UE6 的门

MCP(Model Context Protocol)在 UE6 里的角色是把 Verse 暴露的引擎能力开放给外部 AI。源码在 Programs/UnrealConsole/Private/MCP/

// UCMcpIntegration.h
namespace UE::UnrealConsole::MCP {
    void Init();     // 注册所有 MCP 工具
    bool RegisterToolsetClass(UClass* ToolsetClass);
}

Epic 在 UE6 公告里明确表示:将通过开放的 MCP 基础设施暴露引擎能力,让开发者可以「混搭」各家领先模型(公告中点名了 Claude 与 Codex 等),直接辅助引擎内容创作。这里的「引擎能力」包括 Verse API——AI 可以生成 Verse 代码来创建实体、修改 Fragment、调度 Processor。

一句话总结:MCP 是 AI 进入 UE6 的门,Verse 是 AI 在门里说的话。 开发者用 Verse 定义 Fragment 和 Processor,MCP 把这些 API 暴露给外部 AI,AI 通过 MCP 调用 Verse API 来辅助内容生成——整个链条是 Verse → ECS → MCP → AI → Verse,形成一个闭环。

为什么是「确定性 API」而非「让 AI 直接写引擎内存」?MCP 暴露的是一组结构化、带类型与权限边界的工具调用,而不是把裸指针交给模型。配合 Verse 的效应系统与事务回滚,AI 生成的操作即使出错,也能被「失败即回滚」兜底——这是「让 AI 安全地动你的工程」的工程前提。换句话说,效应系统不只是给人用的安全网,也是给 AI 用的安全网。

四层架构全景

把上面的所有模块拼在一起:

┌──────────────────────────────────────────┐
│  MCP                                     │  AI 接口层
│  暴露 Verse API 给 Claude/Gemini/Codex    │
├──────────────────────────────────────────┤
│  Verse                                   │  语言层
│  效应系统(并行安全) + 并发原语(编排)       │
│  + 事务性内存(回滚) + GC(内存管理)        │
├──────────────────────────────────────────┤
│  Scene Graph + ECS (Mass Entity)         │  运行时层
│  Fragment(数据) + Archetype(布局)         │
│  + Processor(逻辑) + EntityManager(调度)  │
│  + ExecutionPhase(DAG) + SceneGraphAPI    │
├──────────────────────────────────────────┤
│  UE6 Core (渲染/物理/网络/音频...)        │  引擎层
└──────────────────────────────────────────┘

迁移视角:存量 UE5 项目怎么办

对绝大多数读者来说,比「源码有多漂亮」更现实的问题是:我手里这个 UE5 项目,会不会被这套新架构一刀切掉?几个判断:

  • 不是「一夜切换」,是「长期共存」。 Epic 明确说 Actor/Blueprint 会在 UE6 早期版本中继续存在,等新框架「足够成熟」后才逐步废弃,并提供转换工具。Early Access 在 2027 年底,正式版还要再过 12–18 个月——这给了项目数年的过渡窗口。

  • C++ 不会消失,是「下沉」。 C++ 退居引擎底层与高性能模块,Verse 接管 gameplay 层。把它理解为「C++ 之于 gameplay,类似于汇编之于 C++」更准确——不是淘汰,是分层。

  • Mass/ECS 不是全新概念。 Mass Entity 自 UE5 起就是实验性插件,已经有团队用它做人群、交通、子弹幕等海量实体场景。提前在 UE5 里熟悉 Mass,是平滑迁移到 UE6 运行时模型的最低成本路径。

  • Verse 已经能学了。 Verse 在 UEFN 里已公开多年,语法、效应系统、failure context 这些核心概念都可以现在就上手——等 UE6 出来再学,等于把学习曲线压缩到迁移窗口里,风险更高。

一个务实的建议:如果你现在启动一个生命周期会跨越 2027–2029 的新项目,值得做的不是「赌 UE6 重写」,而是「在 UE5 里就采用对 UE6 友好的架构」——数据与逻辑分离、减少深继承链、关键系统优先考虑 Mass/数据驱动。这样无论迁移与否,工程都更健康。

风险与未解之问:这套架构还要回答什么

一篇负责任的拆解不该只讲优点。这套架构同样背着几个尚未被充分回答的问题:

  • 调试与可观测性。 效应系统、事务回滚、协作式 Task、寄存器 VM——每一层都在「为正确性和性能做抽象」,但抽象越多,出问题时越难定位。「一个 decides 在深层失败、整串事务回滚」时,开发者怎么知道是哪一步触发的?工具链(断点、回放、效应可视化)能不能跟上语言的雄心,是成败关键。

  • 性能可预测性。 协作式调度避免了锁,但也意味着「一个不让出的长任务会拖住同一调度上下文里的其他 Task」。NaN-boxing 让浮点零成本,却给非浮点值加了解包成本。这些权衡在 Demo 里很美,在真实的、有 GC 停顿和 cache 抖动的项目里表现如何,还需要大规模实战检验。

  • 生态与人才。 Verse 是一门全新语言,functional logic + 效应系统的范式对习惯了 C++/Blueprint 的团队有真实的学习成本。第三方插件、教程、Stack Overflow 答案、AI 训练语料……整个生态要重新积累。Epic 把「AI 辅助」当成解法之一,但这也带来「AI 生成代码的质量与可维护性」这个新问题。

  • 「换两样东西」的复合风险。 同时换语言和对象模型,意味着任何一层出问题都会拖累整体迁移。这是 Epic 自己也承认「比 UE4→UE5 更难」的根本原因。它的回报可能很大,但执行风险也实打实地翻倍。

把这些问题摆上桌,不是唱衰,而是因为:正因为这套架构的赌注足够大,它值得被认真地、带着怀疑地认真对待。

为什么这套架构值得认真对待

翻完 Verse 编译器 + Verse VM + EntityFramework + Mass Entity,几个判断:

第一,这不是「UE5 加了一层脚本」。 Verse 的效应系统被深度集成到编译器的每个阶段——Parser 解析效应标注、SemanticAnalyzer 验证效应兼容性、IRGenerator 生成效应追踪字节码、VM 在运行时执行效应令牌传递。整个工具链围绕效应系统重新设计。而效应系统直接服务于 Scene Graph 的并行安全——reads/writes 标注让编译器/调度器能判断两个 Processor 能否并行执行。语言和运行时是互相定义的。

第二,并发模型务实且完整。 race/rush/branch/spawn 几种原语覆盖了游戏开发中最常见的并发模式——加载资源、竞速搜索、后台任务、多路并行。这些原语天然支持效应追踪,直接映射到 ECS 的多 Processor 调度,不需要程序员手动管理线程池、mutex 或 TaskGraph。

第三,事务性内存解决了游戏逻辑中最头疼的问题之一。 游戏逻辑经常需要「尝试做一件事,失败就全部回滚」——放置建筑(检查空间→扣资源→生成实体→任一步失败全部撤销)。Verse 的事务系统把这种模式变成语言原语,编译器自动管理回滚日志。在 ECS 体系下,这对应「原子地修改一组实体的 Fragment」——要么全部成功,要么全部回滚。

第四,源码已经就位。 VerseCompiler + VerseVM + EntityFramework + Mass Entity——这些模块都已经在公开仓库里,可以编译、运行、调试。Epic 在 UE6 源码公开的较早阶段就把整个新编程模型放了进去,而不是只给一份 PPT。

第五,AI 是这套架构的一等公民。 MCP 不是后来加的外挂,是架构设计之初就预留的接口。Verse 定义引擎能力,MCP 暴露给 AI,AI 生成 Verse 代码操作引擎——这个闭环意味着 UE6 的架构假设是「AI 会参与游戏开发」,而不是「AI 也许有点用」。

Epic 同时换掉你的语言和对象模型,不是因为 C++ 不够快或者 Actor 不够好,而是因为他们看到了一个更大的机会:当语言层(Verse)和运行时层(Scene Graph + ECS)被一起重新设计时,它们之间的接口可以被优化到极致——效应系统保证并行安全,并发原语映射到调度器,事务性内存映射到 Fragment 原子操作。单独换语言、或单独换运行时,都做不到这一点。


我每周拆解一个 UE5/UE6 底层系统,从源码级讲到可运行的代码。觉得有用,关注不走丢。

基本 文件 流程 错误 SQL 调试
  1. 请求信息 : 2026-06-26 22:03:43 HTTP/1.1 GET : https://www.yeyulingfeng.com/a/802863.html
  2. 运行时间 : 0.180310s [ 吞吐率:5.55req/s ] 内存消耗:4,725.81kb 文件加载:145
  3. 缓存信息 : 0 reads,0 writes
  4. 会话信息 : SESSION_ID=48338f1c9ff00ba5e57e52b898348470
  1. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/public/index.php ( 0.79 KB )
  2. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/autoload.php ( 0.17 KB )
  3. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_real.php ( 2.49 KB )
  4. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/platform_check.php ( 0.90 KB )
  5. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/ClassLoader.php ( 14.03 KB )
  6. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/composer/autoload_static.php ( 6.05 KB )
  7. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper.php ( 8.34 KB )
  8. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/helper.php ( 2.19 KB )
  9. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/ralouphie/getallheaders/src/getallheaders.php ( 1.60 KB )
  10. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/helper.php ( 1.47 KB )
  11. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/stubs/load_stubs.php ( 0.16 KB )
  12. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Exception.php ( 1.69 KB )
  13. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Facade.php ( 2.71 KB )
  14. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/deprecation-contracts/function.php ( 0.99 KB )
  15. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap.php ( 8.26 KB )
  16. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/polyfill-mbstring/bootstrap80.php ( 9.78 KB )
  17. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/Resources/functions/dump.php ( 1.49 KB )
  18. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-dumper/src/helper.php ( 0.18 KB )
  19. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/symfony/var-dumper/VarDumper.php ( 4.30 KB )
  20. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions_include.php ( 0.16 KB )
  21. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/guzzlehttp/guzzle/src/functions.php ( 5.54 KB )
  22. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/App.php ( 15.30 KB )
  23. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-container/src/Container.php ( 15.76 KB )
  24. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/container/src/ContainerInterface.php ( 1.02 KB )
  25. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/provider.php ( 0.19 KB )
  26. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Http.php ( 6.04 KB )
  27. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Str.php ( 7.29 KB )
  28. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Env.php ( 4.68 KB )
  29. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/common.php ( 0.03 KB )
  30. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/helper.php ( 18.78 KB )
  31. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Config.php ( 5.54 KB )
  32. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/alipay.php ( 3.59 KB )
  33. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Env.php ( 1.67 KB )
  34. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/app.php ( 0.95 KB )
  35. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cache.php ( 0.78 KB )
  36. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/console.php ( 0.23 KB )
  37. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/cookie.php ( 0.56 KB )
  38. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/database.php ( 2.48 KB )
  39. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/filesystem.php ( 0.61 KB )
  40. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/lang.php ( 0.91 KB )
  41. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/log.php ( 1.35 KB )
  42. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/middleware.php ( 0.19 KB )
  43. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/route.php ( 1.89 KB )
  44. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/session.php ( 0.57 KB )
  45. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/trace.php ( 0.34 KB )
  46. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/config/view.php ( 0.82 KB )
  47. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/event.php ( 0.25 KB )
  48. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Event.php ( 7.67 KB )
  49. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/service.php ( 0.13 KB )
  50. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/AppService.php ( 0.26 KB )
  51. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Service.php ( 1.64 KB )
  52. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Lang.php ( 7.35 KB )
  53. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/lang/zh-cn.php ( 13.70 KB )
  54. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/Error.php ( 3.31 KB )
  55. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/RegisterService.php ( 1.33 KB )
  56. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/services.php ( 0.14 KB )
  57. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/PaginatorService.php ( 1.52 KB )
  58. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ValidateService.php ( 0.99 KB )
  59. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/service/ModelService.php ( 2.04 KB )
  60. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Service.php ( 0.77 KB )
  61. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Middleware.php ( 6.72 KB )
  62. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/initializer/BootService.php ( 0.77 KB )
  63. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Paginator.php ( 11.86 KB )
  64. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-validate/src/Validate.php ( 63.20 KB )
  65. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/Model.php ( 23.55 KB )
  66. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Attribute.php ( 21.05 KB )
  67. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/AutoWriteData.php ( 4.21 KB )
  68. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/Conversion.php ( 6.44 KB )
  69. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/DbConnect.php ( 5.16 KB )
  70. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/ModelEvent.php ( 2.33 KB )
  71. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/concern/RelationShip.php ( 28.29 KB )
  72. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Arrayable.php ( 0.09 KB )
  73. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/contract/Jsonable.php ( 0.13 KB )
  74. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/model/contract/Modelable.php ( 0.09 KB )
  75. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Db.php ( 2.88 KB )
  76. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/DbManager.php ( 8.52 KB )
  77. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Log.php ( 6.28 KB )
  78. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Manager.php ( 3.92 KB )
  79. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerTrait.php ( 2.69 KB )
  80. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/log/src/LoggerInterface.php ( 2.71 KB )
  81. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cache.php ( 4.92 KB )
  82. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/psr/simple-cache/src/CacheInterface.php ( 4.71 KB )
  83. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/helper/Arr.php ( 16.63 KB )
  84. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/driver/File.php ( 7.84 KB )
  85. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/cache/Driver.php ( 9.03 KB )
  86. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/CacheHandlerInterface.php ( 1.99 KB )
  87. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/Request.php ( 0.09 KB )
  88. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Request.php ( 55.78 KB )
  89. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/middleware.php ( 0.25 KB )
  90. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Pipeline.php ( 2.61 KB )
  91. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/TraceDebug.php ( 3.40 KB )
  92. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/middleware/SessionInit.php ( 1.94 KB )
  93. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Session.php ( 1.80 KB )
  94. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/driver/File.php ( 6.27 KB )
  95. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/SessionHandlerInterface.php ( 0.87 KB )
  96. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/session/Store.php ( 7.12 KB )
  97. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Route.php ( 23.73 KB )
  98. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleName.php ( 5.75 KB )
  99. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Domain.php ( 2.53 KB )
  100. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleGroup.php ( 22.43 KB )
  101. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Rule.php ( 26.95 KB )
  102. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/RuleItem.php ( 9.78 KB )
  103. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/route/app.php ( 3.94 KB )
  104. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/Route.php ( 4.70 KB )
  105. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/dispatch/Controller.php ( 4.74 KB )
  106. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/route/Dispatch.php ( 10.44 KB )
  107. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Index.php ( 9.87 KB )
  108. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/BaseController.php ( 2.05 KB )
  109. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/facade/Db.php ( 0.93 KB )
  110. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/connector/Mysql.php ( 5.44 KB )
  111. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/PDOConnection.php ( 52.47 KB )
  112. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Connection.php ( 8.39 KB )
  113. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/ConnectionInterface.php ( 4.57 KB )
  114. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/builder/Mysql.php ( 16.58 KB )
  115. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Builder.php ( 24.06 KB )
  116. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseBuilder.php ( 27.50 KB )
  117. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/Query.php ( 15.71 KB )
  118. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/BaseQuery.php ( 45.13 KB )
  119. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TimeFieldQuery.php ( 7.43 KB )
  120. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/AggregateQuery.php ( 3.26 KB )
  121. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ModelRelationQuery.php ( 20.07 KB )
  122. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ParamsBind.php ( 3.66 KB )
  123. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/ResultOperation.php ( 7.01 KB )
  124. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/WhereQuery.php ( 19.37 KB )
  125. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/JoinAndViewQuery.php ( 7.11 KB )
  126. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/TableFieldInfo.php ( 2.63 KB )
  127. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-orm/src/db/concern/Transaction.php ( 2.77 KB )
  128. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/driver/File.php ( 5.96 KB )
  129. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/LogHandlerInterface.php ( 0.86 KB )
  130. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/log/Channel.php ( 3.89 KB )
  131. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/event/LogRecord.php ( 1.02 KB )
  132. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-helper/src/Collection.php ( 16.47 KB )
  133. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/facade/View.php ( 1.70 KB )
  134. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/View.php ( 4.39 KB )
  135. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/app/controller/Es.php ( 3.30 KB )
  136. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Response.php ( 8.81 KB )
  137. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/response/View.php ( 3.29 KB )
  138. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/Cookie.php ( 6.06 KB )
  139. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-view/src/Think.php ( 8.38 KB )
  140. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/framework/src/think/contract/TemplateHandlerInterface.php ( 1.60 KB )
  141. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/Template.php ( 46.61 KB )
  142. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/driver/File.php ( 2.41 KB )
  143. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-template/src/template/contract/DriverInterface.php ( 0.86 KB )
  144. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/runtime/temp/c935550e3e8a3a4c27dd94e439343fdf.php ( 31.50 KB )
  145. /yingpanguazai/ssd/ssd1/www/wwww.yeyulingfeng.com/vendor/topthink/think-trace/src/Html.php ( 4.42 KB )
  1. CONNECT:[ UseTime:0.000749s ] mysql:host=127.0.0.1;port=3306;dbname=wenku;charset=utf8mb4
  2. SHOW FULL COLUMNS FROM `fenlei` [ RunTime:0.001175s ]
  3. SELECT * FROM `fenlei` WHERE `fid` = 0 [ RunTime:0.000552s ]
  4. SELECT * FROM `fenlei` WHERE `fid` = 63 [ RunTime:0.000451s ]
  5. SHOW FULL COLUMNS FROM `set` [ RunTime:0.000916s ]
  6. SELECT * FROM `set` [ RunTime:0.000393s ]
  7. SHOW FULL COLUMNS FROM `article` [ RunTime:0.000991s ]
  8. SELECT * FROM `article` WHERE `id` = 802863 LIMIT 1 [ RunTime:0.000874s ]
  9. UPDATE `article` SET `lasttime` = 1782482623 WHERE `id` = 802863 [ RunTime:0.009689s ]
  10. SELECT * FROM `fenlei` WHERE `id` = 64 LIMIT 1 [ RunTime:0.000470s ]
  11. SELECT * FROM `article` WHERE `id` < 802863 ORDER BY `id` DESC LIMIT 1 [ RunTime:0.000861s ]
  12. SELECT * FROM `article` WHERE `id` > 802863 ORDER BY `id` ASC LIMIT 1 [ RunTime:0.006491s ]
  13. SELECT * FROM `article` WHERE `id` < 802863 ORDER BY `id` DESC LIMIT 10 [ RunTime:0.016751s ]
  14. SELECT * FROM `article` WHERE `id` < 802863 ORDER BY `id` DESC LIMIT 10,10 [ RunTime:0.001071s ]
  15. SELECT * FROM `article` WHERE `id` < 802863 ORDER BY `id` DESC LIMIT 20,10 [ RunTime:0.004759s ]
0.183728s