Skip to content

整理脚本目录并加载模块 ​

建立可运行的 SE Lua 工程,理解 client、server、common 与 data 目录边界。

什么时候查这篇 ​

新增文件后不知道应该放在哪里,或遇到 require 失败时,使用本专题。按当前需求选择小节即可,不必按专题编号顺序读完。

  • 开始前:完成主线第一课,能确认两端的日志来自本次试玩。
  • 安装与示例范围:最小模块实验需要三个文件一起安装;示例入口替换专用实验地图的同名文件,不追加到正在运行的主线入口。
  • 本次要看到:三条文件依赖均存在,client 和 server 都能打印共享模块结果。

如果还没有完成可运行的小游戏,先回到主线:10 课。语法卡住时查Lua 速查,运行结果不符时查按现象排错。

你会学到什么 ​

  • 如何从编辑器生成 Lua 脚本工程。
  • 默认生成的 client、server、common 三个目录分别负责什么。
  • 什么时候会出现 data/、EggyAPI.lua,以及它们和 VS Code 插件“导出数据 / 导出 API”的关系。
  • official、.codemaker、.vscode 这类目录为什么不要随便改。
  • 如何写最小脚本,确认 client 和 server 都在运行。
  • 为什么 main.lua 应该只做入口组装。
  • 世界编辑器的 Lua 运行环境与原点版有哪些差异(库裁剪、表键、math 库)。

从编辑器生成脚本工程 ​

  1. 在编辑器左上角选择 LUA - 蛋仔开发助手。
  2. 在弹窗左下角选择 生成工程。
  3. 选择本地路径,生成成功后用 VS Code 打开。
  4. 在 VS Code 里确认默认源码目录只有 client、server、common。

如果你还没有在 VS Code 插件里点过其它按钮,先不要疑惑为什么没有 data/ 或 EggyAPI.lua:

动作生成或更新什么用途
生成工程client/、server/、common/脚本入口和双端共享模块
导出数据data/,以及 UINodes.lua、Prefab.lua 等导出表UI 节点、预设、资源索引等编辑器数据
导出 APIEggyAPI.lua给 VS Code / Lua 语言服务使用的 API 提示与类型辅助

不同编辑器版本生成的辅助目录可能略有差异,但第一轮主线代码先围绕 client/server/common 组织;需要 UI、Prefab 或资源导出时,再通过“导出数据”获得 data/。

推荐工程结构 ​

text
LuaSource_<project_name>/
  .codemaker/              -- 官方编程助手规则、技能、工具
  .vscode/                 -- VS Code 工作区配置
  EggyAPI.lua              -- 点击“导出 API”后生成,供 VS Code 提示使用
  data/                    -- 点击“导出数据”后生成;也可手动放自己的静态配置
    CustomAsset.lua        -- 编辑器导出的自定义资产
    OfficialAsset.lua      -- 编辑器导出的官方资产索引
    Prefab.lua             -- 编辑器导出的预设资源
    UINodes.lua            -- UI 编辑器导出的节点表
    items.lua              -- 你自己写的静态配置
  common/
    remote_events.lua      -- 双端共享事件定义
  client/
    main.lua               -- 客户端入口
  server/
    main.lua               -- 服务端入口
  official/                -- 若存在,视为官方脚本目录
  log.txt                  -- 某些版本/导出流程生成的试玩日志;实际位置以当前工具为准

目录职责 ​

目录运行端能引用谁不能引用谁典型内容
data/双端可 require必要时引用其它纯 data 模块common/client/server纯配置、导出表、资源 URI
common/双端可 requiredataclient/server工具函数、RemoteEvent 定义、常量
client/clientdata/common/clientserverUI、输入、本地表现、相机
server/serverdata/common/serverclient计分、校验、存储、回合、跨服
official/由官方生成不建议引用或修改不修改官方脚本或辅助内容

data 和 common 的区别很重要:

  • data 可能来自“导出数据”,也可以由你手动创建配置表;它只放“数据”:table、数字、字符串、资源 URI,不要在顶层获取 Service、绑定事件或启动逻辑。
  • common 可以放双端工具,也可以集中定义 RemoteEvent,但仍不能依赖 client 或 server。

EggyAPI.lua 不属于玩法代码,不要在业务脚本里 require("EggyAPI")。它的作用是让编辑器和 VS Code 更懂当前 SDK。

require 的规则 ​

