diff --git a/docs/zh/API documentation/Client-Side.md b/docs/zh/API documentation/Client-Side.md new file mode 100644 index 00000000..b1106a18 --- /dev/null +++ b/docs/zh/API documentation/Client-Side.md @@ -0,0 +1,1502 @@ +## 目录 + +### MPVehicleGE + +- [Vehicle Functions(车辆函数)](#vehicle-functions) +- [Player Functions(玩家函数)](#player-functions) +- [Nametag Functions(昵称标签函数)](#nametag-functions) +- [Role Functions(角色函数)](#role-functions) +- [Navigation Functions(导航函数)](#navigation-functions) +- [Object Methods(对象方法)](#object-methods) +- [Event Hooks(事件钩子)](#event-hooks) + +### MPConfig + +- [MPConfig Functions(MPConfig函数)](#mpconfig-functions) + +### MPCoreNetwork + +- [MPCoreNetwork Functions](#mpcorenetwork-functions) + +### MPGameNetwork + +- [事件系统功能](#event-system-functions) +- [按键功能](#keypress-functions) +- [用户界面功能](#ui-functions) +- [MPGameNetwork 回调](#mpgamenetwork-callbacks) + +### MPHelpers + +- [编码函数](#encoding-functions) +- [颜色函数](#color-functions) +- [字符串函数](#string-functions) +- [表函数](#table-functions) +- [调试函数](#debug-functions) + +--- + +## 车辆函数 + +### `getGameVehicleID(serverVehicleID)` + +将 serverVehicleID 解析为 gameVehicleID + +**参数:** + +- `serverVehicleID` (字符串)- 格式:“X-Y”,其中 X 为玩家 ID,Y 为车辆 ID + +**返回:** + +- (数字)- 游戏内部车辆 ID +- (编号) `-1` - 如果车辆未知 + +**用法:** + +```lua +local gameID = extensions.MPVehicleGE.getGameVehicleID("0-0") +``` + +--- + +### `getServerVehicleID(gameVehicleID)` + +将 gameVehicleID 解析为 serverVehicleID + +**参数:** + +- `gameVehicleID` (数字)- 游戏内部车辆 ID + +**返回:** + +- (字符串)- 服务器车辆 ID(例如,“0-0”) +- (nil)- 如果 gameVehicleID 未知 + +**用法:** + +```lua +local serverID = extensions.MPVehicleGE.getServerVehicleID(11171) +``` + +--- + +### `getVehicleByServerID(serverVehicleID)` + +返回此车辆的完整车辆表 + +**参数:** + +- `serverVehicleID` (字符串)- 格式:“X-Y” + +**返回:** + +- (表)- 车辆信息(名称、游戏车辆 ID、jbeam、所有者 ID、所有者名称、是否本地、是否已生成等) +- (nil)- 如果服务器车辆 ID 无效 + +**用法:** + +```lua +local vehicle = extensions.MPVehicleGE.getVehicleByServerID("0-0") +if vehicle then + print("Owner: " .. vehicle.ownerName) +end +``` + +--- + +### `getVehicleByGameID(gameVehicleID)` + +返回此车辆的完整车辆表 + +**参数:** + +- `gameVehicleID` (数字)- 游戏内部车辆 ID + +**返回:** + +- (表)- 车辆信息 +- (nil) - 如果 gameVehicleID 无效 + +**用法:** + +```lua +local vehicle = extensions.MPVehicleGE.getVehicleByGameID(11171) +``` + +--- + +### `isOwn(gameVehicleID)` + +检查给定车辆是否属于此客户端 + +**参数:** + +- `gameVehicleID` (数字)- 游戏内部车辆 ID + +**返回:** + +- (boolean)- 如果车辆属于此客户端,则返回 true + +**用法:** + +```lua +if extensions.MPVehicleGE.isOwn(11171) then + print("This is my vehicle") +end +``` + +--- + +### `getOwnMap()` + +返回一个包含此客户端拥有的所有车辆的表。 + +**参数:** + +- 无 + +**返回:** + +- (表)- 已拥有车辆地图`{[gameVehicleID] = vehicles_subtable}` + +**用法:** + +```lua +local myVehicles = extensions.MPVehicleGE.getOwnMap() +``` + +--- + +### `getVehicleMap()` + +返回一个包含所有已知多人游戏载具的表。 + +**参数:** + +- 无 + +**返回:** + +- (表)- 所有车辆的地图`{[serverVehicleID] = gameVehicleID}` + +**用法:** + +```lua +local allVehicles = extensions.MPVehicleGE.getVehicleMap() +``` + +--- + +### `getDistanceMap()` + +返回每个多人游戏载具到此客户端视角的距离 + +**参数:** + +- 无 + +**返回:** + +- (表)- 距离地图`{[gameVehicleID] = distanceInMeters}` + +**用法:** + +```lua +local distances = extensions.MPVehicleGE.getDistanceMap() +``` + +--- + +### `getNicknameMap()` + +返回所有多人游戏车辆 ID 及其所有者名称 + +**参数:** + +- 无 + +**返回:** + +- (表)- 昵称映射表`{[gameVehicleID] = ownerName}` + +**用法:** + +```lua +local nicknameMap = extensions.MPVehicleGE.getNicknameMap() +``` + +--- + +### `getVehicles()` + +返回完整的车辆表 + +**参数:** + +- 无 + +**返回:** + +- (表)- 所有车辆`{[serverVehicleID] = vehicles_subtable}` + +**用法:** + +```lua +local vehicles = extensions.MPVehicleGE.getVehicles() +for serverID, vehicle in pairs(vehicles) do + print("Vehicle: " .. vehicle.jbeam) +end +``` + +--- + +## 玩家函数 + +### `getPlayerByName(name)` + +返回该玩家的信息表和 ID + +**参数:** + +- `name` (字符串)- 玩家名称 + +**返回:** + +- (表)- 玩家信息(姓名、玩家ID、角色、载具等) +- (数字)- 玩家 ID +- (nil)- 如果未找到玩家 + +**用法:** + +```lua +local player, playerID = extensions.MPVehicleGE.getPlayerByName("John") +if player then + print("Player ID: " .. playerID) +end +``` + +--- + +### `getPlayers()` + +返回完整的玩家表 + +**参数:** + +- 无 + +**返回:** + +- (表)- 所有玩家`{[playerID] = players_subtable}` + +**用法:** + +```lua +local players = extensions.MPVehicleGE.getPlayers() +for playerID, player in pairs(players) do + print("Player: " .. player.name) +end +``` + +--- + +## 昵称标签函数 + +### `setPlayerNickPrefix(targetName, tagSource, text)` + +给玩家的名字标签添加前缀(显示在名字前面) + +**参数:** + +- `targetName` (字符串)- 玩家名称 +- `tagSource` (字符串)- 此前缀的唯一标识符 +- `text` (字符串)- 显示在名称之前的文本 + +**用法:** + +```lua +extensions.MPVehicleGE.setPlayerNickPrefix("John", "RANK", "1st.") +-- Result: "1st. John" +``` + +--- + +### `setPlayerNickSuffix(targetName, tagSource, text)` + +给玩家的名字标签添加后缀(显示在名字后面) + +**参数:** + +- `targetName` (字符串)- 玩家名称 +- `tagSource` (字符串)- 此后缀的唯一标识符 +- `text` (字符串)- 名称后显示的文本 + +**用法:** + +```lua +extensions.MPVehicleGE.setPlayerNickSuffix("John", "STATUS", "[AFK]") +-- Result: "John [AFK]" +``` + +--- + +### `hideNicknames(hide)` + +开启或关闭 BeamMP 的姓名标签绘制功能 + +**参数:** + +- `hide` (boolean) - True 表示隐藏姓名标签,False 表示显示姓名标签 + +**用法:** + +```lua +extensions.MPVehicleGE.hideNicknames(true) -- Hide +extensions.MPVehicleGE.hideNicknames(false) -- Show +``` + +--- + +### `toggleNicknames()` + +切换显示姓名标签 + +**参数:** + +- 无 + +**用法:** + +```lua +extensions.MPVehicleGE.toggleNicknames() +``` + +--- + +## 角色函数 + +### `setPlayerRole(playerID, tag, shorttag, red, green, blue)` + +为玩家设置自定义角色 + +**参数:** + +- `playerID` (数字)- 玩家的ID +- `tag` (字符串)- 角色标签(例如,“VIP”) +- `shorttag` (字符串)- 简短版本(例如,“V”) +- `red` (数字)- 红色通道(0-255) +- `green` (数字)- 绿色通道(0-255) +- `blue` (数字)- 蓝色通道(0-255) + +**返回:** + +- (布尔值,字符串)- 如果玩家不存在`false, "player not found"` +- (布尔值,字符串)- 如果参数无效,则`false, error` +- (无)——关于成功无信息 + +**用法:** + +```lua +local success, error = extensions.MPVehicleGE.setPlayerRole(0, "VIP", "V", 255, 215, 0) +if success == false then + print("Error: " .. error) +end +``` + +--- + +### `clearPlayerRole(playerID)` + +清除玩家的自定义角色 + +**参数:** + +- `playerID` (数字)- 玩家的ID + +**返回:** + +- (布尔值)- 始终返回`false` (实现怪癖 - 用于检查玩家是否存在) + +**用法:** + +```lua +extensions.MPVehicleGE.clearPlayerRole(0) +``` + +--- + +### `setVehicleRole(playerIDVehicleID, tag, shorttag, red, green, blue)` + +为特定车辆设置自定义角色 + +**参数:** + +- `playerIDVehicleID` (字符串)- 车辆 ID(格式:“0-0”) +- `tag` (字符串)- 角色标签 +- `shorttag` (字符串)- 短版本 +- `red` (数字)- 红色(0-255) +- `green` (数字)- 绿色(0-255) +- `blue` (数字)- 蓝色(0-255) + +**返回:** + +- (布尔值,字符串)- 如果车辆不存在`false, "vehicle not found"` +- (布尔值,字符串)- 如果参数无效,则`false, error` +- (无)——关于成功无信息 + +**用法:** + +```lua +local success, error = extensions.MPVehicleGE.setVehicleRole("0-0", "Police", "POL", 0, 0, 255) +if success == false then + print("Error: " .. error) +end +``` + +--- + +### `clearVehicleRole(playerIDVehicleID)` + +清除车辆的自定义角色 + +**参数:** + +- `playerIDVehicleID` (字符串)- 车辆 ID(格式:“0-0”) + +**返回:** + +- (布尔值)- 始终返回`false` (实现特性 - 用于检查车辆是否存在) + +**用法:** + +```lua +extensions.MPVehicleGE.clearVehicleRole("0-0") +``` + +--- + +## 导航函数 + +### `groundmarkerToPlayer(targetName)` + +设置一条通往目标玩家位置的地面标记路线(静态) + +**参数:** + +- `targetName` (字符串)- 玩家名称,如果为 nil 则清除 + +**用法:** + +```lua +extensions.MPVehicleGE.groundmarkerToPlayer("John") -- Set +extensions.MPVehicleGE.groundmarkerToPlayer(nil) -- Clear +``` + +--- + +### `groundmarkerFollowPlayer(targetName, dontfollow)` + +设置跟随目标玩家的地面标记路线 + +**参数:** + +- `targetName` (字符串)- 玩家名称,如果为 nil 则停止 +- `dontfollow` (布尔值)- 如果为true,则创建静态标记 + +**用法:** + +```lua +extensions.MPVehicleGE.groundmarkerFollowPlayer("John") -- Follow +extensions.MPVehicleGE.groundmarkerFollowPlayer("John", true) -- Static +extensions.MPVehicleGE.groundmarkerFollowPlayer(nil) -- Stop +``` + +--- + +### `queryRoadNodeToPosition(targetPosition, owner)` + +查找距离目标位置最近的道路节点 + +**参数:** + +- `targetPosition` (vec3 或表)- 目标位置,包含 x、y、z 坐标 +- `owner` (字符串)- 可选标识符(默认值:“target”) + +**返回:** + +- (布尔值)- 成功状态 +- (数字)- 节点 ID(如果成功) + +**用法:** + +```lua +local pos = vec3(100, 200, 50) +local success, nodeID = extensions.MPVehicleGE.queryRoadNodeToPosition(pos) +``` + +--- + +## 对象方法 + +### 玩家对象方法 + +#### `player:setNickPrefix(tagSource, text)` + +设置该玩家名称标签的前缀 + +**参数:** + +- `tagSource` (字符串)- 唯一标识符 +- `text` (字符串)- 要显示的文本(或 nil 表示不显示) + +**用法:** + +```lua +local player = extensions.MPVehicleGE.getPlayerByName("John") +if player then + player:setNickPrefix("STATUS", "[AFK]") +end +``` + +--- + +#### `player:setNickSuffix(tagSource, text)` + +为该玩家的姓名标签设置后缀 + +**参数:** + +- `tagSource` (字符串)- 唯一标识符 +- `text` (字符串)- 要显示的文本(或 nil 表示不显示) + +**用法:** + +```lua +local player = extensions.MPVehicleGE.getPlayerByName("John") +if player then + player:setNickSuffix("MISSION", "[In Mission]") +end +``` + +--- + +#### `player:setCustomRole(role)` + +为该玩家设置自定义角色 + +**参数:** + +- `role` (表)- 角色表: `{backcolor = {r, g, b}, tag = string, shorttag = string}` + +**用法:** + +```lua +local player = extensions.MPVehicleGE.getPlayerByName("John") +if player then + player:setCustomRole({ + backcolor = {r = 255, g = 0, b = 0}, + tag = " [VIP]", + shorttag = " [V]" + }) +end +``` + +--- + +#### `player:clearCustomRole()` + +清除该玩家的自定义角色 + +**用法:** + +```lua +local player = extensions.MPVehicleGE.getPlayerByName("John") +if player then + player:clearCustomRole() +end +``` + +--- + +### 车辆对象方法 + +#### `vehicle:getOwner()` + +返回此车辆的所有者 + +**返回:** + +- (表)- 玩家对象 +- (数字)- 玩家 ID + +**用法:** + +```lua +local vehicle = extensions.MPVehicleGE.getVehicleByServerID("0-0") +if vehicle then + local owner, ownerID = vehicle:getOwner() + print("Owner: " .. owner.name) +end +``` + +--- + +#### `vehicle:setCustomRole(role)` + +为这辆车设置自定义角色 + +**参数:** + +- `role` (表)- 角色表: `{backcolor = {r, g, b}, tag = string, shorttag = string}` + +**用法:** + +```lua +local vehicle = extensions.MPVehicleGE.getVehicleByServerID("0-0") +if vehicle then + vehicle:setCustomRole({ + backcolor = {r = 0, g = 0, b = 255}, + tag = " [Police]", + shorttag = " [POL]" + }) +end +``` + +--- + +#### `vehicle:clearCustomRole()` + +清除此车辆的自定义角色 + +**用法:** + +```lua +local vehicle = extensions.MPVehicleGE.getVehicleByServerID("0-0") +if vehicle then + vehicle:clearCustomRole() +end +``` + +--- + +#### `vehicle:setDisplayName(displayName)` + +为这辆车设置自定义显示名称 + +**参数:** + +- `displayName` (字符串)- 要显示的自定义名称 + +**用法:** + +```lua +local vehicle = extensions.MPVehicleGE.getVehicleByServerID("0-0") +if vehicle then + vehicle:setDisplayName("Patrol Car #1") +end +``` + +--- + +## 事件钩子 + +BeamMP 提供事件钩子,您可以重写这些钩子以在特定事件发生时执行自定义代码。**请勿直接调用这些函数**,而应在保留原始功能的前提下对其进行重写。 + +### 钩子模式 + +重写函数时,务必保留原函数: + +```lua +-- Save the original function +local originalCallback = MPVehicleGE.onVehicleSpawned + +-- Override with your custom logic +MPVehicleGE.onVehicleSpawned = function(gameVehicleID) + -- Call the original first + originalCallback(gameVehicleID) + + -- Your custom code here + print("Vehicle spawned: " .. gameVehicleID) +end +``` + +--- + +### 可用的事件钩子 + +#### `onUpdate(dt)` + +连接到多人游戏时,每一帧都会被调用 + +**参数:** + +- `dt` (数值)- 自上一帧以来的时间间隔(秒)。 + +**用法:** + +```lua +local originalOnUpdate = MPVehicleGE.onUpdate +MPVehicleGE.onUpdate = function(dt) + originalOnUpdate(dt) + -- Your frame-by-frame logic here +end +``` + +--- + +#### `onPreRender(dt)` + +在渲染每一帧之前调用 + +**参数:** + +- `dt` (数值)- 时间差(秒) + +**注意:**此功能在内部处理名称标签渲染、距离计算和地面标记。 + +**用法:** + +```lua +local originalOnPreRender = MPVehicleGE.onPreRender +MPVehicleGE.onPreRender = function(dt) + originalOnPreRender(dt) + -- Your pre-render logic here +end +``` + +--- + +#### `onVehicleSpawned(gameVehicleID)` + +当车辆生成时调用(包括本地和远程车辆) + +**参数:** + +- `gameVehicleID` (数字)- 游戏内部车辆 ID + +**用法:** + +```lua +local originalOnVehicleSpawned = MPVehicleGE.onVehicleSpawned +MPVehicleGE.onVehicleSpawned = function(gameVehicleID) + originalOnVehicleSpawned(gameVehicleID) + + local vehicle = extensions.MPVehicleGE.getVehicleByGameID(gameVehicleID) + if vehicle then + print(vehicle.ownerName .. " spawned a " .. vehicle.jbeam) + end +end +``` + +--- + +#### `onVehicleDestroyed(gameVehicleID)` + +车辆被销毁/移除时调用 + +**参数:** + +- `gameVehicleID` (数字)- 游戏内部车辆 ID + +**用法:** + +```lua +local originalOnVehicleDestroyed = MPVehicleGE.onVehicleDestroyed +MPVehicleGE.onVehicleDestroyed = function(gameVehicleID) + local vehicle = extensions.MPVehicleGE.getVehicleByGameID(gameVehicleID) + if vehicle then + print("Vehicle " .. vehicle.jbeam .. " was destroyed") + end + + originalOnVehicleDestroyed(gameVehicleID) +end +``` + +--- + +#### `onVehicleSwitched(oldGameVehicleID, newGameVehicleID)` + +当玩家切换车辆时调用 + +**参数:** + +- `oldGameVehicleID` (数字)- 先前的车辆 ID(或 -1) +- `newGameVehicleID` (数字)- 新车辆 ID(或 -1) + +**用法:** + +```lua +local originalOnVehicleSwitched = MPVehicleGE.onVehicleSwitched +MPVehicleGE.onVehicleSwitched = function(oldID, newID) + originalOnVehicleSwitched(oldID, newID) + + print("Switched from vehicle " .. oldID .. " to " .. newID) +end +``` + +--- + +#### `onVehicleResetted(gameVehicleID)` + +车辆重置时调用(仅限本地车辆) + +**参数:** + +- `gameVehicleID` (数字)- 游戏内部车辆 ID + +**用法:** + +```lua +local originalOnVehicleResetted = MPVehicleGE.onVehicleResetted +MPVehicleGE.onVehicleResetted = function(gameVehicleID) + originalOnVehicleResetted(gameVehicleID) + + print("Vehicle " .. gameVehicleID .. " was reset") +end +``` + +--- + +#### `onVehicleColorChanged(gameVehicleID, index, paint)` + +当车辆的涂装颜色发生变化时调用 + +**参数:** + +- `gameVehicleID` (数字)- 游戏内部车辆 ID +- `index` (数字)- 涂装槽索引(0、1 或 2) +- `paint` (表) - 包含颜色信息的油漆数据 + +**用法:** + +```lua +local originalOnVehicleColorChanged = MPVehicleGE.onVehicleColorChanged +MPVehicleGE.onVehicleColorChanged = function(gameVehicleID, index, paint) + originalOnVehicleColorChanged(gameVehicleID, index, paint) + + print("Vehicle " .. gameVehicleID .. " changed paint slot " .. index) +end +``` + +--- + +#### `onVehicleReady(gameVehicleID)` + +当车辆的扩展设备加载完毕且车辆完全准备就绪时,就会发出此通知。 + +**参数:** + +- `gameVehicleID` (数字)- 游戏内部车辆 ID + +**注意:**如果需要加载车辆扩展,请使用此方法代替`onVehicleSpawned` 。 + +**用法:** + +```lua +local originalOnVehicleReady = MPVehicleGE.onVehicleReady +MPVehicleGE.onVehicleReady = function(gameVehicleID) + originalOnVehicleReady(gameVehicleID) + + -- Safe to interact with vehicle extensions here + local veh = be:getObjectByID(gameVehicleID) + if veh then + veh:queueLuaCommand("print('Vehicle is ready!')") + end +end +``` + +--- + +#### `onUIInitialised()` + +在 BeamMP 用户界面初始化时调用 + +**用法:** + +```lua +local originalOnUIInitialised = MPVehicleGE.onUIInitialised +MPVehicleGE.onUIInitialised = function() + originalOnUIInitialised() + + print("BeamMP UI initialized") +end +``` + +--- + +#### `onSettingsChanged()` + +当 BeamMP 设置更改时调用 + +**用法:** + +```lua +local originalOnSettingsChanged = MPVehicleGE.onSettingsChanged +MPVehicleGE.onSettingsChanged = function() + originalOnSettingsChanged() + + print("BeamMP settings changed") +end +``` + +--- + +## MPConfig 函数 + +### `MPConfig.getPlayerServerID()` + +返回本地玩家的服务器分配 ID + +**返回:** + +- (数字)- 玩家的服务器 ID(如果未设置则为 -1) + +**用法:** + +```lua +local myID = extensions.MPConfig.getPlayerServerID() +``` + +--- + +### `MPConfig.getNickname()` + +返回本地玩家的昵称 + +**返回:** + +- (字符串)- 玩家当前的昵称 + +**用法:** + +```lua +local name = extensions.MPConfig.getNickname() +``` + +--- + +### `MPConfig.getConfig()` + +返回 BeamMP 配置设置 + +**返回:** + +- (表)- 包含所有 BeamMP 设置的配置表 +- (nil)- 如果配置文件不存在 + +**用法:** + +```lua +local config = extensions.MPConfig.getConfig() +``` + +--- + +### `MPConfig.setConfig(settingName, settingVal)` + +设置特定配置值 + +**参数:** + +- `settingName` (字符串)- 设置的名称 +- `settingVal` (任意值) - 要设置的值 + +**用法:** + +```lua +extensions.MPConfig.setConfig("myCustomSetting", true) +``` + +--- + +## MPCoreNetwork 函数 + +### `MPCoreNetwork.getCurrentServer()` + +返回有关当前连接服务器的信息 + +**返回:** + +- (表)- 服务器数据(IP 地址、端口、名称、映射) +- (nil)- 如果未连接 + +**用法:** + +```lua +local server = extensions.MPCoreNetwork.getCurrentServer() +if server then + print("Server: " .. server.name) + print("IP: " .. server.ip .. ":" .. server.port) +end +``` + +--- + +## 事件系统功能 + +### `TriggerServerEvent(name, data)` + +向服务器发送事件 + +**参数:** + +- `name` (字符串)- 事件名称 +- `data` (字符串)- 要发送的数据 + +**注意:**这是一个全局函数。服务器必须已注册此事件的处理程序。 + +**用法:** + +```lua +TriggerServerEvent("playerReady", "ready") + +-- With JSON +local data = {position = {x=100, y=200, z=50}} +TriggerServerEvent("updatePlayer", jsonEncode(data)) +``` + +--- + +### `TriggerClientEvent(name, data)` + +触发本地客户端事件 + +**参数:** + +- `name` (字符串)- 事件名称 +- `data` (字符串)- 要发送的数据 + +**注意:**全局函数。在本地触发,无需发送到服务器。 + +**用法:** + +```lua +TriggerClientEvent("localUpdate", "data") +``` + +--- + +### `AddEventHandler(event_name, func, name)` + +注册一个用于处理特定事件的函数 + +**参数:** + +- `event_name` (字符串)- 要处理的事件的名称 +- `func` (函数)- 处理函数(接收事件数据) +- `name` (字符串)- 可选的内部名称 + +**注意:**全局函数。 + +**用法:** + +```lua +AddEventHandler("playerDamage", function(data) + print("Damage: " .. data) +end) + +-- With JSON +AddEventHandler("vehicleSpawned", function(data) + local vehData = jsonDecode(data) + print("Spawned: " .. vehData.model) +end) +``` + +--- + +### `RemoveEventHandler(event_name, name)` + +移除事件处理程序 + +**参数:** + +- `event_name` (字符串)- 事件名称 +- `name` (字符串)- 可选的内部名称 + +**注意:**全局函数。 + +**用法:** + +```lua +RemoveEventHandler("playerDamage") +``` + +--- + +## 按键功能 + +### `onKeyPressed(keyname, func)` + +注册一个按键按下时要调用的函数 + +**参数:** + +- `keyname` (字符串)- 按键的名称(例如,“NUMPAD1”、“F1”) +- `func` (函数)- 要调用的函数(接收布尔值) + +**注意:**全局函数。 + +**用法:** + +```lua +onKeyPressed("NUMPAD1", function(state) + print("NUMPAD1 pressed!") +end) +``` + +--- + +### `onKeyReleased(keyname, func)` + +注册一个在按键释放时要调用的函数 + +**参数:** + +- `keyname` (字符串)- 键的名称 +- `func` (函数)- 要调用的函数(接收布尔值) + +**注意:**全局函数。 + +**用法:** + +```lua +onKeyReleased("NUMPAD1", function(state) + print("NUMPAD1 released!") +end) +``` + +--- + +### `addKeyEventListener(keyname, func, type)` + +注册一个具有可自定义触发类型的按键事件监听器 + +**参数:** + +- `keyname` (字符串)- 键的名称 +- `func` (函数)- 要调用的函数 +- `type` (字符串)- 事件类型:“向下”、“向上”或“两者”(默认值:“两者”) + +**注意:**全局函数。 + +**用法:** + +```lua +addKeyEventListener("F1", function(isPressed) + if isPressed then + print("F1 pressed") + else + print("F1 released") + end +end, "both") +``` + +--- + +### `getKeyState(keyname)` + +返回键的当前状态 + +**参数:** + +- `keyname` (字符串)- 按键名称 + +**返回:** + +- (布尔值)- 按下时为true,否则为false + +**注意:**全局函数。仅适用于通过 addKeyEventListener 注册的键。 + +**用法:** + +```lua +local isPressed = getKeyState("NUMPAD1") +if isPressed then + print("NUMPAD1 is held down") +end +``` + +--- + +## UI 函数 + +### `MPGameNetwork.spawnUiDialog(dialogInfo)` + +创建自定义交互式对话框 + +**参数:** + +- `dialogInfo` (表)- 对话框配置: + - `title` (字符串)- 对话框标题(可选) + - `body` (字符串)- 对话框消息(可选) + - `buttons` (表) - 按钮配置(可选) + - `class` (字符串)- “experimental” 用于危险警示线(可选) + - `interactionID` (字符串)- 交互标识符(可选) + - `reportToServer` (布尔值)- 发送到服务器(可选,默认值:false) + - `reportToExtensions` (布尔值)- 触发本地事件(可选,默认值:false) + +**用法:** + +```lua +-- Simple dialog +extensions.MPGameNetwork.spawnUiDialog({ + title = "Welcome", + body = "Welcome to the server!" +}) + +-- Choice dialog +extensions.MPGameNetwork.spawnUiDialog({ + title = "Choose Team", + body = "Which team?", + buttons = { + {label = "Red", key = "joinRed"}, + {label = "Blue", key = "joinBlue"} + }, + interactionID = "teamSelection", + reportToServer = true +}) +``` + +--- + +## MPGameNetwork 回调 + +### `MPGameNetwork.onUpdate(dt)` + +连接到多人游戏时,每一帧都会被调用 + +**参数:** + +- `dt` (数值)- 时间差(秒) + +**用法:** + +```lua +local originalOnUpdate = MPGameNetwork.onUpdate +MPGameNetwork.onUpdate = function(dt) + originalOnUpdate(dt) + -- Your code here +end +``` + +--- + +### `MPGameNetwork.onVehicleReady(gameVehicleID)` + +当车辆准备就绪且扩展设备已加载完毕时,会发出呼叫。 + +**参数:** + +- `gameVehicleID` (数字)- 游戏内部车辆 ID + +**用法:** + +```lua +local originalOnVehicleReady = MPGameNetwork.onVehicleReady +MPGameNetwork.onVehicleReady = function(gameVehicleID) + originalOnVehicleReady(gameVehicleID) + -- Your code here +end +``` + +--- + +## 编码函数 + +### `MPHelpers.b64encode(string)` + +将字符串编码为 Base64(RFC 2045) + +**参数:** + +- `string` (字符串)- 要编码的字符串 + +**返回:** + +- (字符串)- Base64 编码的字符串 + +**用法:** + +```lua +local encoded = extensions.MPHelpers.b64encode("Hello World") + +-- Encoding JSON +local data = {name = "Player", score = 100} +local encoded = extensions.MPHelpers.b64encode(jsonEncode(data)) +TriggerServerEvent("sendData", encoded) +``` + +--- + +### `MPHelpers.b64decode(string)` + +解码 Base64 字符串(RFC 2045) + +**参数:** + +- `string` (string)- Base64 编码的字符串 + +**返回:** + +- (字符串)- 解码后的字符串 + +**用法:** + +```lua +local decoded = extensions.MPHelpers.b64decode("SGVsbG8gV29ybGQ=") + +-- Decoding JSON +AddEventHandler("receiveData", function(data) + local decoded = extensions.MPHelpers.b64decode(data) + local jsonData = jsonDecode(decoded) +end) +``` + +--- + +## 颜色函数 + +### `MPHelpers.hex2rgb(hex)` + +将十六进制颜色代码转换为 RGB 值 + +**参数:** + +- `hex` (字符串)- 十六进制颜色代码(例如,“#FF5733”或“#F57”) + +**返回:** + +- (表)- RGB 值`{r, g, b}`范围为 0-1 +- (表)- 如果无效则为`{0, 0, 0}` + +**注意:**支持 3 位和 6 位十六进制代码。 + +**用法:** + +```lua +local rgb = extensions.MPHelpers.hex2rgb("#FF5733") +print(rgb[1], rgb[2], rgb[3]) -- 1.0, 0.341, 0.2 + +-- Short format +local rgb = extensions.MPHelpers.hex2rgb("#F57") +``` + +--- + +## 字符串函数 + +### `MPHelpers.splitStringToTable(string, delimiter, convert_into)` + +按分隔符拆分字符串,并可选择转换值 + +**参数:** + +- `string` (字符串)- 要拆分的字符串 +- `delimiter` (字符串) - 用于分割的分隔符 +- `convert_into` (number) - 转换类型(可选): + - `nil`或`0` - 保留为字符串(默认值) + - `1` - 转换为数字 + - `2` - 转换为布尔值 + +**返回:** + +- (表)- 分割值的数组 + +**用法:** + +```lua +-- Strings +local parts = extensions.MPHelpers.splitStringToTable("Hello,World", ",") +-- {"Hello", "World"} + +-- Numbers +local nums = extensions.MPHelpers.splitStringToTable("10,20,30", ",", 1) +-- {10, 20, 30} + +-- Parse coordinates +local coords = extensions.MPHelpers.splitStringToTable("100,200,50", ",", 1) +local x, y, z = coords[1], coords[2], coords[3] +``` + +--- + +## 表函数 + +### `MPHelpers.tableDiff(old, new)` + +比较两个表并返回它们的差异 + +**参数:** + +- `old`表 - 要比较的第一个表 +- `new` (表)——第二个用于比较的表 + +**返回:** + +- (表) `diff` - 所有不同的键 +- (表) `o` - 与旧值不同的值 +- (表) `n` - 与新值不同的数值 + +**用法:** + +```lua +local oldConfig = {speed = 100, damage = 50, armor = 30} +local newConfig = {speed = 120, damage = 50, armor = 40} + +local diff, oldVals, newVals = extensions.MPHelpers.tableDiff(oldConfig, newConfig) +-- diff = {speed = 120, armor = 40} + +for key, value in pairs(diff) do + print(key .. " changed from " .. oldVals[key] .. " to " .. newVals[key]) +end +``` + +--- + +## 调试函数 + +### `MPHelpers.simpletraces(level)` + +返回格式化的调用者信息字符串。 + +**参数:** + +- `level` (数字)- 堆栈层级(可选,默认值:2) + +**返回:** + +- (字符串)- 格式化字符串: `"source:line, namewhat name"` +- (字符串)- 如果信息不可用,则为`"unknown"` + +**用法:** + +```lua +local function myFunction() + local caller = extensions.MPHelpers.simpletraces() + print("Called from: " .. caller) +end +``` + +--- + +### `MPHelpers.simpletrace(level)` + +将调用者信息记录到控制台 + +**参数:** + +- `level` (数字)- 堆栈层级(可选,默认值:1) + +**注意:**将调用位置记录到控制台。 + +**用法:** + +```lua +local function myFunction() + extensions.MPHelpers.simpletrace() + -- Logs: "Code was called from: lua/ge/extensions/mymod.lua:42" +end +``` + +--- + +*最后更新日期:2026年1月1日* diff --git a/docs/zh/API documentation/Server-Side.md b/docs/zh/API documentation/Server-Side.md new file mode 100644 index 00000000..73f5cf3f --- /dev/null +++ b/docs/zh/API documentation/Server-Side.md @@ -0,0 +1,1549 @@ +## 目录 + +### 全局 + +- [全局函数](#global-functions) + +### MP + +- [玩家](#mp--players) +- [车辆](#mp--vehicles) +- [通信](#mp--communication) +- [事件](#mp--events) +- [工具](#mp--utilities) + +### Util + +- [日志记录](#util--logging) +- [JSON](#util--json) +- [随机数](#util--random) +- [性能分析](#util--profiling) + +### Http + +- [HTTP 函数](#http) + +### FS + +- [检查](#fs--checks) +- [操作](#fs--operations) +- [路径](#fs--paths) + +### 事件 + +- [事件参考](#events) + +--- + +## 全局函数 + +### `print(...)` + +打印到服务器控制台,以日期、时间和`[LUA]`为前缀。 + +**参数:** + +- `...` (任意)——任何类型的值。表会连同其内容一起打印出来。 + +**用法:** + +```lua +local name = "John Doe" +print("Hello, I'm", name, "and I'm", 32) +``` + +--- + +### `printRaw(...)` + +不带任何前缀直接打印到服务器控制台。 + +**参数:** + +- `...` (任意)——任何类型的值。 + +--- + +### `exit()` + +正常关闭服务器。触发`onShutdown`事件。 + +--- + +## MP — 玩家 + +### `MP.GetPlayerCount() -> number` + +返回当前在线玩家的数量。 + +**返回:** + +- (数字)- 玩家人数。 + +--- + +### `MP.GetPlayers() -> table` + +返回所有已连接玩家的表。 + +**返回:** + +- (表)- `{[playerID] = playerName}`的映射。 + +--- + +### `MP.GetPlayerName(playerID) -> string` + +根据ID返回玩家名称。 + +**参数:** + +- `playerID` (数字)- 玩家的 ID。 + +**返回:** + +- (字符串)- 玩家名称,如果找不到则为`""` 。 + +**用法:** + +```lua +local player_id = 4 +print(MP.GetPlayerName(player_id)) +``` + +--- + +### `MP.GetPlayerIDByName(name) -> number` + +根据名称返回玩家的 ID。 + +**参数:** + +- `name` (字符串)- 玩家的名称。 + +**返回:** + +- (数字)- 玩家 ID,如果找不到则为`-1` 。 + +--- + +### `MP.GetPlayerIdentifiers(playerID) -> table` + +返回玩家的标识符,例如 IP 地址、BeamMP 论坛 ID 和 Discord ID。 + +**参数:** + +- `playerID` (数字)- 玩家的 ID。 + +**返回:** + +- (表)- 包含键`ip` 、 `beammp` 、 `discord` (仅当已链接时)的表。 +- (nil)- 如果未找到玩家。 + +**用法:** + +```lua +local player_id = 5 +print(MP.GetPlayerIdentifiers(player_id)) +-- { ip: "127.0.0.1", discord: "12345678987654321", beammp: "1234567" } +``` + +--- + +### `MP.GetPlayerRole(playerID) -> string|nil` + +返回玩家在 BeamMP 后端设置的角色。 + +**参数:** + +- `playerID` (数字)- 玩家的 ID。 + +**返回:** + +- (字符串)- 玩家的角色。 +- (nil)- 如果未找到玩家。 + +--- + +### `MP.IsPlayerConnected(playerID) -> boolean` + +返回是否已收到来自玩家的 UDP 数据包,即连接是否已完全建立。 + +**参数:** + +- `playerID` (数字)- 玩家的 ID。 + +**返回:** + +- (布尔值)- 如果完全连接, `true` 。 + +**用法:** + +```lua +local player_id = 8 +print(MP.IsPlayerConnected(player_id)) +``` + +--- + +### `MP.IsPlayerGuest(playerID) -> boolean` + +返回玩家是否为访客(未在 BeamMP 论坛注册)。 + +**参数:** + +- `playerID` (数字)- 玩家的 ID。 + +**返回:** + +- (布尔值)- 如果是访客`true` 。 + +--- + +### `MP.DropPlayer(playerID, reason?)` + +将玩家踢出服务器。 + +**参数:** + +- `playerID` (数字)- 玩家的 ID。 +- `reason` (字符串,可选)- 被踢的原因。 + +**用法:** + +```lua +function ChatHandler(player_id, player_name, message) + if string.match(message, "darn") then + MP.DropPlayer(player_id, "Profanity is not allowed") + return 1 + end +end +``` + +--- + +## MP — 车辆 + +### `MP.GetPlayerVehicles(playerID) -> table` + +返回玩家的所有车辆。 + +**参数:** + +- `playerID` (数字)- 玩家的 ID。 + +**返回:** + +- (表)- `{[vehicleID] = dataString}`的映射,其中 dataString 是原始 JSON 字符串。 +- (nil)- 如果玩家没有车辆或未被找到。 + +**用法:** + +```lua +local player_id = 3 +local player_vehicles = MP.GetPlayerVehicles(player_id) + +for vehicle_id, vehicle_data in pairs(player_vehicles) do + local start = string.find(vehicle_data, "{") + local formattedVehicleData = string.sub(vehicle_data, start, -1) + print(Util.JsonDecode(formattedVehicleData)) +end +``` + +--- + +### `MP.GetPositionRaw(playerID, vehicleID) -> table, string` + +返回车辆的当前原始位置。 + +**参数:** + +- `playerID` (数字)- 玩家的 ID。 +- `vehicleID` (number)- 车辆的 ID。 + +**返回:** + +- (表)- 包含以下键的表: `pos` 、 `rot` 、 `vel` 、 `rvel` 、 `tim` 、 `ping` 。 +- (字符串)- 如果发生错误,则显示错误信息;成功时显示空字符串。 + +**注意:** `pos` 、 `rot` 、 `vel` 、 `rvel`中的每个值都是一个表,索引为`1, 2, 3` ( `rot`的索引为`4` )。 + +**用法:** + +```lua +local player_id = 4 +local vehicle_id = 0 + +local raw_pos, error = MP.GetPositionRaw(player_id, vehicle_id) +if error == "" then + local x, y, z = table.unpack(raw_pos["pos"]) + print("X:", x, "Y:", y, "Z:", z) +else + print(error) +end +``` + +--- + +### `MP.RemoveVehicle(playerID, vehicleID)` + +移除玩家拥有的车辆。 + +**参数:** + +- `playerID` (数字)- 玩家的 ID。 +- `vehicleID` (number)- 车辆的 ID。 + +**用法:** + +```lua +local player_id = 3 +local player_vehicles = MP.GetPlayerVehicles(player_id) + +for vehicle_id, vehicle_data in pairs(player_vehicles) do + MP.RemoveVehicle(player_id, vehicle_id) +end +``` + +--- + +## MP — 通讯 + +### `MP.SendChatMessage(playerID, message, logChat?)` + +向特定玩家或所有人发送聊天消息。 + +**参数:** + +- `playerID` (数字)- 玩家的 ID, `-1`表示所有人。 +- `message` (字符串)- 消息内容。 +- `logChat` (布尔值,可选)- 是否记录到服务器日志(默认值: `true` )。 + +**注意:**此函数不返回值。 + +**用法:** + +```lua +-- To a specific player +function ChatHandler(player_id, player_name, msg) + if string.match(msg, "darn") then + MP.SendChatMessage(player_id, "Please do not use profanity.") + return 1 + end +end + +-- To everyone +MP.SendChatMessage(-1, "Hello World!") +``` + +--- + +### `MP.SendNotification(playerID, message, icon?, category?)` + +向特定玩家或所有玩家发送通知(弹出窗口)。 + +**参数:** + +- `playerID` (数字)- 玩家的 ID, `-1`表示所有人。 +- `message` (字符串)- 通知内容。 +- `icon` (字符串,可选)- 通知图标。 +- `category` (字符串,可选)- 通知类别。 + +**注意:**此函数不返回值。当仅使用 3 个参数(不指定类别)调用时,类别会自动设置为消息的值。 + +--- + +### `MP.ConfirmationDialog(playerID, title, body, buttons, interactionID, warning?, reportToServer?, reportToExtensions?)` + +向玩家发送带有按钮的确认对话框。 + +**参数:** + +- `playerID` (数字)- 玩家的 ID, `-1`表示所有人。 +- `title` (字符串)- 对话框标题。 +- `body` (字符串)- 对话框正文。 +- `buttons` (表)- 按钮数组。 +- `interactionID` (字符串)- 此交互的唯一标识符。 +- `warning` (布尔值,可选)- 显示警告样式(默认值: `false` )。 +- `reportToServer` (布尔值,可选)- 向服务器发送响应(默认值: `true` )。 +- `reportToExtensions` (布尔值,可选)- 触发本地事件(默认值: `true` )。 + +**注意:**当只使用 5 个参数调用该函数时,该函数不返回值。当使用 6-8 个参数调用该函数时,它会返回`boolean, string` 。 + +--- + +### `MP.TriggerClientEvent(playerID, eventName, data) -> boolean, string` + +将事件发送给特定客户端或所有人。 + +**参数:** + +- `playerID` (数字)- 玩家的 ID, `-1`表示所有人。 +- `eventName` (字符串)- 事件名称。 +- `data` (字符串)- 要发送的数据。 + +**返回:** + +- (布尔值)- 如果发送成功则为`true` `-1`始终为`true` 。 +- (字符串)- 如果失败,则显示错误消息。 + +--- + +### `MP.TriggerClientEventJson(playerID, eventName, data) -> boolean, string` + +与`TriggerClientEvent`相同,但接受 Lua 表并自动将其编码为 JSON。 + +**参数:** + +- `playerID` (数字)- 玩家的 ID, `-1`表示所有人。 +- `eventName` (字符串)- 事件名称。 +- `data` (表) - 要进行 JSON 编码并发送的 Lua 表。 + +**返回:** + +- (布尔值)- 成功时为`true` 。 +- (字符串)- 如果失败,则显示错误消息。 + +--- + +## MP — 事件 + +### `MP.RegisterEvent(eventName, functionName)` + +将函数注册为事件的处理程序。 + +**参数:** + +- `eventName` (字符串)- 事件名称。 +- `functionName` (字符串)- 要注册的 Lua 函数的名称。 + +**注意:**如果事件不存在,则会创建该事件。可以为同一个事件注册多个处理程序。 + +**用法:** + +```lua +function ChatHandler(player_id, player_name, msg) + if msg == "hello" then + print("Hello World!") + return 0 + end +end + +MP.RegisterEvent("onChatMessage", "ChatHandler") +``` + +--- + +### `MP.TriggerLocalEvent(eventName, ...) -> table` + +仅在当前状态下触发事件。同步。 + +**参数:** + +- `eventName` (字符串)- 事件名称。 +- `...` (任意,可选)——传递给处理程序的参数。 + +**返回:** + +- (表)- 所有处理程序的返回值表。 + +**用法:** + +```lua +local Results = MP.TriggerLocalEvent("MyEvent") +print(Results) +``` + +--- + +### `MP.TriggerGlobalEvent(eventName, ...) -> table` + +在所有状态下触发事件。异步执行。本地处理程序同步且立即运行。 + +**参数:** + +- `eventName` (字符串)- 事件名称。 +- `...` (任意,可选)- 参数。支持的类型:字符串、数字、布尔值、表。 + +**返回:** + +- (表)- 类似 Future 的对象,包含: + - `:IsDone() -> boolean` — 所有处理程序是否已完成。 + - `:GetResults() -> table` — 返回所有处理程序的值。 + +**注意:**调用这些方法时要用冒号`:`不要用句点`.` 。 + +**用法:** + +```lua +local Future = MP.TriggerGlobalEvent("MyEvent") +while not Future:IsDone() do + MP.Sleep(100) +end +local Results = Future:GetResults() +print(Results) +``` + +--- + +### `MP.CreateEventTimer(eventName, intervalMS, strategy?)` + +创建一个定时器,重复触发一个事件。 + +**参数:** + +- `eventName` (字符串)- 要触发的事件。 +- `intervalMS` (数值)- 触发之间的间隔,以毫秒为单位。 +- `strategy` (数字,可选)- `MP.CallStrategy.BestEffort` (默认值)或`MP.CallStrategy.Precise` 。 + +**注意:**不建议使用低于 25 毫秒的间隔,且服务可能无法稳定运行。 + +**用法:** + +```lua +local seconds = 0 + +function CountSeconds() + seconds = seconds + 1 +end + +MP.RegisterEvent("EverySecond", "CountSeconds") +MP.CreateEventTimer("EverySecond", 1000) +``` + +--- + +### `MP.CancelEventTimer(eventName)` + +取消已存在的事件计时器。 + +**参数:** + +- `eventName` (字符串)- 事件名称。 + +**注意:**由于异步行为,该事件在被取消之前可能会再次触发一次。 + +--- + +## MP — 工具 + +### `MP.CreateTimer() -> table` + +创建一个计时器对象,用于测量经过的时间。 + +**返回:** + +- (表)- 对象包含: + - `:GetCurrent() -> float` — 自上次开始以来经过的秒数。 + - `:Start()` — 重置计时器。 + +**用法:** + +```lua +local mytimer = MP.CreateTimer() +-- do stuff here that needs to be timed +print(mytimer:GetCurrent()) +``` + +--- + +### `MP.GetOSName() -> string` + +返回服务器操作系统的名称。 + +**返回:** + +- (字符串)- `"Windows"` 、 `"Linux"`或`"Other"` 。 + +--- + +### `MP.GetServerVersion() -> number, number, number` + +返回服务器版本。 + +**返回:** + +- (数字)- 主要 +- (数字)- 次要 +- (number)- 补丁 + +**用法:** + +```lua +local major, minor, patch = MP.GetServerVersion() +print(major, minor, patch) +``` + +--- + +### `MP.Get(configID) -> value` + +通过 ID 读取服务器配置设置。 + +**参数:** + +- `configID` (数字)- 来自`MP.Settings`的 ID。 + +**返回:** + +- (值)- 设置的当前值。 + +--- + +### `MP.Set(configID, value)` + +临时更改服务器配置设置。更改不会保存到配置文件中。 + +**参数:** + +- `configID` (数字)- 来自`MP.Settings`的 ID。 +- `value` (任意)- 新值。类型必须与设置匹配。 + +**用法:** + +```lua +MP.Set(MP.Settings.Debug, true) +``` + +--- + +### `MP.Settings` + +用于`MP.Get`和`MP.Set`设置 ID 枚举。 + +```lua +MP.Settings.Debug -- 0 (boolean) +MP.Settings.Private -- 1 (boolean) +MP.Settings.MaxCars -- 2 (number) +MP.Settings.MaxPlayers -- 3 (number) +MP.Settings.Map -- 4 (string) +MP.Settings.Name -- 5 (string) +MP.Settings.Description -- 6 (string) +MP.Settings.InformationPacket -- 7 (boolean) +``` + +--- + +### `MP.CallStrategy` + +用于`MP.CreateEventTimer`枚举。 + +```lua +MP.CallStrategy.BestEffort -- Skip trigger if previous handler hasn't finished (default) +MP.CallStrategy.Precise -- Always trigger, even if it causes the queue to build up +``` + +--- + +### `MP.Sleep(ms)` + +暂停当前​​ Lua 状态若干毫秒。 + +**参数:** + +- `ms` (数字)- 睡眠时间(以毫秒为单位)。 + +**注意:**睡眠状态下不会执行任何操作。如果注册了事件处理程序,**请勿让服务器睡眠超过 500 毫秒**——睡眠状态会显著降低整个服务器的运行速度。 + +**用法:** + +```lua +local Future = MP.TriggerGlobalEvent("MyEvent") +while not Future:IsDone() do + MP.Sleep(100) +end +``` + +--- + +### `MP.GetStateMemoryUsage() -> number` + +返回当前 Lua 状态的内存使用情况。 + +**返回:** + +- (数字)- 内存大小(以字节为单位)。 + +--- + +### `MP.GetLuaMemoryUsage() -> number` + +返回所有 Lua 状态的总内存使用量。 + +**返回:** + +- (数字)- 内存大小(以字节为单位)。 + +--- + +## Util — 日志记录 + +### `Util.LogInfo(...)` 、 `Util.LogWarn(...)` 、 `Util.LogError(...)` 、 `Util.LogDebug(...)` + +在相应级别的服务器日志中打印信息。 + +**参数:** + +- `...` (任意)——任何类型的值。 + +**注意:**仅当启用`MP.Settings.Debug`时才会显示`Util.LogDebug` 。 + +**用法:** + +```lua +Util.LogInfo("Hello, World!") +Util.LogWarn("Cool warning") +Util.LogError("Oh no!") +Util.LogDebug("hi") +``` + +--- + +## Util — JSON + +### `Util.JsonEncode(table) -> string` + +将 Lua 表编码为 JSON 字符串。 + +**参数:** + +- `table` (table) - 要编码的表。 + +**返回:** + +- (字符串)- 压缩后的 JSON 字符串。 + +**注意:**根据键类型自动检测数组还是对象。函数、用户数据和不支持的类型将被忽略。 + +**用法:** + +```lua +local player = { + name = "Lion", + age = 69, + skills = { "skill A", "skill B" } +} +local json = Util.JsonEncode(player) +-- '{"name":"Lion","age":69,"skills":["skill A","skill B"]}' +``` + +--- + +### `Util.JsonDecode(json) -> table` + +将 JSON 字符串解码为 Lua 表。 + +**参数:** + +- `json` (字符串)- 有效的 JSON 字符串。 + +**返回:** + +- (表)——解码后的表。 +- (nil)- 如果 JSON 无效。 + +**用法:** + +```lua +local json = "{\"message\":\"OK\",\"code\":200}" +local tbl = Util.JsonDecode(json) +-- { message = "OK", code = 200 } +``` + +--- + +### `Util.JsonPrettify(json) -> string` + +为 JSON 字符串添加缩进和换行符,以提高可读性(缩进为 4)。 + +**参数:** + +- `json` (字符串)- 有效的 JSON 字符串。 + +**返回:** + +- (字符串)- 美化打印的 JSON。 + +**用法:** + +```lua +local myjson = Util.JsonEncode({ name="Lion", age = 69, skills = { "skill A", "skill B" } }) +print(Util.JsonPrettify(myjson)) +``` + +--- + +### `Util.JsonMinify(json) -> string` + +从 JSON 字符串中删除不必要的空格和换行符。 + +**参数:** + +- `json` (字符串)- 有效的 JSON 字符串。 + +**返回:** + +- (字符串)- 压缩后的 JSON。 + +**用法:** + +```lua +local pretty = Util.JsonPrettify(Util.JsonEncode({ name="Lion", age = 69 })) +print(Util.JsonMinify(pretty)) +``` + +--- + +### `Util.JsonFlatten(json) -> string` + +根据 RFC 6901 将嵌套的 JSON 扁平化为`/a/b/c`样式的键。 + +**参数:** + +- `json` (字符串)- 有效的 JSON 字符串。 + +**返回:** + +- (字符串)- 扁平化的 JSON。 + +**用法:** + +```lua +local json = Util.JsonEncode({ name="Lion", skills = { "skill A", "skill B" } }) +print(Util.JsonFlatten(json)) +-- '{"/name":"Lion","/skills/0":"skill A","/skills/1":"skill B"}' +``` + +--- + +### `Util.JsonUnflatten(json) -> string` + +将扁平化的 JSON 恢复到其嵌套结构。 + +**参数:** + +- `json` (字符串)- 扁平化的 JSON 字符串。 + +**返回:** + +- (字符串)- 嵌套 JSON。 + +--- + +### `Util.JsonDiff(a, b) -> string` + +根据 RFC 6902 计算两个 JSON 字符串之间的差异。 + +**参数:** + +- `a` (字符串)- 第一个 JSON 字符串。 +- `b` (字符串)- 第二个 JSON 字符串。 + +**返回:** + +- (字符串)- 表示差异的 JSON 补丁。 + +--- + +## Util — 随机 + +### `Util.Random() -> float` + +返回一个介于 0 和 1 之间的随机浮点数。 + +**返回:** + +- (float) + +**用法:** + +```lua +local rand = Util.Random() +print("rand: " .. rand) +-- rand: 0.135477 +``` + +--- + +### `Util.RandomRange(min, max) -> float` + +返回给定范围内的随机浮点数。 + +**参数:** + +- `min` (数字)- 下限。 +- `max` (数字)- 上限。 + +**返回:** + +- (float) + +**用法:** + +```lua +local randFloat = Util.RandomRange(1, 1000) +print("randFloat: " .. randFloat) +-- randFloat: 420.6969 +``` + +--- + +### `Util.RandomIntRange(min, max) -> number` + +返回给定范围内的随机整数。 + +**参数:** + +- `min` (数字)- 下限。 +- `max` (数字)- 上限。 + +**返回:** + +- (数字)- 整数。 + +**用法:** + +```lua +local randInt = Util.RandomIntRange(1, 100) +print("randInt: " .. randInt) +-- randInt: 69 +``` + +--- + +## Util — 分析 + +### `Util.DebugStartProfile(name)` + +启动一个命名执行时间测量。 + +**参数:** + +- `name` (字符串)- 此测量的标识符。 + +--- + +### `Util.DebugStopProfile(name)` + +停止指定名称的测量。必须在调用`DebugStartProfile`之后,并使用相同的名称调用此函数。 + +**参数:** + +- `name` (字符串)- 此测量的标识符。 + +--- + +### `Util.DebugExecutionTime() -> table` + +返回每个已运行处理程序的执行时间统计信息。 + +**返回:** + +- (表)- 每个处理程序: `mean` 、 `stdev` 、 `min` 、 `max` 、 `n` (全部以毫秒为单位)。 + +**用法:** + +```lua +function printDebugExecutionTime() + local stats = Util.DebugExecutionTime() + local pretty = "DebugExecutionTime:\n" + local longest = 0 + for name, t in pairs(stats) do + if #name > longest then + longest = #name + end + end + for name, t in pairs(stats) do + pretty = pretty .. string.format("%" .. longest + 1 .. "s: %12f +/- %12f (min: %12f, max: %12f) (called %d time(s))\n", name, t.mean, t.stdev, t.min, t.max, t.n) + end + print(pretty) +end +``` + +--- + +## Http + +### `Http.CreateConnection(host, port) -> table` + +创建与外部服务器的HTTP连接。 + +**参数:** + +- `host` (字符串)- 服务器地址。 +- `port` (number)- 端口号。 + +**返回:** + +- (表)- 具有方法的连接对象`:Get(path, headers)` 。 + +--- + +### `connection:Get(path, headers)` + +发送HTTP GET请求。 + +**参数:** + +- `path` (字符串)- 请求路径。 +- `headers` (表)- 表头作为`{[string] = string}` 。 + +--- + +## FS — 检查 + +### `FS.Exists(path) -> boolean` + +返回路径是否存在。 + +**参数:** + +- `path` (字符串)- 要检查的路径。 + +**返回:** + +- (布尔值)- 如果存在`true` 。 + +--- + +### `FS.IsDirectory(path) -> boolean` + +返回指定路径是否为目录。 + +**参数:** + +- `path` (字符串)- 要检查的路径。 + +**返回:** + +- (布尔值)- 如果目录为`true` 。 + +**注意:** `false`并不意味着该路径就是一个文件。请使用`FS.IsFile`单独进行检查。 + +--- + +### `FS.IsFile(path) -> boolean` + +返回指定路径是否为普通文件。 + +**参数:** + +- `path` (字符串)- 要检查的路径。 + +**返回:** + +- (布尔值)- 如果是普通文件`true` 。 + +**注意:** `false`并不意味着该路径是一个目录。 + +--- + +## FS — 操作 + +### `FS.CreateDirectory(path) -> boolean, string` + +创建目录,包括任何缺失的父目录(类似于`mkdir -p` )。 + +**参数:** + +- `path` (字符串)- 要创建的目录的路径。 + +**返回:** + +- (布尔值)- 成功时为`true` 。 +- (字符串)- 失败时显示错误消息,成功时显示`""` 。 + +**用法:** + +```lua +local success, error_message = FS.CreateDirectory("data/mystuff/somefolder") + +if not success then + print("failed to create directory: " .. error_message) +end +``` + +--- + +### `FS.Remove(path) -> boolean, string` + +删除文件或空目录。 + +**参数:** + +- `path` (字符串)- 要删除的路径。 + +**返回:** + +- (布尔值)- 成功时为`true` 。 +- (字符串)- 失败时的错误信息。 + +--- + +### `FS.Rename(path, newPath) -> boolean, string` + +重命名或移动文件或目录。 + +**参数:** + +- `path` (字符串)- 当前路径。 +- `newPath` (字符串)- 新路径。 + +**返回:** + +- (布尔值)- 成功时为`true` 。 +- (字符串)- 失败时的错误信息。 + +--- + +### `FS.Copy(path, newPath) -> boolean, string` + +复制文件或目录(递归)。 + +**参数:** + +- `path` (字符串)- 源路径。 +- `newPath` (字符串)- 目标路径。 + +**返回:** + +- (布尔值)- 成功时为`true` 。 +- (字符串)- 失败时的错误信息。 + +--- + +### `FS.ListFiles(path) -> table` + +返回目录中的文件名列表(非递归)。 + +**参数:** + +- `path` (字符串)- 目录路径。 + +**返回:** + +- (表)- 文件名数组。 +- (nil)- 如果路径不存在。 + +**用法:** + +```lua +print(FS.ListFiles("Resources/Server/examplePlugin")) +-- { 1: "example.json", 2: "example.lua" } +``` + +--- + +### `FS.ListDirectories(path) -> table` + +返回目录内所有目录名称的列表(非递归)。 + +**参数:** + +- `path` (字符串)- 目录路径。 + +**返回:** + +- (表格)- 目录名称数组。 +- (nil)- 如果路径不存在。 + +**用法:** + +```lua +print(FS.ListDirectories("Resources")) +-- { 1: "Client", 2: "Server" } +``` + +--- + +## FS — 路径 + +### `FS.GetFilename(path) -> string` + +从指定路径返回带扩展名的文件名。 + +**参数:** + +- `path` (字符串)- 路径字符串。 + +**返回:** + +- (字符串)- 文件名。 + +**用法:** + +```lua +"my/path/a.txt" -> "a.txt" +"somefile.txt" -> "somefile.txt" +"/awesome/path" -> "path" +``` + +--- + +### `FS.GetExtension(path) -> string` + +返回包含点号的文件扩展名。 + +**参数:** + +- `path` (字符串)- 路径字符串。 + +**返回:** + +- (字符串)- 扩展名(例如`".json"` ),如果没有扩展名,则为`""` 。 + +**用法:** + +```lua +"myfile.txt" -> ".txt" +"somefile." -> "." +"/awesome/path" -> "" +"/awesome/path/file.zip.txt" -> ".txt" +``` + +--- + +### `FS.GetParentFolder(path) -> string` + +返回包含目录的路径。 + +**参数:** + +- `path` (字符串)- 路径字符串。 + +**返回:** + +- (字符串)- 父文件夹路径。 + +**用法:** + +```lua +"/var/tmp/example.txt" -> "/var/tmp" +"/" -> "/" +"mydir/a/b/c.txt" -> "mydir/a/b" +``` + +--- + +### `FS.ConcatPaths(...) -> string` + +使用系统首选分隔符将路径段连接起来,并解析存在的`..`分隔符。 + +**参数:** + +- `...` (字符串)- 路径段。 + +**返回:** + +- (字符串)- 连接路径。 + +**用法:** + +```lua +FS.ConcatPaths("a", "b", "/c/d/e/", "/f/", "g", "h.txt") +-- "a/b/c/d/e/f/g/h.txt" +``` + +--- + +## 事件 + +### 玩家连接顺序 + +``` +onPlayerAuth → onPlayerConnecting → onPlayerJoining → onPlayerJoin +``` + +--- + +### `onInit` + +插件文件全部加载完毕后立即触发。 + +**参数:**无**可取消:**否 + +--- + +### `onConsoleInput` + +当服务器控制台收到输入时触发。 + +**参数:** + +- `input` (字符串)- 输入的文本。 + +**可取消:**否 + +**用法:** + +```lua +function handleConsoleInput(cmd) + local delim = cmd:find(' ') + if delim then + local message = cmd:sub(delim+1) + if cmd:sub(1, delim-1) == "print" then + return message + end + end +end + +MP.RegisterEvent("onConsoleInput", "handleConsoleInput") +``` + +--- + +### `onShutdown` + +服务器关闭且所有玩家都被踢出后触发。 + +**参数:**无**可取消:**否 + +--- + +### `onPlayerAuth` + +当玩家尝试连接时触发,在任何其他连接事件之前触发。 + +**参数:** + +- `name` (字符串)- 玩家名称。 +- `role` (字符串)- 后端玩家角色。 +- `isGuest` (布尔值)- 玩家是否为访客。 +- `identifiers` (表) - 标识符: `ip` 、 `beammp` 、 `discord` 。 + +**可取消:**是 + +- 返回`1` — 以通用消息拒绝。 +- 返回`string` ——拒绝,拒绝理由为该字符串。 +- 返回`2` — 即使服务器已满也允许进入。 + +**用法:** + +```lua +function myPlayerAuthorizer(name, role, is_guest, identifiers) + return "Sorry, you cannot join at this time." +end + +MP.RegisterEvent("onPlayerAuth", "myPlayerAuthorizer") +``` + +--- + +### `postPlayerAuth` + +无论玩家是否被接受或拒绝,都会在`onPlayerAuth`之后触发。 + +**参数:** + +- `wasRejected` (布尔值)- 玩家是否被拒绝。 +- `reason` (字符串)- 如果被拒绝,则显示拒绝原因。 +- `name` (字符串)- 玩家名称。 +- `role` (字符串)- 玩家角色。 +- `isGuest` (布尔值)- 是否为访客。 +- `identifiers` (表)- 标识符。 + +**可取消:**否 + +--- + +### `onPlayerConnecting` + +当玩家开始连接时触发,在`onPlayerAuth`之后。 + +**参数:** + +- `playerID` (数字) + +**可取消:**否 + +--- + +### `onPlayerJoining` + +玩家完成所有模组下载后触发。 + +**参数:** + +- `playerID` (数字) + +**可取消:**否 + +--- + +### `onPlayerJoin` + +玩家完成同步并进入游戏后触发。 + +**参数:** + +- `playerID` (数字) + +**可取消:**否 + +--- + +### `onPlayerDisconnect` + +当玩家断开连接时触发。 + +**参数:** + +- `playerID` (数字) + +**可取消:**否 + +--- + +### `onChatMessage` + +当玩家发送聊天消息时触发。 + +**参数:** + +- `playerID` (数字) +- `playerName` (字符串) +- `message` (字符串) + +**可取消:**是——返回`1`可防止消息显示给任何人。 + +**用法:** + +```lua +function MyChatMessageHandler(sender_id, sender_name, message) + if message == "darn" then + return 1 + else + return 0 + end +end + +MP.RegisterEvent("onChatMessage", "MyChatMessageHandler") +``` + +--- + +### `postChatMessage` + +在`onChatMessage`之后触发。 + +**参数:** + +- `wasSent` (布尔值)- 消息是否已发送。 +- `playerID` (数字) +- `playerName` (字符串) +- `message` (字符串) + +**可取消:**否 + +--- + +### `onVehicleSpawn` + +当玩家生成新车辆时触发。 + +**参数:** + +- `playerID` (数字) +- `vehicleID` (number) +- `data` (字符串)- 包含车辆配置和位置数据的 JSON 字符串。 + +**可取消:**是——返回非`0`值可阻止生成。 + +--- + +### `postVehicleSpawn` + +在`onVehicleSpawn`之后触发。 + +**参数:** + +- `wasSpawned` (布尔值)- 车辆是否实际生成。 +- `playerID` (数字) +- `vehicleID` (number) +- `data` (字符串) + +**可取消:**否 + +--- + +### `onVehicleEdited` + +当玩家编辑现有车辆时触发。 + +**参数:** + +- `playerID` (数字) +- `vehicleID` (number) +- `data` (字符串)- 新配置的 JSON 字符串(不包含位置数据)。 + +**可取消:**是——返回非`0`值将取消编辑。 + +--- + +### `postVehicleEdited` + +在`onVehicleEdited`之后触发。 + +**参数:** + +- `wasAllowed` (布尔值)- 是否允许编辑。 +- `playerID` (数字) +- `vehicleID` (number) +- `data` (字符串) + +**可取消:**否 + +--- + +### `onVehicleDeleted` + +当车辆被删除时触发。 + +**参数:** + +- `playerID` (数字) +- `vehicleID` (number) + +**可取消:**否 + +--- + +### `onVehicleReset` + +当玩家重置车辆时触发。 + +**参数:** + +- `playerID` (数字) +- `vehicleID` (number) +- `data` (字符串)- 新位置和旋转的 JSON 字符串(不包含配置)。 + +**可取消:**否 + +--- + +### `onVehiclePaintChanged` + +当车辆油漆发生变化时触发。 + +**参数:** + +- `playerID` (数字) +- `vehicleID` (number) +- `data` (字符串)- 包含新绘制数据的 JSON 字符串。 + +**可取消:**否 + +--- + +### `onFileChanged` + +当插件目录中的文件发生更改时触发。 + +**参数:** + +- `path` (字符串)- 相对于服务器根目录的已更改文件的路径。 + +**可取消:**否 + +**注意:**服务器启动后添加的文件不会被跟踪。 diff --git a/docs/zh/FAQ/game-faq.md b/docs/zh/FAQ/game-faq.md index ae448853..97a4d248 100644 --- a/docs/zh/FAQ/game-faq.md +++ b/docs/zh/FAQ/game-faq.md @@ -10,25 +10,25 @@ ### **如何安装 BeamMP?** -有一个关于如何在Windows上安装BeamMP的完整指南,您可以在这里找到它。 +关于如何在Windows上安装BeamMP的完整指南,您可以在[这里](https://docs.beammp.com/game/getting-started/)找到它。 --- -### **BeamMP可以在BeamNG的破解版上运行吗?** +### **BeamMP可以运行在盗版或者修改版的BeamNG吗?** -BeamMP将无法与盗版或过时版本的BeamNG.drive一起工作。BeamMP支持团队不提供盗版/过期副本问题的支持。 +BeamMP 无法在盗版或旧版本的 BeamNG.drive 上运行。包括但不限于第三方插件在内的修改可能会干扰 BeamMP 的正常运行(请参阅[如何清理插件](https://github.com/Protogen187/Docs/blob/main/docs/en/FAQ/Clearing-mods.md))。
BeamMP 支持团队无法针对盗版、旧版本或其他经过修改的 BeamNG.drive 所产生的问题提供技术支持。 --- ### **BeamMP 可以在 Linux 上运行吗?** -Client在Linux上不被官方支持。但是,您可以遵循我们的[指南,了解如何在Linux](../game/getting-started/#2b-linux-installation)上使用BeamMP。 +客户端在Linux上不被官方支持。但是,您可以查看我们的[指南来了解如何在Linux上使用BeamMP](../game/getting-started/#2b-linux-installation)。 --- ### **为什么启动器被我的杀毒软件或Windows Defender标记** -由于它与网络和其他东西交互,一些防病毒程序可能会将BeamMP标记为威胁。在任何代码中都没有**病毒**。启动器、服务器和lua客户端的代码可以在[GitHub](https://github.com/BeamMP)上找到。 +由于 BeamMP 需要与网络进行交互及其他因素,部分杀毒软件可能会将其标记为威胁。但请放心,所有代码中均不含任何病毒。启动器、服务器以及 Lua 客户端的源代码均可在我们的 [GitHub](https://github.com/BeamMP) 页面上找到。 --- @@ -38,7 +38,7 @@ Client在Linux上不被官方支持。但是,您可以遵循我们的[指南 --- -## **各种各样的** +## **其他** --- diff --git a/docs/zh/FAQ/march-28-outage.md b/docs/zh/FAQ/march-28-outage.md new file mode 100644 index 00000000..d6aecb91 --- /dev/null +++ b/docs/zh/FAQ/march-28-outage.md @@ -0,0 +1,25 @@ +# 2026年3月28日 BeamMP 停机故障常见问题解答(FAQ) + +针对 2026 年 3 月 28 日开始且目前仍在持续的BeamMP停机故障的临时常见问题解答(FAQ)。 + +**最后更新于2026年4月1日** + +=== 我需要帮助!我的 BeamMP 启动器无法运行!
请尝试重新安装 BeamMP 启动器。具体操作步骤如下:

1. 访问 [beammp.com](https://beammp.com/)
2. 点击 *Download Now(立即下载)*
3. 运行安装程序并按照提示进行操作 + +``` +!!! 注意 + +截至 2026 年 4 月 1 日,Windows Defender SmartScreen 会将该 MSI 安装程序识别为“未知应用”。 + +若要跳过此警告,请点击 *更多信息*,然后点击 *仍要运行*。 +``` + +=== 我需要帮助!我的授权密钥 (authkey) 失效了!

截至 2026 年 4 月 1 日,Keymaster 和认证系统处于离线状态。这意味着您的 authkeys 将无法正常工作。若要解决此问题,请按照以下步骤操作:

1. 打开您的 ``ServerConfig.toml`` 文件,或任何存放服务器配置的地方。
2. 将 ``Private`` 设置为 ``true``。设置后应如下所示:``Private = true``。
3. 这应该能解决 authkey 的失效问题。 + +``` +!!! 注意 + +截至 2026 年 4 月 1 日,BeamMP 的认证系统处于离线状态。目前仅支持游客账号(Guest accounts)登录。 + +请确保您的服务器已开启游客访问权限。 +``` diff --git a/docs/zh/beamng/cef-snippets.md b/docs/zh/beamng/cef-snippets.md new file mode 100644 index 00000000..8dc6d15f --- /dev/null +++ b/docs/zh/beamng/cef-snippets.md @@ -0,0 +1,12 @@ +!!! warning "本页面正在建设中!" + +``` +本站点目前正处于积极开发与维护阶段。 + +觉得您可以提供帮助?请点击页面右侧的铅笔图标参与编辑! +此操作适用于站内的任何页面。 +``` + +# BeamNG.drive CEF Code 的片段 + +to-do diff --git a/docs/zh/beamng/css-snippets.md b/docs/zh/beamng/css-snippets.md new file mode 100644 index 00000000..d9d0ac06 --- /dev/null +++ b/docs/zh/beamng/css-snippets.md @@ -0,0 +1,189 @@ +!!! warning "本页面正在建设中!" + +``` +本站点目前正处于积极开发与维护阶段。 + +觉得您可以提供帮助?请点击页面右侧的铅笔图标参与编辑! +此操作适用于站内的任何页面。 +``` + +# BeamNG.drive CSS Code 的片段 + +## 常见变量 + +=== BeamNG Orange + +``` +```css +var(--bng-orange) /*Common orange*/ +var(--bng-orange-shade1) /*70% opacity*/ +var(--bng-orange-shade2) /*40% opacity*/ +var(--bng-orange-shade1opaque) +var(--bng-orange-shade2opaque) +``` +``` + +=== Monochrome + +``` +```css +--- Monochrome +var(--bng-black-8) /*80% opacity (duplicate --bng-black-o8)*/ +var(--bng-black-6) /*60% opacity (duplicate --bng-black-o6)*/ +var(--bng-black-4) /*40% opacity (duplicate --bng-black-o4)*/ +var(--bng-black-2) /*20% opacity (duplicate --bng-black-o2)*/ + +var(--dark-neutral-grey) +var(--neutral-grey) +var(--light-neutral-grey) +var(--dark-grey) +var(--dark-grey-alpha) /*80% opacity*/ + +var(--black-1) /*70% opacity*/ +var(--black-2) /*40% opacity (duplicate --bng-black-o4)*/ + +var(--white-1) /*80% opacity*/ +var(--white-2) /*40% opacity*/ +var(--white-3) /*20% opacity*/ +``` +``` + +=== BeamNG 界面颜色调色板 + +``` +=== Orange + + ```css + var(--bng-orange-50) + var(--bng-orange-100) + var(--bng-orange-200) + var(--bng-orange-300) + var(--bng-orange-b400) + var(--bng-orange-500) + var(--bng-orange-600) + var(--bng-orange-700) + var(--bng-orange-800) + var(--bng-orange-900) + ``` + +=== Cool Gray + + ```css + var(--bng-cool-gray-50) + var(--bng-cool-gray-100) + var(--bng-cool-gray-200) + var(--bng-cool-gray-300) + var(--bng-cool-gray-400) + var(--bng-cool-gray-500) + var(--bng-cool-gray-600) + var(--bng-cool-gray-700) + var(--bng-cool-gray-800) + var(--bng-cool-gray-900) + ``` + +=== Ter Blue + ```css + var(--bng-ter-blue-50) + var(--bng-ter-blue-100) + var(--bng-ter-blue-200) + var(--bng-ter-blue-300) + var(--bng-ter-blue-400) + var(--bng-ter-blue-500) + var(--bng-ter-blue-600) + var(--bng-ter-blue-700) + var(--bng-ter-blue-800) + var(--bng-ter-blue-900) + ``` + +=== Add Blue + ```css + var(--bng-add-blue-50) + var(--bng-add-blue-100) + var(--bng-add-blue-200) + var(--bng-add-blue-300) + var(--bng-add-blue-400) + var(--bng-add-blue-500) + var(--bng-add-blue-600) + var(--bng-add-blue-700) + var(--bng-add-blue-800) + var(--bng-add-blue-900) + ``` + +=== Add Green + ```css + var(--bng-add-green-50) + var(--bng-add-green-100) + var(--bng-add-green-200) + var(--bng-add-green-300) + var(--bng-add-green-400) + var(--bng-add-green-500) + var(--bng-add-green-600) + var(--bng-add-green-700) + var(--bng-add-green-800) + var(--bng-add-green-900) + ``` + +=== Add Yellow + ```css + var(--bng-add-yellow-50) + var(--bng-add-yellow-100) + var(--bng-add-yellow-200) + var(--bng-add-yellow-300) + var(--bng-add-yellow-400) + var(--bng-add-yellow-500) + var(--bng-add-yellow-600) + var(--bng-add-yellow-700) + var(--bng-add-yellow-800) + var(--bng-add-yellow-900) + ``` + +=== Add Peach + ```css + var(--bng-add-peach-50) + var(--bng-add-peach-100) + var(--bng-add-peach-200) + var(--bng-add-peach-300) + var(--bng-add-peach-400) + var(--bng-add-peach-500) + var(--bng-add-peach-600) + var(--bng-add-peach-700) + var(--bng-add-peach-800) + var(--bng-add-peach-900) + ``` + +=== Add Red + ```css + var(--bng-add-red-50) + var(--bng-add-red-100) + var(--bng-add-red-200) + var(--bng-add-red-300) + var(--bng-add-red-400) + var(--bng-add-red-500) + var(--bng-add-red-600) + var(--bng-add-red-700) + var(--bng-add-red-800) + var(--bng-add-red-900) + ``` +``` + +=== 额外颜色预设 + +``` +```css +var(--bng-filter-orange) /*Filter preset to force SVGs to use bng-orange*/ +var(--bng-black-o8) /*80% opacity*/ +var(--bng-black-o6) /*60% opacity*/ +var(--bng-black-o4) /*40% opacity*/ +var(--bng-black-o2) /*20% opacity*/ +``` +``` + +=== 圆角预设 + +``` +```css +var(--bng-corners-1) /*0.25rem*/ +var(--bng-corners-2) /*0.50rem*/ +var(--bng-corners-3) /*1.00rem*/ +``` +``` diff --git a/docs/zh/beamng/dev/modding/imgui-window-tutorial.md b/docs/zh/beamng/dev/modding/imgui-window-tutorial.md new file mode 100644 index 00000000..3c247fd1 --- /dev/null +++ b/docs/zh/beamng/dev/modding/imgui-window-tutorial.md @@ -0,0 +1,88 @@ +!!! warning "本页面正在建设中!" + +``` +本站点目前正处于积极开发与维护阶段。 + +觉得您可以提供帮助?请点击页面右侧的铅笔图标参与编辑! +此操作适用于站内的任何页面。 + +#创建 ImGui 窗口 +``` + +本页将介绍如何创建一个基础的 ImGui 窗口。 + +## 设置 + +在开始使用 ImGui 之前,需要进行一些基础设置: + +```lua +local im = ui_imgui -- 缩写以避免频繁查找。这有助于性能优化 +local imguiExampleWindowOpen = im.BoolPtr(true) +``` + +`imguiExampleWindowOpen` 将用于决定该示例窗口是否应当进行渲染。 + +## 窗口渲染 + +ImGui 窗口及其内容必须在每一个需要显示的帧中重新创建。这意味着,若要使用 ImGui,必须通过某种形式的onUpdate函数来实现。 + +```lua +local function onUpdate() + if worldReadyState == 2 then + if imguiExampleWindowOpen[0] == true then + imguiExample() + end + end +end +M.onUpdate = onUpdate +``` + +只要关卡已完全加载,且示例窗口处于应当显示的状态,这段代码就会运行一个函数来创建该示例窗口。 + +## 窗口内容 + +如果您是初次编写 ImGui,可以把ImGui看作 HTML 的亲戚: + +- `im.SetNextWindowSize(im.ImVec2(x, y), im.Cond_FirstUseEver)` 用于在尚未定义视口尺寸的情况下,对其进行初始化定义。 +- `im.Begin()` 和 `im.End()`相当于你的 `` 和 `` +- `im.Text()` 相当于你的 `

` + +```lua +local buttonPresses = 0 + +local function imguiExample() + im.SetNextWindowSize(im.ImVec2(366, 100), im.Cond_FirstUseEver) -- 准备窗口尺寸 + im.Begin("Hello World, I am a window") -- 创建一个标题为“Hello World, I am a window”的窗口 + im.Indent() -- 缩进元素(类似于内边距) + im.Text("Hello World, I am text.") -- 添加一行文本,类似于

标签 + im.SameLine() -- 与 HTML 不同,这会将下一个元素附加到上一个元素的同一行 + if im.Button("The Hello World Button") then -- 类似于