require 必须带目录前缀,并且只能引用当前目录规则允许的模块。下面四条是分别放在合适运行端的写法,不是让你把它们全部复制到同一个文件:

  • 双端都可用:require("data.items")、require("common.remote_events")。
  • 只放客户端:require("client.hud")。
  • 只放服务端:require("server.round_manager")。

错误写法:

示例类别:错误示例。 只用于识别问题,不要安装或运行。

lua
local Config = require("items")          -- 找不到 data/items.lua
local Hud = require("server.hud")        -- client 不能 require server
local Service = require("GameAPI")       -- game、Enums、Data 类型都是全局,不 require

全局对象直接使用:game、Enums、Vector3、Color、Quaternion、CFrame、RemoteEvent 等都不需要 require。如果看到旧规则要求 math.Vector3(...),以当前教程和运行时验证为准:正文统一使用全局 Vector3(...)。

Lua 运行环境(与原点版的差异) ​

世界编辑器的脚本同样运行在安全沙盒中,出于安全考虑裁剪了部分标准库。这部分裁剪与原点版(帧同步)一致;但在语言特性与 math 库上,世界编辑器不做原点版那样的定制。

库的裁剪(与原点版共通) ​

以下标准库被移除,脚本中不能使用:

  • io
  • os
  • package
  • debug

全局变量、函数和标准库按白名单管理。下面只列本教程会直接用到的常用入口,不宣称是运行包的完整清单;具体可用范围仍以目标运行包和当前开发助手提示为准。旧 Lua 教程里出现、但目标环境没有提供的库或函数不能直接照搬。

全局变量/函数限制
_VERSION无
error / assert无
ipairs / pairs / next无
pcall / xpcall无
tostring / tonumber / type字符串转数字失败时 tonumber 返回 nil,使用前要准备默认值
select无
coroutine协程标准库;入门异步优先使用用事件和计时器组织动作的 Task 服务
require仅限加载脚本工程目录下的其他 Lua 模块
setmetatable不可使用 __mode 和 __gc 域
getmetatable仅可获取 table 的 metatable
traceback等价于 debug.traceback
print无
string / table / utf8 / math保留的标准库入口;具体成员仍以目标运行包为准

例如在结算后保存最高分并查询排行会用 tonumber(value) or 0 把可能的字符串输入规整成数字;用事件和计时器组织动作则优先用 Task:Spawn / Task:Wait 讲协程,不要求新手直接操作 coroutine。

main.lua 应该做什么 ​

client/main.lua 和 server/main.lua 会自动执行,但它们不应该越来越长。推荐原则:

  • main.lua 负责 require 模块。
  • main.lua 负责调用 Init() / Start()。
  • 玩法细节放进 Manager 或模块。
  • UI 模块不要在 require 顶层自动绑定事件,应显式调用 Init()。

本专题先用下面的 TestCommonUtil 完成最小入口。到把稳定玩法拆成可清理的模块再拆 Manager,完成小游戏后选择扩展挑战会给出包含 RoundManager.Init(...)、Start()、Destroy() 的完整模块,避免你现在复制一个依赖尚未创建文件的半成品入口。

最小示例:确认双端都在运行 ​

common/TestCommonUtil.lua ​

运行端:common

示例类别:完整模块文件。 保存为 common/TestCommonUtil.lua;由对应运行端入口 require 并调用,单独放置文件不会自动执行功能。

lua
local TestCommonUtil = {}

function TestCommonUtil.PrintCurrentSide()
    local RunService = game:GetService("RunService")
    if RunService:IsClient() then
        print("[SE Lua Guide] 这里是客户端 client")
    elseif RunService:IsServer() then
        print("[SE Lua Guide] 这里是服务端 server")
    else
        print("[SE Lua Guide] 当前不是 client/server 试玩运行域")
    end
end

return TestCommonUtil

client/main.lua ​

运行端:client

示例类别:配套入口;运行端:client;文件:client/main.lua。 先安装 common/TestCommonUtil.lua,再替换实验地图入口。

lua
local TestCommonUtil = require("common.TestCommonUtil")

print("[SE Lua Guide] Hello, SE Client!")
TestCommonUtil.PrintCurrentSide()

server/main.lua ​

运行端:server

示例类别:配套入口;运行端:server。 先创建它 require 的所有文件;按本小节指定入口整段替换,不与已有主线入口重复安装。

lua
local TestCommonUtil = require("common.TestCommonUtil")

print("[SE Lua Guide] Hello, SE Server!")
TestCommonUtil.PrintCurrentSide()

期望结果 ​

运行游戏后,在编辑器输出窗口中应该看到类似日志。部分版本或导出流程也会生成 log.txt;没有这个文件不代表脚本没运行,应以当前编辑器输出和工具实际提供的日志入口为准。

text
[SE Lua Guide] Hello, SE Server!
[SE Lua Guide] 这里是服务端 server
[SE Lua Guide] Hello, SE Client!
[SE Lua Guide] 这里是客户端 client

日志顺序可能不同,这是正常的。客户端和服务端不是同一条顺序执行的脚本。

如果只看到其中一端,按这个顺序排查:

  1. 确认文件名分别是 client/main.lua 和 server/main.lua,没有放反目录。
  2. 确认 require("common.TestCommonUtil") 的目录、文件名和大小写完全一致。
  3. 从日志中找到第一条错误;后续错误往往只是第一处加载失败的连带结果。
  4. 修复后重新试玩,不要只看旧日志判断新代码。

查 API 时选对体系 ​

本教程使用 game:GetService(...) 这一套 SE Game API。搜索到使用 LuaAPI、GameAPI 或 GlobalAPI 的旧例子时,先确认它适用于同一套编辑器和版本,不直接替换当前函数名。

当前能力以本页末尾的 API 页面为入口;编辑器提示与实际运行不一致时,保留第一条错误并查看运行与兼容说明。不要通过引入 SDK 私有路径解决“找不到 API”。

常见错误 ​

错误:把运行逻辑写进 data ​

data/items.lua 只应该返回配置表。如果在里面 game:GetService()、绑定事件、创建 Unit,client 和 server require 它时都会产生副作用。data/ 即使是你手动创建的,也要遵守同样规则。

错误:client require server 模块 ​

客户端不能直接引用服务端模块。需要跨端通信时,用请求和快照同步双端状态会使用 RemoteEvent。

错误:修改 official 目录 ​

如果工程里有 official/,把它当作官方生成内容。项目逻辑写在 client/server/common/data,不要把自定义玩法塞进 official。

错误:把 EggyAPI.lua 当运行时代码 ​

EggyAPI.lua 是点击“导出 API”后生成给编辑器/VS Code 看的辅助文件。它不是玩法模块,不应被 client/main.lua 或 server/main.lua require。

错误:main.lua 堆满所有玩法 ​

第一天能跑,第三天就难改。超过一个小功能后,就把计分、回合、UI、技能等拆成模块。

练习任务 ​

  1. 如果工程里还没有 data/,先手动创建它,或在插件里点击“导出数据”生成它。
  2. 创建 data/round_config.lua,返回 { RoundSeconds = 60 }。
  3. 在 client 和 server 中分别 require 并打印 RoundSeconds。
  4. 创建 common/side.lua,封装 RunService:IsClient() / IsServer()。
  5. 点击“导出 API”,确认根目录出现 EggyAPI.lua,但不要在运行时代码里 require 它。
  6. 在确认前五步通过后,临时把一个 require 路径写错,观察第一条加载错误;随后立即恢复正确路径并重新试玩,确保工程回到可运行状态。

本专题验收标准 ​

  • [ ] 我知道如何从编辑器生成脚本工程。
  • [ ] 我知道默认生成工程先只有 client/server/common。
  • [ ] 我知道 data/ 来自“导出数据”或手动创建,EggyAPI.lua 来自“导出 API”。
  • [ ] 我知道 client/server/common/data 的职责和依赖方向。
  • [ ] 我知道 official 和 .codemaker 不应作为玩法代码目录。
  • [ ] 我知道 require 要写目录前缀。
  • [ ] 我能通过日志确认 client 和 server 都在运行。

本专题产物 ​

本专题产物是一个能启动的脚本工程骨架:client/main.lua、server/main.lua 和 common 模块都能被正确加载;如果你需要配置表或 UI 节点映射,还应能通过手动创建或“导出数据”得到 data/,并知道“导出 API”生成的 EggyAPI.lua 只服务于编辑器提示。

本专题 API 对照 ​

把结果带回小游戏 ​

先确认本页“本次要看到”的现象,再把选中的功能接到已有模块。保留原有入口和清理逻辑,只迁入需要的部分;不要把多个试验入口拼在一起。

返回主线对应步骤,或去专题导航选择下一项能力。新的代码尚未完成目标地图实测时,记录为待验证,不把编译通过当作行为通过。