mirror of
https://github.com/BeamMP/Docs.git
synced 2026-06-17 22:32:47 +00:00
Merge branch 'main' into zh-support
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,64 @@
|
||||
# 常见问题解答
|
||||
|
||||
常见问题列表。
|
||||
|
||||
---
|
||||
|
||||
## **客户端**
|
||||
|
||||
---
|
||||
|
||||
### **如何安装 BeamMP?**
|
||||
|
||||
关于如何在Windows上安装BeamMP的完整指南,您可以在[这里](https://docs.beammp.com/game/getting-started/)找到它。
|
||||
|
||||
---
|
||||
|
||||
### **BeamMP可以运行在盗版或者修改版的BeamNG吗?**
|
||||
|
||||
BeamMP 无法在盗版或旧版本的 BeamNG.drive 上运行。包括但不限于第三方插件在内的修改可能会干扰 BeamMP 的正常运行(请参阅[如何清理插件](https://github.com/Protogen187/Docs/blob/main/docs/en/FAQ/Clearing-mods.md))。<br>BeamMP 支持团队无法针对盗版、旧版本或其他经过修改的 BeamNG.drive 所产生的问题提供技术支持。
|
||||
|
||||
---
|
||||
|
||||
### **BeamMP 可以在 Linux 上运行吗?**
|
||||
|
||||
客户端在Linux上不被官方支持。但是,您可以查看我们的[指南来了解如何在Linux上使用BeamMP](../game/getting-started/#2b-linux-installation)。
|
||||
|
||||
---
|
||||
|
||||
### **为什么启动器被我的杀毒软件或Windows Defender标记**
|
||||
|
||||
由于 BeamMP 需要与网络进行交互及其他因素,部分杀毒软件可能会将其标记为威胁。但请放心,所有代码中均不含任何病毒。启动器、服务器以及 Lua 客户端的源代码均可在我们的 [GitHub](https://github.com/BeamMP) 页面上找到。
|
||||
|
||||
---
|
||||
|
||||
### **我的游戏性能很差,我该怎么办?**
|
||||
|
||||
我们正在努力使多人游戏体验尽可能稳定。如果您已经降低了图形设置,但性能仍然很差,请考虑在玩家较少的服务器上进行游戏。当你和很多人一起玩游戏时,游戏主要是CPU受限的,所以旧的CPU(甚至是四核)在多人的情况下会受到影响。(一般经验法则:每个CPU线程1辆车)
|
||||
|
||||
---
|
||||
|
||||
## **其他**
|
||||
|
||||
---
|
||||
|
||||
### **我在哪里可以找到代码?**
|
||||
|
||||
所有源代码都可以在我们的[GitHub](https://github.com/BeamMP)上找到。在进行任何更改之前,请记住代码受我们的[使用条款](https://forum.beammp.com/t/terms-of-use-v1-0/43)和许可的约束:
|
||||
|
||||
代码 | 许可证
|
||||
--- | :-:
|
||||
服务器 | [许可证](https://github.com/BeamMP/BeamMP-Server/blob/master/LICENSE)
|
||||
启动器 | [许可证](https://github.com/BeamMP/BeamMP-Launcher/blob/master/LICENSE)
|
||||
客户端 Lua | [许可证](https://github.com/BeamMP/BeamMP/blob/development/LICENSE)
|
||||
|
||||
---
|
||||
|
||||
### **我发现了错误或漏洞,我该怎么办?**
|
||||
|
||||
如果问题与代码相关,并且您知道如何使用Github,请在[ Github ](https://github.com/BeamMP)上的相应存储库中打开一个新的“issue”。我们使用基于问题的工作流程,所以即使你已经修复了bug,也要考虑打开一个新的“Issue”,然后打开一个包含问题解决方案的“Pull Request”。更多关于贡献的信息可以在[中找到](https://github.com/BeamMP/BeamMP/blob/development/CONTRIBUTING.md)。
|
||||
|
||||
如果您没有GitHub帐户,或者您不知道如何使用GitHub,或者您有任何其他问题,您可以通过以下方式与我们联系:
|
||||
|
||||
- 如果不是敏感内容,您可以在我们的[BeamMP 论坛](https://forum.beammp.com)上创建帖子,或者您可以在我们[的官方 Discord](https://discord.gg/beammp)上报告此问题。
|
||||
- 如果信息敏感,您可以直接向我们的[Discord](https://discord.gg/beammp)上的工作人员报告问题。
|
||||
@@ -0,0 +1,25 @@
|
||||
# 2026年3月28日 BeamMP 停机故障常见问题解答(FAQ)
|
||||
|
||||
针对 2026 年 3 月 28 日开始且目前仍在持续的BeamMP停机故障的临时常见问题解答(FAQ)。
|
||||
|
||||
**最后更新于2026年4月1日**
|
||||
|
||||
=== 我需要帮助!我的 BeamMP 启动器无法运行!<br>请尝试重新安装 BeamMP 启动器。具体操作步骤如下:<br><br>1. 访问 [beammp.com](https://beammp.com/)<br>2. 点击 *Download Now(立即下载)*<br>3. 运行安装程序并按照提示进行操作
|
||||
|
||||
```
|
||||
!!! 注意
|
||||
|
||||
截至 2026 年 4 月 1 日,Windows Defender SmartScreen 会将该 MSI 安装程序识别为“未知应用”。
|
||||
|
||||
若要跳过此警告,请点击 *更多信息*,然后点击 *仍要运行*。
|
||||
```
|
||||
|
||||
=== 我需要帮助!我的授权密钥 (authkey) 失效了!<br><br>截至 2026 年 4 月 1 日,Keymaster 和认证系统处于离线状态。这意味着您的 authkeys 将无法正常工作。若要解决此问题,请按照以下步骤操作:<br><br>1. 打开您的 ``ServerConfig.toml`` 文件,或任何存放服务器配置的地方。<br>2. 将 ``Private`` 设置为 ``true``。设置后应如下所示:``Private = true``。<br>3. 这应该能解决 authkey 的失效问题。
|
||||
|
||||
```
|
||||
!!! 注意
|
||||
|
||||
截至 2026 年 4 月 1 日,BeamMP 的认证系统处于离线状态。目前仅支持游客账号(Guest accounts)登录。
|
||||
|
||||
请确保您的服务器已开启游客访问权限。
|
||||
```
|
||||
@@ -0,0 +1,12 @@
|
||||
!!! warning "本页面正在建设中!"
|
||||
|
||||
```
|
||||
本站点目前正处于积极开发与维护阶段。
|
||||
|
||||
觉得您可以提供帮助?请点击页面右侧的铅笔图标参与编辑!
|
||||
此操作适用于站内的任何页面。
|
||||
```
|
||||
|
||||
# BeamNG.drive CEF Code 的片段
|
||||
|
||||
to-do
|
||||
@@ -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*/
|
||||
```
|
||||
```
|
||||
@@ -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()`相当于你的 `<body>` 和 `</body>`
|
||||
- `im.Text()` 相当于你的 `<p></p>`
|
||||
|
||||
```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.") -- 添加一行文本,类似于 <p> 标签
|
||||
im.SameLine() -- 与 HTML 不同,这会将下一个元素附加到上一个元素的同一行
|
||||
if im.Button("The Hello World Button") then -- 类似于 <button>。点击时运行 Lua 代码
|
||||
buttonPresses = buttonPresses + 1
|
||||
end
|
||||
if buttonPresses > 0 then
|
||||
im.Text("The Hello World Button has been pressed " .. buttonPresses .. " times!")
|
||||
else
|
||||
im.Text("The Hello World Button has not been pressed.")
|
||||
end
|
||||
im.Unindent() -- 结束缩进
|
||||
im.End() -- 完成“画布”以便进行渲染
|
||||
end
|
||||
```
|
||||
|
||||
您可以添加以下函数,以便轻松切换窗口的可见性:
|
||||
|
||||
```lua
|
||||
local function toggleExampleImgui()
|
||||
imguiExampleWindowOpen[0] = not imguiExampleWindowOpen[0]
|
||||
end
|
||||
```
|
||||
|
||||
## 结果
|
||||
|
||||
<figure class="image image_resized" style="width:100%" markdown="">  </figure>
|
||||
|
||||
当The Hello World Button按钮被按下时,其下方的计数器将更新,并显示The Hello World Button按钮被按下的次数。
|
||||
|
||||
## 下载
|
||||
|
||||
本教程几乎完全基于 [StanleyDudek](https://github.com/StanleyDudek) 的 ImGui 示例模组(Mod)。您可以从[此处](../../../../assets/content/imguiExample.zip)下载该示例模组。
|
||||
@@ -0,0 +1,3 @@
|
||||
# imgui-windows.md
|
||||
|
||||
此页面需要创建。
|
||||
@@ -0,0 +1,83 @@
|
||||
!!! warning "本页面正在建设中!"
|
||||
|
||||
```
|
||||
本站点目前正处于积极开发与维护阶段。
|
||||
|
||||
觉得您可以提供帮助?请点击页面右侧的铅笔图标参与编辑!
|
||||
此操作适用于站内的任何页面。
|
||||
```
|
||||
|
||||
# BeamNG.drive ImGui Code 的片段
|
||||
|
||||
## 配置
|
||||
|
||||
### 配置 ImGui
|
||||
|
||||
```lua
|
||||
local im = ui_imgui
|
||||
```
|
||||
|
||||
### 配置 Window
|
||||
|
||||
```lua
|
||||
im.SetNextWindowSize(im.ImVec2(366, 100), im.Cond_FirstUseEver)
|
||||
```
|
||||
|
||||
### 创建 window
|
||||
|
||||
```lua
|
||||
im.Begin("Window Title") -- Create window
|
||||
im.End()
|
||||
```
|
||||
|
||||
## 一般演示
|
||||
|
||||
=== 基本格式
|
||||
|
||||
```
|
||||
```lua
|
||||
im.Text("") -- 普通文本
|
||||
im.TextWrapped("") -- 自动换行文本
|
||||
im.TextColored(im.ImVec4(0,1,0,1), "") -- 彩色文本(参数为 R,G,B,A)
|
||||
im.TextDisabled("") -- 禁用状态样式的文本(预设样式)
|
||||
|
||||
im.LabelText("", "") -- 带标签的文本
|
||||
im.BulletText("") -- 带项目符号(圆点)的文本
|
||||
im.SeparatorText("") -- 带中间文字的分隔线
|
||||
|
||||
im.Separator() -- 分隔线(在添加前可能需要换行)
|
||||
im.SameLine() -- 将下一个元素水平附加到上一个元素之后
|
||||
im.NewLine() -- 换行
|
||||
|
||||
im.Spacing() -- 微小间距(填充)
|
||||
im.Indent() -- 缩进
|
||||
im.Unindent() -- 取消缩进
|
||||
```
|
||||
```
|
||||
|
||||
=== 输入
|
||||
|
||||
```
|
||||
```lua
|
||||
im.Button("", im.ImVec2(0,0)) -- 按钮(0 = 自动适应内容大小)
|
||||
im.SmallButton("") -- 小按钮(适应内容且内边距更小)
|
||||
im.ArrowButton("", 0) -- 箭头按钮(参数1:字符串实际未被使用?参数2:0=左,1=右,2=上,3=下)
|
||||
im.InvisibleButton("", im.ImVec2(0,0), ...) -- 不可见按钮(用于 ImGui 光标定位?)
|
||||
|
||||
im.Checkbox("", im.BoolPtr(false)) -- 复选框
|
||||
|
||||
im.RadioButton1("", im.BoolPtr(false)) -- 单选框 1
|
||||
im.RadioButton2("", im.IntPtr(), 0) -- 单选框 2(参数3:0 或 1,分别代表禁用或启用状态)
|
||||
```
|
||||
```
|
||||
|
||||
=== 其他
|
||||
|
||||
```
|
||||
```lua
|
||||
im.Bullet()
|
||||
|
||||
im.ProgressBar(0.5, im.ImVec2(0,0), "") -- 进度条(参数 2:填 0 则使用默认宽度和/或高度)
|
||||
im.TextUnformatted("", "") -- 非格式化文本(第二个参数似乎会导致游戏崩溃)
|
||||
```
|
||||
```
|
||||
@@ -0,0 +1,11 @@
|
||||
# 欢迎来到 BeamNG.drive 文档
|
||||
|
||||
本文档是非官方的,由BeamMP模组团队和BeamNG社区制作。
|
||||
|
||||
## 了解文件结构
|
||||
|
||||
...
|
||||
|
||||
## 片段
|
||||
|
||||
对您可能有用的代码片段可以在这里找到: [Lua Snippets](lua-snippets.md)
|
||||
@@ -0,0 +1,346 @@
|
||||
!!! warning "本页面正在建设中!"
|
||||
|
||||
```
|
||||
本站点目前正处于积极开发与维护阶段。
|
||||
|
||||
觉得您可以提供帮助?请点击页面右侧的铅笔图标参与编辑!
|
||||
此操作适用于站内的任何页面。
|
||||
```
|
||||
|
||||
# BeamNG.drive Lua Code 的片段
|
||||
|
||||
## 世界
|
||||
|
||||
### 绘制标记&车辆检测
|
||||
|
||||
在地图上绘制标记是告知用户该处存在某种交互形式的最佳方式之一。
|
||||
|
||||
绘制标记相当简单。以下是巴士路线标记绘制方式的一个示例:
|
||||
|
||||
```lua
|
||||
local function createBusMarker(markerName)
|
||||
local marker = createObject('TSStatic')
|
||||
marker:setField('shapeName', 0, "art/shapes/interface/position_marker.dae")
|
||||
marker:setPosition(vec3(0, 0, 0))
|
||||
marker.scale = vec3(1, 1, 1)
|
||||
marker:setField('rotation', 0, '1 0 0 0')
|
||||
marker.useInstanceRenderData = true
|
||||
marker:setField('instanceColor', 0, '1 1 1 0')
|
||||
marker:setField('collisionType', 0, "Collision Mesh") -- 碰撞类型:碰撞网格
|
||||
marker:setField('decalType', 0, "Collision Mesh") -- 贴花类型:碰撞网格
|
||||
marker:setField('playAmbient', 0, "1") -- 播放环境动画
|
||||
marker:setField('allowPlayerStep', 0, "1") -- 允许玩家踏上
|
||||
marker:setField('canSave', 0, "0") -- 是否可保存
|
||||
marker:setField('canSaveDynamicFields', 0, "1") -- 是否可保存动态字段
|
||||
marker:setField('renderNormals', 0, "0") -- 渲染法线
|
||||
marker:setField('meshCulling', 0, "0") -- 网格剔除
|
||||
marker:setField('originSort', 0, "0")
|
||||
marker:setField('forceDetail', 0, "-1")
|
||||
marker.canSave = false
|
||||
marker:registerObject(markerName)
|
||||
scenetree.MissionGroup:addObject(marker)
|
||||
return marker
|
||||
end
|
||||
|
||||
-- 随后可以在循环中调用此函数来设置您的标记。
|
||||
-- 注意:您应该只在初始化设置时执行一次,而不是在每一帧都调用。
|
||||
if #markers == 0 then
|
||||
for k,v in pairs(nameMarkers) do
|
||||
local mk = scenetree.findObject(v)
|
||||
if mk == nil then
|
||||
log('I', logTag,'Creating marker '..tostring(v)) -- 正在创建标记...
|
||||
mk = createBusMarker(v)
|
||||
ScenarioObjectsGroup:addObject(mk.obj)
|
||||
end
|
||||
table.insert(markers, mk)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
这是来自 [BeamNG-FuelStations](https://github.com/BeamMP/BeamNG-FuelStations/tree/master) 的自定义标记示例:
|
||||
|
||||
```lua
|
||||
local stations = [
|
||||
{ "location": [ -778.813, 485.973, 23.46 ], "type":"gas" }, -- 燃油站
|
||||
{ "location": [ 617.164, -192.107, 53.2 ], "type":"ev" }, -- 充电站
|
||||
]
|
||||
|
||||
-- 检查实体是否在区域内
|
||||
local function IsEntityInsideArea(pos1, pos2, radius)
|
||||
return pos1:distance(pos2) < radius
|
||||
end
|
||||
|
||||
local onUpdate = function (dt)
|
||||
for k, spot in pairs(stations) do -- 遍历当前地图上的所有站点
|
||||
local bottomPos = vec3(spot.location[1], spot.location[2], spot.location[3])
|
||||
local topPos = bottomPos + vec3(0,0,2) -- 偏移向量以获得顶部位置(2米高)
|
||||
|
||||
local spotInRange = false -- 站点是否在范围内?用于颜色判定
|
||||
local spotCompatible = false -- 站点是否匹配(燃料类型)?
|
||||
|
||||
if activeVeh then -- 如果存在车辆且属于当前玩家(若在多人模式下)
|
||||
local vehPos = activeVeh:getPosition()
|
||||
|
||||
-- 检查车辆是否在站点 1.5 米范围内
|
||||
spotInRange = IsEntityInsideArea(vec3(vehPos.x, vehPos.y,vehPos.z), bottomPos, 1.5)
|
||||
|
||||
-- 检查燃料类型是否匹配
|
||||
spotCompatible = activeFuelType == "any" or spot.type == "any" or activeFuelType == spot.type
|
||||
end
|
||||
|
||||
-- 确定站点颜色:如果范围内且匹配,则使用活动颜色,否则使用非活动颜色或默认半透明白色
|
||||
local spotColor = (spotInRange and spotCompatible) and activeColorMap[spot.type] or inactiveColorMap[spot.type] or ColorF(1,1,1,0.5)
|
||||
|
||||
-- 绘制圆柱体:底部位置,顶部位置,半径,颜色
|
||||
debugDrawer:drawCylinder(bottomPos:toPoint3F(), topPos:toPoint3F(), 1, spotColor)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
## 用户界面
|
||||
|
||||
### 屏幕右上角弹出的通知
|
||||
|
||||
<figure class="image image_resized" style="width:75%" markdown="">  </figure>
|
||||
|
||||
```lua
|
||||
--guihooks.trigger('toastrMsg', {type, title, msg, config = {timeOut}})
|
||||
guihooks.trigger('toastrMsg', {type = "info", title = "Info Message:", msg = "Info Message Text Here", config = {timeOut = 5000}})
|
||||
guihooks.trigger('toastrMsg', {type = "warning", title = "Warning Message:", msg = "Warning Message Text Here", config = {timeOut = 5000}})
|
||||
guihooks.trigger('toastrMsg', {type = "error", title = "Error Message:", msg = "Error Message Text Here", config = {timeOut = 5000}})
|
||||
```
|
||||
|
||||
### 消息通知,默认显示在消息应用的屏幕左上角
|
||||
|
||||
这需要安装“消息”或“消息与任务”UI 应用。图标可以在此处找到: `ui\ui-vue\src\assets\fonts\bngIcons\svg这需要安装“消息”或“消息与任务”UI 应用。图标可以在此处找到:
|
||||
|
||||
<figure class="image image_resized" style="width:75%" markdown="">  </figure>
|
||||
|
||||
```lua
|
||||
--guihooks.trigger('Message', {msg, ttl, category, icon})
|
||||
--ui_message(msg, ttl, category, icon)
|
||||
guihooks.trigger('Message', {msg = "Message Text Here", ttl = 5.0, category = "arrow_upward", icon = "arrow_upward"})
|
||||
guihooks.trigger('Message', {msg = "Message Text Here", ttl = 5.0, category = "arrow_downward", icon = "arrow_downward"})
|
||||
guihooks.trigger('Message', {msg = "Message Text Here", ttl = 5.0, category = "flag", icon = "flag"})
|
||||
guihooks.trigger('Message', {msg = "Message Text Here", ttl = 5.0, category = "check", icon = "check"})
|
||||
guihooks.trigger('Message', {msg = "Message Text Here", ttl = 5.0, category = "check_circle", icon = "check_circle"})
|
||||
guihooks.trigger('Message', {msg = "Message Text Here", ttl = 5.0, category = "warning", icon = "warning"})
|
||||
guihooks.trigger('Message', {msg = "Message Text Here", ttl = 5.0, category = "error", icon = "error"})
|
||||
guihooks.trigger('Message', {msg = "Message Text Here", ttl = 5.0, category = "directions_car", icon = "directions_car"})
|
||||
guihooks.trigger('Message', {msg = "Message Text Here", ttl = 5.0, category = "star", icon = "star"})
|
||||
guihooks.trigger('Message', {msg = "Message Text Here", ttl = 5.0, category = "timeline", icon = "timeline"})
|
||||
guihooks.trigger('Message', {msg = "Message Text Here", ttl = 5.0, category = "save", icon = "save"})
|
||||
guihooks.trigger('Message', {msg = "Message Text Here", ttl = 5.0, category = "settings", icon = "settings"})
|
||||
```
|
||||
|
||||
### 屏幕中央大尺寸或小尺寸闪烁显示
|
||||
|
||||
<figure class="image image_resized" style="width:75%" markdown="">  </figure>
|
||||
|
||||
<figure class="image image_resized" style="width:75%" markdown="">  </figure>
|
||||
|
||||
```lua
|
||||
--guihooks.trigger('ScenarioFlashMessage', {{msg, ttl, sound, big}} ) -- requires RaceCountdown ui app
|
||||
guihooks.trigger('ScenarioFlashMessage', {{"Message", 5.0, 0, true}} )
|
||||
guihooks.trigger('ScenarioFlashMessage', {{"Message Text Here", 5.0, 0, false}} )
|
||||
|
||||
--countdown example, when all executed at once, the items are queued and will follow eachother after the previous ttl expires
|
||||
guihooks.trigger('ScenarioFlashMessage', {{"3", 1.0, "Engine.Audio.playOnce('AudioGui', 'event:UI_Countdown1')", true}})
|
||||
guihooks.trigger('ScenarioFlashMessage', {{"2", 1.0, "Engine.Audio.playOnce('AudioGui', 'event:UI_Countdown2')", true}})
|
||||
guihooks.trigger('ScenarioFlashMessage', {{"1", 1.0, "Engine.Audio.playOnce('AudioGui', 'event:UI_Countdown3')", true}})
|
||||
guihooks.trigger('ScenarioFlashMessage', {{"GO!", 3.0, "Engine.Audio.playOnce('AudioGui', 'event:UI_CountdownGo')", true}})
|
||||
|
||||
--另一个声音示例
|
||||
guihooks.trigger('ScenarioFlashMessage', {{"Teleported!", 3.0, "Engine.Audio.playOnce('AudioGui', 'event:UI_Checkpoint')", false}})
|
||||
```
|
||||
|
||||
### 屏幕中央中等尺寸持久显示
|
||||
|
||||
这需要安装实时竞赛显示UI 应用。
|
||||
|
||||
<figure class="image image_resized" style="width:75%" markdown="">  </figure>
|
||||
|
||||
```lua
|
||||
--guihooks.trigger('ScenarioRealtimeDisplay', {msg = msg} ) -- 需要安装 Race Realtime Display UI 应用
|
||||
guihooks.trigger('ScenarioRealtimeDisplay', {msg = "在此输入消息文本"} )
|
||||
-- 这些消息会持久显示,可以通过发送空字符串来清除
|
||||
-- 如果您正在运行实时数据(例如计时器、距离计算等),这是一个非常适合快速更新的接口
|
||||
guihooks.trigger('ScenarioRealtimeDisplay', {msg = ""} )
|
||||
```
|
||||
|
||||
### 确认对话框
|
||||
|
||||
确认对话框是一个带有多达两个按钮的简化弹出窗口。
|
||||
|
||||
```lua
|
||||
-- 打开一个包含标题、正文文本和最多两个按钮的确认对话框(ConfirmationDialog)
|
||||
guihooks.trigger("ConfirmationDialogOpen",
|
||||
"示例标题",
|
||||
"示例正文文本内容",
|
||||
"确定",
|
||||
"", -- 对应的 gelua 代码,此处为空字符串
|
||||
"取消",
|
||||
"" -- 对应的 gelua 代码
|
||||
)
|
||||
|
||||
-- 关闭任何具有指定标题的已打开确认对话框
|
||||
guihooks.trigger("ConfirmationDialogClose", "示例标题")
|
||||
```
|
||||
|
||||
<figure class="image image_resized" style="width:75%" markdown="">  </figure>
|
||||
|
||||
按钮的两个字段都必须为字符串类型,按钮才会显示。
|
||||
|
||||
如果提供了确定按钮,按下 *确定 / 首要操作(OK / Primary action)* 键等同于点击“确定”按钮。
|
||||
|
||||
如果提供了取消按钮,按下 *菜单(Menu)*键等同于点击取消按钮。
|
||||
|
||||
支持HTML,例如可以用来添加图片或图标。
|
||||
|
||||
可以同时显示多个,并将按顺序排列显示。
|
||||
|
||||
!!! bug
|
||||
|
||||
```
|
||||
如果不提供任何按钮,玩家将无法在不使用控制台的情况下关闭或退出该对话框。
|
||||
```
|
||||
|
||||
!!! bug
|
||||
|
||||
```
|
||||
当 ConfirmationDialog(确认对话框)处于活动状态时,迷你地图UI应用的 SDF 部分仍然保持可见。
|
||||
|
||||
可以使用 `#!lua guihooks.trigger('ShowApps', false)` 隐藏 UI 应用,作为一种临时解决方案。
|
||||
```
|
||||
|
||||
<figure class="image image_resized" style="width:75%" markdown="">  </figure>
|
||||
|
||||
### introPopupTutorial
|
||||
|
||||
introPopupTutorial 是一个高度可定制的弹出窗口,很大程度上是通过嵌入式 HTML 来定义的。通常的做法是从一个独立的 HTML 文件中进行加载,该文件位于:`/gameplay/tutorials/pages/*/content.html`.
|
||||
|
||||
```lua
|
||||
guihooks.trigger("introPopupTutorial", {
|
||||
{
|
||||
content = readFile("/gameplay/tutorials/pages/template/content.html"):gsub("\r\n",""),
|
||||
flavour = "onlyOk"
|
||||
}
|
||||
})
|
||||
|
||||
guihooks.trigger("introPopupClose")
|
||||
```
|
||||
|
||||
<figure class="image image_resized" style="width:75%" markdown="">  </figure>
|
||||
|
||||
`flavour` 控制哪些按钮会被显示。共有四种类型:
|
||||
|
||||
- `withLogbook`
|
||||
- Buttons: Career Logbook, Okay
|
||||
- `onlyOk`
|
||||
- Buttons: Okay
|
||||
- `onlyLogbook`
|
||||
- Buttons: Career Logbook
|
||||
- `noButtons`
|
||||
- 不提供任何按钮
|
||||
|
||||
!!! 警告
|
||||
|
||||
```
|
||||
如果在页面中使用noButtons类型,且页面内容中没有提供额外的 JavaScript 来关闭该弹出窗口,则会导致游戏出现Softlock。在此类型下,多个页面不会合并到同一个弹出窗口中。因此,不建议使用此类型。
|
||||
```
|
||||
|
||||
如果提供了多个页面,或者该Hook被多次触发,这些页面将合并到同一个弹出窗口中。<br>如果在一个 introPopup 处于活动状态时触发该钩子,或者已经触发了另一种不同类型的 introPopup,则它会在当前窗口关闭后,在一个独立的弹出窗口中显示。
|
||||
|
||||
### introPopupCareer
|
||||
|
||||
introPopupCareer是一种易于使用且开放式Open-ended的弹出窗口,如果需要,它还支持嵌入 HTML 内容。
|
||||
|
||||
Flavours控制显示哪些按钮以及默认的图像长宽比。共有四种类型:
|
||||
|
||||
- `default`
|
||||
- Default image aspect ratio: 16x9
|
||||
- Buttons: Later, Okay
|
||||
- `welcome`
|
||||
- Default image aspect ratio: 16x9
|
||||
- Buttons: Career Logbook, Okay
|
||||
- `branch-info`
|
||||
- Default image aspect ratio: 16x9
|
||||
- Buttons: Career Logbook, Okay
|
||||
- `garage`
|
||||
- Buttons: Later, Okay
|
||||
|
||||
```lua
|
||||
guihooks.trigger("introPopupCareer", {
|
||||
{
|
||||
title = "Example title",
|
||||
text = "Example text",
|
||||
image = "/gameplay/tutorials/pages/template/image.jpg",
|
||||
ratio = "16x9",
|
||||
flavour = "default"
|
||||
}
|
||||
})
|
||||
|
||||
guihooks.trigger("introPopupClose")
|
||||
```
|
||||
|
||||
<figure class="image image_resized" style="width:75%" markdown=""> !在 BeamNG.drive 中显示的introPopupCareer代码片段](../../assets/content/introPopupCareer.png) </figure>
|
||||
|
||||
如果提供了多个页面,或者该Hook被多次触发,这些页面将被合并到同一个弹出窗口中。<br>如果在一个introPopup处于活动状态时触发了该钩子,或者已经触发了另一种不同类型的introPopup,那么它将在当前窗口关闭后,通过一个独立的弹出窗口进行显示。
|
||||
|
||||
!!! bug
|
||||
|
||||
```
|
||||
背景模糊具有最小高度限制,这会导致内容较少的弹出窗口在其窗口下方出现多余的模糊区域。目前主要有两种解决方法:
|
||||
|
||||
* 重复输入 `\n`(换行符)并在结尾添加 `#!html <div />`,直到窗口遮住模糊区域。
|
||||
* 使用空路径或缺失的 `image` 路径,并调整长宽比(Aspect Ratio),直到窗口遮住模糊区域。
|
||||
```
|
||||
|
||||
### introPopupMission
|
||||
|
||||
introPopupMission与 introPopupCareer几乎完全相同,但它需要手动定义按钮,而不是直接为按钮选择预设样式。
|
||||
|
||||
按钮样式组合为*bng-button-*`style`。内置的按钮样式包括:
|
||||
|
||||
- `main` - 橙色
|
||||
- `secondary` - 青色
|
||||
- `attention` - 红色
|
||||
- `white` - 白色
|
||||
- `link` - 半透明
|
||||
- `outline` - 橙色轮廓
|
||||
|
||||
```lua
|
||||
guihooks.trigger('introPopupMission', {
|
||||
title = "introPopupMission title",
|
||||
text = "introPopupMission description",
|
||||
image = "/gameplay/tutorials/pages/template/image.jpg",
|
||||
ratio = "16x9",
|
||||
buttons = {
|
||||
{ default=true, class="main", label="main button", clickLua="" },
|
||||
{ default=false, class="secondary", label="secondary button", clickLua="" },
|
||||
{ default=false, class="attention", label="attention button", clickLua="" },
|
||||
{ default=false, class="white", label="white button", clickLua="" },
|
||||
{ default=false, class="link", label="link button", clickLua="" },
|
||||
{ default=false, class="outline", label="outline button", clickLua="" }
|
||||
}
|
||||
})
|
||||
|
||||
guihooks.trigger("introPopupClose")
|
||||
```
|
||||
|
||||
<figure class="image image_resized" style="width:75%" markdown="">  </figure>
|
||||
|
||||
如果提供了多个页面,或者该Hook被多次触发,这些页面将合并到同一个弹出窗口中。<br>如果在一个introPopup处于活动状态时触发了该钩子,或者已经触发了另一种不同类型的 introPopup,则它会在当前窗口关闭后,通过一个独立的弹出窗口进行显示。
|
||||
|
||||
!!! bug
|
||||
|
||||
```
|
||||
背景模糊具有最小高度限制,这会导致内容较少的弹出窗口在其窗口下方出现多余的模糊区域。目前主要有两种解决方法:
|
||||
|
||||
* 重复输入 `\n`(换行符)并在结尾添加 `#!html <div />`,直到窗口拉长并遮住模糊区域。
|
||||
* 使用空路径或缺失的 `image`(图像)路径,并调整长宽比(Aspect Ratio),直到窗口覆盖住模糊区域。
|
||||
```
|
||||
|
||||
### 对话窗口
|
||||
|
||||
todo
|
||||
+232
-11
@@ -8,17 +8,19 @@
|
||||
这也可以在任何页面上完成。
|
||||
```
|
||||
|
||||
# BeamNG.drive代码片段
|
||||
# BeamNG.drive 代码的片段
|
||||
|
||||
## Lua代码片段
|
||||
|
||||
### 绘制标记和车辆检测
|
||||
### 世界
|
||||
|
||||
#### 绘制标记和车辆检测
|
||||
|
||||
在地图中绘制标记可能是向用户表明他们可以在那里进行某种形式的交互的最佳方式之一。
|
||||
|
||||
绘制标记相当容易。以下是如何绘制公交车路线标记的示例:
|
||||
|
||||
```Lua
|
||||
```lua
|
||||
local function createBusMarker(markerName)
|
||||
local marker = createObject('TSStatic')
|
||||
marker:setField('shapeName', 0, "art/shapes/interface/position_marker.dae")
|
||||
@@ -60,7 +62,7 @@
|
||||
|
||||
以下是来自[BeamNG-FuelStations](https://github.com/BeamMP/BeamNG-FuelStations/tree/master)的自定义标记示例:
|
||||
|
||||
```Lua
|
||||
```lua
|
||||
local stations = [
|
||||
{ "location": [ -778.813, 485.973, 23.46 ], "type":"gas" },
|
||||
{ "location": [ 617.164, -192.107, 53.2 ], "type":"ev" },
|
||||
@@ -93,11 +95,11 @@
|
||||
end
|
||||
```
|
||||
|
||||
### guihooks示例
|
||||
### 用户界面
|
||||
|
||||
#### Toast通知,位于屏幕右上角
|
||||
#### 屏幕右上角弹出的通知
|
||||
|
||||

|
||||
<figure class="image image_resized" style="width:75%" markdown="">  </figure>
|
||||
|
||||
```lua
|
||||
--guihooks.trigger('toastrMsg', {type, title, msg, config = {timeOut}})
|
||||
@@ -108,10 +110,13 @@ guihooks.trigger('toastrMsg', {type = "error", title = "Error Message:", msg = "
|
||||
|
||||
#### 消息通知,消息应用程序中默认位于屏幕左上角
|
||||
|
||||

|
||||
这需要'Messages' 或 'Messages & Tasks' UI 插件。图标文件可以在以下路径中找到 `ui\ui-vue\src\assets\fonts\bngIcons\svg这需要'Messages' 或 'Messages & Tasks' UI 插件。图标文件可以在以下路径中找到
|
||||
|
||||
<figure class="image image_resized" style="width:75%" markdown="">  </figure>
|
||||
|
||||
```lua
|
||||
--guihooks.trigger('Message', {msg, ttl, category, icon}) --requires Messages app
|
||||
--guihooks.trigger('Message', {msg, ttl, category, icon})
|
||||
--ui_message(msg, ttl, category, icon)
|
||||
guihooks.trigger('Message', {msg = "Message Text Here", ttl = 5.0, category = "arrow_upward", icon = "arrow_upward"})
|
||||
guihooks.trigger('Message', {msg = "Message Text Here", ttl = 5.0, category = "arrow_downward", icon = "arrow_downward"})
|
||||
guihooks.trigger('Message', {msg = "Message Text Here", ttl = 5.0, category = "flag", icon = "flag"})
|
||||
@@ -128,7 +133,9 @@ guihooks.trigger('Message', {msg = "Message Text Here", ttl = 5.0, category = "s
|
||||
|
||||
#### 位于中心,大,小型短暂显示
|
||||
|
||||

|
||||
<figure class="image image_resized" style="width:75%" markdown="">  </figure>
|
||||
|
||||
<figure class="image image_resized" style="width:75%" markdown="">  </figure>
|
||||
|
||||
```lua
|
||||
--guihooks.trigger('ScenarioFlashMessage', {{msg, ttl, sound, big}} ) -- requires RaceCountdown ui app
|
||||
@@ -147,7 +154,9 @@ guihooks.trigger('ScenarioFlashMessage', {{"Teleported!", 3.0, "Engine.Audio.pla
|
||||
|
||||
#### 位于中心,中型持续显示
|
||||
|
||||

|
||||
这需要 **“比赛实时显示 (Race Realtime Display)”** UI 插件。
|
||||
|
||||
<figure class="image image_resized" style="width:75%" markdown="">  </figure>
|
||||
|
||||
```lua
|
||||
--guihooks.trigger('ScenarioRealtimeDisplay', {msg = msg} ) -- requires Race Realtime Display ui app
|
||||
@@ -157,6 +166,218 @@ guihooks.trigger('ScenarioRealtimeDisplay', {msg = "Message Text Here"} )
|
||||
guihooks.trigger('ScenarioRealtimeDisplay', {msg = ""} )
|
||||
```
|
||||
|
||||
#### Confirmation Dialog
|
||||
|
||||
ConfirmationDialog是一种简单的弹出窗口,最多支持两个按钮。
|
||||
|
||||
```lua
|
||||
-- -- 打开一个包含标题、正文及最多两个按钮的Confirmation Dialog
|
||||
guihooks.trigger("ConfirmationDialogOpen",
|
||||
"Example Title",
|
||||
"Example Body Text",
|
||||
"Okay",
|
||||
"", --gelua. empty string
|
||||
"Cancel",
|
||||
"" --gelua
|
||||
)
|
||||
|
||||
-- 关闭任何具有指定标题且处于打开状态的确认对话框
|
||||
guihooks.trigger("ConfirmationDialogClose", "Example Title")
|
||||
```
|
||||
|
||||
<figure class="image image_resized" style="width:75%" markdown="">  </figure>
|
||||
|
||||
按钮的两个字段都必须是字符串,该按钮才能正常显示。
|
||||
|
||||
如果提供了Okay按钮,按下 *确定 / 主要动作 (OK / Primary action)*按键的效果等同于点击确定按钮。
|
||||
|
||||
如果提供了Cancel按钮,按下*菜单 (Menu)*按键的效果等同于点击取消按钮。
|
||||
|
||||
支持HTML格式,例如可以用来添加图像或图标。
|
||||
|
||||
可以同时显示多个,并将按顺序依次呈现。
|
||||
|
||||
!!! bug
|
||||
|
||||
```
|
||||
不提供任何按钮会导致玩家在不使用控制台的情况下无法退出该对话框。
|
||||
```
|
||||
|
||||
!!! bug
|
||||
|
||||
```
|
||||
当 **ConfirmationDialog**(确认对话框)处于活动状态时,小地图 (Minimap) UI 插件的 **SDF 部分** 依然保持可见。
|
||||
|
||||
可以使用 `#!lua guihooks.trigger('ShowApps', false)` 隐藏 UI 插件,作为一种临时性的补救方案。
|
||||
```
|
||||
|
||||
<figure class="image image_resized" style="width:75%" markdown="">  </figure>
|
||||
|
||||
#### introPopupTutorial
|
||||
|
||||
introPopupTutorial 是一种高度可定制的弹出窗口,其内容主要由嵌入式 HTML 定义。标准做法是从位于`/gameplay/tutorials/pages/*/content.html`的独立 HTML 文件中进行加载。
|
||||
|
||||
```lua
|
||||
guihooks.trigger("introPopupTutorial", {
|
||||
{
|
||||
content = readFile("/gameplay/tutorials/pages/template/content.html"):gsub("\r\n",""),
|
||||
flavour = "onlyOk"
|
||||
}
|
||||
})
|
||||
|
||||
guihooks.trigger("introPopupClose")
|
||||
```
|
||||
|
||||
<figure class="image image_resized" style="width:75%" markdown="">  </figure>
|
||||
|
||||
Flavours控制显示的按钮类型。共有四种预设模式:
|
||||
|
||||
- `withLogbook`
|
||||
- Buttons: Career Logbook, Okay
|
||||
- `onlyOk`
|
||||
- Buttons: Okay
|
||||
- `onlyLogbook`
|
||||
- Buttons: Career Logbook
|
||||
- `noButtons`
|
||||
- Provides no buttons
|
||||
|
||||
!!! 警告
|
||||
|
||||
```
|
||||
当页面使用noButtons模式时,如果页面内容中未提供用于关闭弹出窗口的额外 JavaScript 代码,则会导致软锁定。在这种模式下,多个页面不会合并到同一个弹出窗口中。因此,不建议使用该模式。
|
||||
```
|
||||
|
||||
如果提供了多个页面,或者该hook被多次触发,这些页面将合并到同一个弹出窗口中。<br>如果在introPopup处于活动状态时触发钩子,或者已经触发了另一种类型的introPopup,则新内容将在现有弹出窗口关闭后,以独立的弹出窗口形式显示。
|
||||
|
||||
#### introPopupCareer
|
||||
|
||||
introPopupCareer是一种易于使用且具有高度开放性的弹出窗口,如有需要,它还支持嵌入 HTML 内容。
|
||||
|
||||
Flavours控制显示的按钮类型以及默认的图像宽高比。共有四种预设模式:
|
||||
|
||||
- `default`
|
||||
- Default image aspect ratio: 16x9
|
||||
- Buttons: Later, Okay
|
||||
- `welcome`
|
||||
- Default image aspect ratio: 16x9
|
||||
- Buttons: Career Logbook, Okay
|
||||
- `branch-info`
|
||||
- Default image aspect ratio: 16x9
|
||||
- Buttons: Career Logbook, Okay
|
||||
- `garage`
|
||||
- Buttons: Later, Okay
|
||||
|
||||
```lua
|
||||
guihooks.trigger("introPopupCareer", {
|
||||
{
|
||||
title = "Example title",
|
||||
text = "Example text",
|
||||
image = "/gameplay/tutorials/pages/template/image.jpg",
|
||||
ratio = "16x9",
|
||||
flavour = "default"
|
||||
}
|
||||
})
|
||||
|
||||
guihooks.trigger("introPopupClose")
|
||||
```
|
||||
|
||||
<figure class="image image_resized" style="width:75%" markdown=""> !在BeamNG.drive中显示的introPopupCareer代码片段](../../assets/content/introPopupCareer.png) </figure>
|
||||
|
||||
如果提供了多个页面,或者该hook被多次触发,这些页面将合并到同一个弹出窗口中。<br>如果在introPopup处于活动状态时触发了hook,或者已经触发了另一种类型的introPopup,则新内容将在当前弹出窗口关闭后,以独立的弹出窗口形式显示。
|
||||
|
||||
!!! bug
|
||||
|
||||
```
|
||||
背景模糊具有最小高度限制,这会导致内容较短的弹出窗口下方出现多余的模糊区域。目前主要有两种规避方案:
|
||||
|
||||
* 重复输入 `\n` 并以 `#!html <div />` 结尾,直到窗口完全覆盖模糊区域。
|
||||
* 使用空路径或缺失的 `image` 路径,并调整宽高比(Aspect Ratio),直到窗口覆盖模糊区域。
|
||||
```
|
||||
|
||||
#### introPopupMission
|
||||
|
||||
introPopupMission与introPopupCareer几乎完全相同,但它需要手动定义按钮,而不是直接为按钮选择Flavour的预设模式。
|
||||
|
||||
按钮样式以 *bng-button-*`style` 的格式进行组合。内置的按钮样式包括:
|
||||
|
||||
- `main` - 橙色
|
||||
- `secondary` - 青色
|
||||
- `attention` - 红色
|
||||
- `white` - 白色
|
||||
- `link` - 半透明
|
||||
- `outline` - 橙色轮廓
|
||||
|
||||
```lua
|
||||
guihooks.trigger('introPopupMission', {
|
||||
title = "introPopupMission title",
|
||||
text = "introPopupMission description",
|
||||
image = "/gameplay/tutorials/pages/template/image.jpg",
|
||||
ratio = "16x9",
|
||||
buttons = {
|
||||
{ default=true, class="main", label="main button", clickLua="" },
|
||||
{ default=false, class="secondary", label="secondary button", clickLua="" },
|
||||
{ default=false, class="attention", label="attention button", clickLua="" },
|
||||
{ default=false, class="white", label="white button", clickLua="" },
|
||||
{ default=false, class="link", label="link button", clickLua="" },
|
||||
{ default=false, class="outline", label="outline button", clickLua="" }
|
||||
}
|
||||
})
|
||||
|
||||
guihooks.trigger("introPopupClose")
|
||||
```
|
||||
|
||||
<figure class="image image_resized" style="width:75%" markdown="">  </figure>
|
||||
|
||||
如果提供了多个页面,或者该hook被多次触发,这些页面将合并到同一个弹出窗口中。<br>如果在introPopup处于活动状态时触发了hook,或者已经触发了另一种类型的introPopup,则新内容将在当前弹出窗口关闭后,以独立的弹出窗口形式显示。
|
||||
|
||||
!!! bug
|
||||
|
||||
```
|
||||
背景模糊具有最小高度限制,这会导致内容较短的弹出窗口在其窗口下方出现多余的模糊区域。目前主要有两种规避方案:
|
||||
|
||||
* 重复使用 `\n` 并以 `#!html <div />` 结尾,直到窗口高度足以覆盖模糊区域。
|
||||
* 使用空路径或缺失的 `image` 路径,并调整宽高比(Aspect Ratio),直到窗口完全覆盖模糊区域。
|
||||
```
|
||||
|
||||
#### Dialogue
|
||||
|
||||
Dialogue被用于*A Rocky Start*活动中,用于显示有关任务的信息。它是一个居中且垂直对齐的弹出窗口,具有特定的布局。它不支持嵌入 HTML。
|
||||
|
||||
```lua
|
||||
ui_missionInfo.openDialogue({
|
||||
title = "Dialogue title",
|
||||
type = "Custom", -- isn't actually displayed
|
||||
typeName = "typeName",
|
||||
data = {
|
||||
{label = "objective", value = "reward"}
|
||||
-- add more...
|
||||
},
|
||||
buttons = {
|
||||
{action = "accept", text = "Accept", cmd = ""},
|
||||
{action = 'decline',text = "Decline", cmd = ""}
|
||||
-- add more...
|
||||
}
|
||||
})
|
||||
|
||||
ui_missionInfo.closeDialogue()
|
||||
```
|
||||
|
||||
<figure class="image image_resized" style="width:75%" markdown="">  </figure>
|
||||
|
||||
同时只能显示一个Dialogue。任何现有的Dialogue都会被直接覆盖。
|
||||
|
||||
!!! info
|
||||
|
||||
```
|
||||
`#!lua ui_missionInfo.closeDialogue()` 必须使用该函数来关闭对话框。
|
||||
|
||||
请确保在按下任何按钮时都调用此函数。
|
||||
```
|
||||
|
||||
## IMGUI代码片段
|
||||
|
||||
todo
|
||||
|
||||
## CEF UI代码片段
|
||||
|
||||
todo
|
||||
|
||||
@@ -11,19 +11,23 @@ BeamMP将无法与盗版或过时版本的BeamNG.drive一起工作。
|
||||
BeamMP支持团队不提供盗版/过期副本问题的支持。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## **2. 安装**
|
||||
|
||||
### **2a. Windows 安装**
|
||||
|
||||
1. 访问[beammp.com](https://beammp.com/)并点击“Download Client”按钮。
|
||||
2. 解压`BeamMP_Installer.zip`。
|
||||
3. 运行`BeamMP_Installer.exe`并按照说明进行操作。
|
||||
4. BeamMP启动器图标应将出现在您的桌面上。如果没有,只需在Windows搜索栏中搜索“BeamMP”即可。
|
||||
5. 启动器运行后,您应该会看到一个终端窗口,随即 BeamNG.drive将自动运行。**请勿**关闭终端窗口。
|
||||
6. BeamNG启动后,在主菜单中点击`Repository`按钮,确保`multiplayerbeammp`是**唯一启用**的mod。
|
||||
7. 返回主菜单,点击“More..”和“多人模式”按钮开始多人模式。
|
||||
8. 系统将提示您登录或以访客身份游玩(并非所有服务器都允许访客)。您可以在我们的[论坛](https://forum.beammp.com)上创建一个帐户,然后使用相同的凭据登录BeamMP。
|
||||
9. 选择您感兴趣的任何服务器,然后点击`连接` 。尽情享受吧!
|
||||
!!!注意
|
||||
|
||||
```
|
||||
截至 2026 年 4 月 1 日,Windows Defender SmartScreen 会将该 MSI 安装程序识别为“未知应用”。
|
||||
|
||||
若要跳过此警告,请点击“更多信息”,然后点击“仍要运行”。
|
||||
```
|
||||
|
||||
1. 前往 [beammp.com](https://beammp.com/) 然后点击“下载”按钮
|
||||
2. 运行 `BeamMP_Installer.msi`安装程序并按照提示进行操作。
|
||||
3. BeamMP启动器的图标应该会出现在您的桌面上。如果没有出现,只需在 Windows 搜索栏中搜索“BeamMP”即可。
|
||||
|
||||
!!!注意
|
||||
|
||||
@@ -66,10 +70,10 @@ export PATH=$VCPKG_ROOT:$PATH
|
||||
|
||||
使用`git`将BeamMP-Launcher仓库克隆至本地,操作示例如下:`git clone https://github.com/BeamMP/BeamMP-Launcher.git`。[查看GitHub仓库克隆操作完整指南](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository)
|
||||
|
||||
检出[最新发布版本](https://github.com/BeamMP/BeamMP-Launcher/releases/latest)所使用的标签。例如,若最新版本使用`v2.6.4`,则执行`git checkout v2.6.4`
|
||||
|
||||
如果你使用了我们提供的示例克隆命令,你可以使用以下命令进入项目的根目录: <br>`cd BeamMP-Launcher`
|
||||
|
||||
查看用于 [最新发布版本](https://github.com/BeamMP/BeamMP-Launcher/releases/latest) 的标签(Tag)。例如,如果最新版本使用的是 `v2.8.0`,则执行命令:`git checkout v2.8.0`
|
||||
|
||||
在项目的根目录中,
|
||||
|
||||
1.
|
||||
@@ -135,9 +139,39 @@ cd ~/beammp-launcher
|
||||
若需在服务器列表(作为服务器自定义名称组成部分)或游戏内聊天中显示表情符号,您需部署包含表情符号的字形库。例如,可通过安装Windows Segoe UI 表情符号字体的 Linux 移植版实现。
|
||||
```
|
||||
|
||||
### **2d. 更新启动器**
|
||||
|
||||
如果您已经构建了启动器并想要对其进行更新:
|
||||
|
||||
```bash
|
||||
export VCPKG_ROOT="$(pwd)/vcpkg"
|
||||
cd BeamMP-Launcher
|
||||
git fetch --tags
|
||||
```
|
||||
|
||||
检出用于 [最新发布版本](https://github.com/BeamMP/BeamMP-Launcher/releases/latest) 的标签。例如,如果最新版本使用的是 `v2.8.0`,则执行 `git checkout v2.8.0`。
|
||||
|
||||
```
|
||||
cmake . -B bin -DCMAKE_TOOLCHAIN_FILE=$VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake -DVCPKG_TARGET_TRIPLET=x64-linux
|
||||
cmake --build bin --parallel
|
||||
cp bin/BeamMP-Launcher ~/beammp-launcher/
|
||||
cd ~/beammp-launcher
|
||||
./BeamMP-Launcher
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## **3. 已知的问题**
|
||||
## **3. 使用BeamMP**
|
||||
|
||||
1. 启动程序后,您应该会看到一个终端窗口。紧接着,标准的 BeamNG 启动程序也会随之启动。**请勿**关闭该终端窗口。
|
||||
2. 在 BeamNG.drive 的主菜单中,点击 `Repository(仓库)` 按钮,并检查确认 `multiplayerbeammp` 是 **唯一** 启用的插件(Mod)。
|
||||
3. 返回主菜单,点击“More..”和“多人模式”按钮开始多人模式。
|
||||
4. 系统将提示您登录或以访客身份游玩(并非所有服务器都允许访客)。您可以在我们的[论坛](https://forum.beammp.com)上创建一个帐户,然后使用相同的凭据登录BeamMP。
|
||||
5. 选择您感兴趣的任何服务器,然后点击`连接` 。尽情享受吧!
|
||||
|
||||
---
|
||||
|
||||
## **4. 已知问题**
|
||||
|
||||
- 当前原生Linux版BeamMP启动器存在单会话限制:成功连接服务器并断开后需重启启动器。可通过热重载方案实现不关闭游戏进程的快速重启
|
||||
- 若未显示多人游戏按钮,请确认以下操作:<br>检查BeamMP模组是否已安装并在模组管理器中启用<br>尝试执行热重载快捷键 Ctrl + L
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
---
|
||||
title: 指南
|
||||
description: 这组页面为BeamMP提供了一些基本指南
|
||||
status: 新的
|
||||
---
|
||||
|
||||
!!! 警告"这个网站正在建设中!"
|
||||
|
||||
```
|
||||
This site is being actively worked on.
|
||||
|
||||
Feel you could help? Please do by clicking on the page with a pencil on the right!
|
||||
|
||||
This can be done any page too.
|
||||
```
|
||||
|
||||
# BeamMP开发指南
|
||||
|
||||
本页面将是客户端和服务器内容创建的介绍和序言。
|
||||
|
||||
这一页还需要开发。
|
||||
@@ -0,0 +1,291 @@
|
||||
# 服务器端的安装
|
||||
|
||||
## **创建服务器**
|
||||
|
||||
设置服务器应用程序的基础知识
|
||||
|
||||
---
|
||||
|
||||
### **概述**
|
||||
|
||||
**创建一个家里云是免费的,但是托管一个VPS更容易也更安全**
|
||||
|
||||
服务器是BeamMP的一个组成部分;玩家通过服务器相互连接。它们在Windows和Linux上本机运行。
|
||||
|
||||
你可以制作私人服务器,只有你邀请的人才能加入,或者设置为公共服务器,显示在我们的官方服务器列表中。
|
||||
|
||||
让服务器上线运行需要经过几个步骤!如果遇到任何问题,可以随时在我们的 [论坛](https://forum.beammp.com) 或 [Discord 服务器](https://discord.gg/beammp) 的 `#support` 频道提问。更多信息也可参考 [服务器维护](server-maintenance.md) 部分。
|
||||
|
||||
请在使用服务器前务必阅读 [许可协议](https://raw.githubusercontent.com/BeamMP/BeamMP-Server/master/LICENSE)。
|
||||
|
||||
*服务器仅支持 IPv4。如果你不确定自己使用的是哪种协议,可以查看在 [*whatsmyip.org*](https://www.whatsmyip.org/) 上看到的 IP 地址——如果它包含 `:` *冒号,则为 **IPv6**。在这种情况下,你需要进一步确认自己是否也拥有 IPv4。你可以联系你的 ISP 查询,或者问问与你同住的人(如果他们懂技术,可能知道!)。计划将来支持 IPv6。**
|
||||
|
||||
## 设置服务器
|
||||
|
||||
设置包括以下步骤,您应该遵循所有步骤。
|
||||
|
||||
### **1. 端口转发**
|
||||
|
||||
!!! info
|
||||
|
||||
```
|
||||
如果你使用的是 VPS(虚拟专用服务器)、Rootserver,或者计划在本地托管服务器(与家里其他玩家在同一屋檐下),可以跳过此步骤。
|
||||
如果你希望家外的人加入你本地托管的服务器(即在本地网络之外),则必须执行此步骤。
|
||||
|
||||
!!! danger ":material-scale-balance: 免责声明:"
|
||||
|
||||
**端口转发存在风险**.
|
||||
|
||||
进行端口转发意味着你理解将家庭网络端口向公众开放的风险,因此 BeamMP 对你或你家庭可能发生的**任何和所有**损害不承担责任。
|
||||
|
||||
我们不对任何外部链接服务或网站上的内容负责。
|
||||
|
||||
因此,建议使用我们的合作服务来托管服务器!
|
||||
|
||||
*请参阅 [端口转发指南]了解详细操作(port-forwarding.md)*
|
||||
```
|
||||
|
||||
#### 合作托管服务(付费):
|
||||
|
||||
- [Horizon Hosting](https://hrzn.link/beammp)
|
||||
- [RackGenius](https://rackgeni.us/beammp-plans)
|
||||
- [Connect Hosting](https://connecthosting.net/beammp)
|
||||
- [Assetto Hosting](https://assettohosting.com/en/games/beamng)
|
||||
- [ZAP-Hosting](https://zap-hosting.com/itsbeammp)
|
||||
- [HostHavoc](https://hosthavoc.com/)
|
||||
- [PedalHost](https://pedal.host/)
|
||||
- [Vyper Hosting](https://vyperhosting.com/r/beammp)
|
||||
- [BisectHosting](https://www.bisecthosting.com/beammp-server-hosting)
|
||||
- [Four Seasons Hosting](https://fourseasonshosting.com)
|
||||
- [Vertuo Hosting](https://vertuohosting.com)
|
||||
- [Winheberg](https://winheberg.fr/offres/gaming/beammp?lang=en)
|
||||
- [Wabbanode](https://wabbanode.com/partner/beammp)
|
||||
- [Iceline Hosting](https://iceline-hosting.com/games/beammp)
|
||||
|
||||
#### 1.1 防火墙
|
||||
|
||||
根据你的设置,你可能需要允许 BeamMP-Server 通过防火墙。在 Windows 上通常需要这样操作(关闭防火墙通常 **无效**),在许多预装的 Linux 服务器上也是如此
|
||||
|
||||
在这里,你需要允许 BeamMP-Server 通过防火墙,**包括入站和出站连接**,并且 **包括 TCP 和 UDP**。如果防火墙要求指定端口,则必须使用你在步骤“1. 端口转发”中使用的相同端口(通常为 30814)。
|
||||
|
||||
如需更详细的指南,请参阅 [此文档页面](https://docs.beammp.com/FAQ/Defender-exclusions/)。<br>如果遇到问题,也欢迎随时在我们的 [论坛](https://forum.beammp.com) 或 [Discord 服务器](https://discord.gg/beammp) 的 `#support` 频道中提问。
|
||||
|
||||
### **2. 获取认证密钥**
|
||||
|
||||
‘认证密钥’,通常称为 ‘AuthKey’,是使 **公共** 服务器可以通过服务器列表访问所必需的。虽然也建议将 AuthKey 添加到私人服务器。你拥有的密钥数量有限。一个密钥一次只能用于一台服务器,因此不能用同一个密钥同时启动两台服务器。通过支持该项目可以获得更多密钥。更多信息请参阅 [这篇文章](https://docs.beammp.com/support/player-faq/)。
|
||||
|
||||
!!! 警告
|
||||
|
||||
```
|
||||
千万不要把密钥给别人看,把它当作密码!
|
||||
```
|
||||
|
||||
此步骤需要一个 [Discord](https://discord.com) 账号。此举是为了防止垃圾信息。
|
||||
|
||||
#### 2.1. 访问密钥页面
|
||||
|
||||
通过 Discord 登录至 [Keymaster](https://keymaster.beammp.com)。在 Keymaster 主页中,点击屏幕左侧的“Keys(密钥)”:
|
||||
|
||||
<figure markdown="">  </figure>
|
||||
|
||||
#### 2.2. 创建密钥
|
||||
|
||||
要创建密钥,请单击右上角的绿色“+”按钮。
|
||||
|
||||
<figure markdown="">  </figure>
|
||||
|
||||
#### 2.3. 填写关键信息
|
||||
|
||||
接下来,填写服务器名称字段(这只是密钥的名称,而不是服务器列表上显示的实际名称),然后点击“Create”。范例:
|
||||
|
||||
<figure class="image image_resized" style="width:44.84%;" markdown="">  </figure>
|
||||
|
||||
最后,它看起来应该是这样的:
|
||||
|
||||
<figure markdown="">  </figure>
|
||||
|
||||
#### 2.4. 复制密钥
|
||||
|
||||
现在复制“Key”字段中的文本,在此范例中为 `3173a2e-6az0-4542-a3p0-ddqq5ff95558`,并保存以便下一步使用。你可以点击密钥右侧的剪贴板图标来完成复制:
|
||||
|
||||
<figure markdown="">  </figure>
|
||||
|
||||
### **3. 安装**
|
||||
|
||||
BeamMP-Server适用于Windows和Linux。接下来的两节分别介绍Windows和Linux。
|
||||
|
||||
#### 3.a. 安装在Windows上
|
||||
|
||||
对于Linux安装,请参见下一步。
|
||||
|
||||
在尝试在家托管服务器之前,请确保已完成端口转发!如果端口未转发,你将无法向公众托管服务器!
|
||||
|
||||
1. 请确保已安装 [Visual C++ 可再发行组件](https://aka.ms/vs/17/release/vc_redist.x64.exe) 以运行服务器。
|
||||
2. 从 [beammp.com](https://www.beammp.com/) 下载服务器可执行文件。你将得到一个可执行文件,名称类似于 `BeamMP-Server.exe`。
|
||||
3. 下载完成后,在某个位置创建一个文件夹,并将 `BeamMP-Server.exe` 放入其中。这就是你的服务器端所在的位置。
|
||||
4. 双击启动服务器一次。这将为你生成所有必要的文件,当你看到文本输出后即可关闭并进行下一步。你应该会在 `BeamMP-Server.exe` 旁看到一个 `ServerConfig.toml` 文件。
|
||||
5. (可选)为了日后快速访问,你可以轻松为 `BeamMP-Server.exe` 创建桌面快捷方式,方法是 **[右键点击]** > **发送到** > **桌面(创建快捷方式)**。
|
||||
|
||||
现在继续进行步骤 [4. 配置](#4-configuration)。
|
||||
|
||||
#### 3.b. 在Linux上安装
|
||||
|
||||
##### 使用我们的版本(推荐)
|
||||
|
||||
此步骤适用于我们在 [此处](https://github.com/BeamMP/BeamMP-Server/releases/latest) 提供二进制文件的所有发行版。如果你使用的是其他发行版或架构,请参考下方的“从源码构建”步骤。
|
||||
|
||||
1. 请确保已安装列在 [此处](https://github.com/BeamMP/BeamMP-Server#runtime-dependencies) 的依赖项。
|
||||
2. 访问 [beammp.com](https://beammp.com/) 并点击“Download Server”按钮,你将被重定向到服务器的 Github 发布页面。
|
||||
3. 下载与你的发行版对应的正确版本。为了简便起见,今后将其称为 `BeamMP-Server-xxx`,其中 `xxx` 表示你所使用发行版的版本。
|
||||
4. 下载完成后,你应该会看到一个名为 `BeamMP-Server-xxx` 的文件,其他文件暂时可以忽略。在某个位置创建一个文件夹,并将 `BeamMP-Server-xxx` 放入其中。这就是你的服务器所在的位置。
|
||||
5. 打开终端,进入你放置 `BeamMP-Server-xxx` 的文件夹,并运行 `chmod +x BeamMP-Server-xxx`。这可以确保你有权限运行它。
|
||||
6. 运行 `./BeamMP-Server-xxx` 启动服务器一次。这将为你生成所有必要的文件,当你看到文本输出后即可关闭并进行下一步。你应该会在 `BeamMP-Server-xxx` 旁看到一个 `ServerConfig.toml` 文件。
|
||||
7. 可选)强烈建议创建一个名为 `beammpserver`(或类似名称)的用户,因为我们不建议以 root、sudo 或你的个人用户账号运行服务器。之后,你应采取措施确保服务器仅以该用户身份启动。
|
||||
|
||||
现在继续进行步骤“4. 配置”。
|
||||
|
||||
##### 从源码编译
|
||||
|
||||
除了我们在 [此处](https://github.com/BeamMP/BeamMP-Server/releases/latest) 提供二进制文件的发行版外,其他发行版也可能可用,但不在官方支持范围内。如果你想自行编译,可以从我们的 [GitHub](https://github.com/BeamMP/BeamMP-Server) 下载源码,教程可在 [此处](https://github.com/BeamMP/BeamMP-Server#build-instructions) 找到。
|
||||
|
||||
最后,确保运行一次服务器:`./BeamMP-Server`,然后继续进行下一步。
|
||||
|
||||
### **4. 配置**
|
||||
|
||||
现在你已经运行过一次服务器,它应该已经生成了一些文件,并可能出现了一两个错误。这是正常的,因为我们还没有完成。你的文件夹中应该包含以下文件:
|
||||
|
||||
<figure markdown="">  </figure>
|
||||
|
||||
它们分别是 ‘ServerConfig.toml’、‘Server.log’ 和 ‘BeamMP-Server.exe’!(根据你的设置,你可能看不到 [.toml]、[.log]、[.exe] 后缀)
|
||||
|
||||
使用文本编辑器(例如 `Notepad`)打开 `ServerConfig.toml`。你可以通过 [右键点击] → “打开方式…” 然后选择文本编辑器来完成此操作。
|
||||
|
||||
以下是一个示例配置:
|
||||
|
||||
```TOML
|
||||
[General]
|
||||
Port = 30814
|
||||
AuthKey = "auth-key"
|
||||
AllowGuests = false
|
||||
LogChat = false
|
||||
Debug = false
|
||||
IP = "::"
|
||||
Private = true
|
||||
InformationPacket = true
|
||||
Name = "Test Server"
|
||||
Tags = "Freeroam,Modded,Racing,Police"
|
||||
MaxCars = 2
|
||||
MaxPlayers = 10
|
||||
Map = "/levels/ks_nord/info.json"
|
||||
Description = "Total Random Beam MP Server"
|
||||
ResourceFolder = "Resources"
|
||||
```
|
||||
|
||||
!!! info
|
||||
|
||||
```
|
||||
这是您的配置文件。它采用了一种名为 TOML的格式。有关该文件及其变量的更多信息,请参考 [Server Maintenance(服务器维护)](server-maintenance.md) 章节。
|
||||
|
||||
只要设置了`Private = true`,您的服务器就不会出现在服务器列表中。如果您希望服务器在列表中显示,请将其设置为`Private = false`。
|
||||
```
|
||||
|
||||
目前,我们只需要关注 `AuthKey`字段。请将你在第一步中复制的AuthKey粘贴到引号 `''`之间。
|
||||
|
||||
对于我们的范例密钥,它应该是这样的:
|
||||
|
||||
```TOML
|
||||
AuthKey = '3173a2e-6az0-4542-a3p0-ddqq5ff95558'
|
||||
```
|
||||
|
||||
同时,请在`Name`字段中为您的服务器命名。您可以为其设置颜色或其他样式,具体请参考服务器维护页面中关于[名称自定义的章节](server-maintenance.md#customize-the-look-of-your-server-name)。
|
||||
|
||||
如果你选择了除 **30814** 之外的其他 **端口**,请确保在 `Port` 下进行替换。
|
||||
|
||||
### **5. 验证**
|
||||
|
||||
现在再次运行你的服务器,看看是否还会出现 `[ERROR]` 或 `[WARN]` 消息。此时服务器应该会保持开启状态。在下面的步骤(6.)中,你可以了解如何加入服务器。
|
||||
|
||||
---
|
||||
|
||||
#### 5.1 怎么添加模组到我的服务器中
|
||||
|
||||
车辆模组和地图模组的安装方式不同,但都需要将它们放入服务器的 (`Resources/Client`) 文件夹中。只需将你想添加的模组放入该文件夹即可。
|
||||
|
||||
!!! 警告
|
||||
|
||||
```
|
||||
如果在添加模组后尝试加入服务器时收到“done”或“start”消息,很可能是因为你向服务器添加了不兼容或损坏的模组。
|
||||
模组之间也可能存在不兼容的情况。如果你在客户端安装了模组,请查阅本指南
|
||||
了解如何从游戏中移除模组。
|
||||
```
|
||||
|
||||
#### 5.2 一般的模组
|
||||
|
||||
如果你只想添加带模组的车辆,只需将模组的 zip 文件放入 `Resources/Client` 文件夹。加入你服务器的任何人都会自动下载这些模组。
|
||||
|
||||
#### 5.3 地图
|
||||
|
||||
所有默认地图(非模组的地图)都可以开箱即用,无需安装。您只需在 `ServerConfig.toml` 文件中将 `Map` 设置更改为 [这些](server-maintenance.md#all-vanilla-maps-names) 中的任意一个。对于任何其他模组地图,请执行以下操作:
|
||||
|
||||
1. 将你的地图 `.zip` 文件放入服务器的 (`Resources/Client`) 文件夹中。
|
||||
2. 接下来,查看地图的 zip 文件内容(不要解压),并打开 `levels` 文件夹。在此文件夹中,应仅有一个以地图名称命名的子文件夹,例如 “myawesomedriftmap2021”。请确保 *完全按照该文件夹的名称复制或记住这个名称*。
|
||||
3. 打开你的 `ServerConfig.toml`。在 `Map` 设置中,你应该会看到 `/levels/MAPNAME/info.json`,其中 `MAPNAME` 可能类似于 `gridmap_v2`。现在,你需要将此 `MAPNAME` 替换为上一步中子文件夹的名称,在本例中是 `myawesomedriftmap2021`。最终它应像下面这样(以本例为例),并且 ***必须*** 在末尾保留 `/info.json`。
|
||||
|
||||
```TOML
|
||||
Map = '/levels/myawesomedriftmap2021/info.json'
|
||||
```
|
||||
|
||||
现在,当有人加入你的服务器时,地图应会自动下载并正常运行。
|
||||
|
||||
**如果这不起作用**,请在你的单人模式 BeamNG.drive 中安装该地图,启动并进入地图。然后,通过按 `~`(*波浪号*)键打开控制台(如果你使用非美式键盘,请在 **选项 > 控制 > 绑定** 菜单的 **通用调试** 部分中查看 **切换系统控制台** 的操作),并运行 `print(getMissionFilename())`。这样就会显示你需要使用的地图名称。
|
||||
|
||||
就这样!你添加的模组地图现在应该可以加入了!
|
||||
|
||||
### **6. 怎么加入你的服务器**
|
||||
|
||||
你和其他玩家如何加入你的服务器。
|
||||
|
||||
#### 6.a. 加入您自己的服务器(私有和公共)
|
||||
|
||||
如果你的服务器与游戏运行在同一台电脑上,你必须通过直接连接加入服务器。为此,请在服务器列表左侧点击 **Direct Connect Tab**。保持默认信息(应为 127.0.0.1 及对应端口),然后点击连接。
|
||||
|
||||
如果你的服务器托管在本地网络中的另一台电脑上,你必须找到该电脑的本地 IP,并使用该本地 IP 进行直接连接。
|
||||
|
||||
如果你的服务器托管在家外(例如 VPS),你必须找到该机器的 [公网 IP](https://whatismyipaddress.com/) 并通过该方式进行直接连接。
|
||||
|
||||
#### 6.b. 其他人加入您的私人服务器
|
||||
|
||||
你必须将服务器的公网 IP 地址提供给其他用户。但请注意,不要随意将你的公网 IP 地址分享给陌生人!要加入你的私人服务器,玩家必须在 BeamMP 中进入 **Direct Connect Tab**,然后输入你的 IP 和端口。
|
||||
|
||||
#### 6.c. 其他人加入您的公共服务器
|
||||
|
||||
若要加入您的公开服务器,其他玩家只需前往服务器列表,输入服务器名称并点击连接即可。如果您不确定自己的服务器名称,请查看您在 `ServerConfig.toml`中填写的名称。<br>如果找不到服务器,请确保已禁用所有搜索过滤器,并将地图设置为“全部”。您也可以前往 [Keymaster](https://keymaster.beammp.com/) 网站查看服务器的 IP 地址。
|
||||
|
||||
如果你或你的朋友遇到“Connection Failed!”错误,请查看启动器窗口中的代码,如 10060、10061、10030。这意味着你要么使用了 CGNAT IPv4,要么在步骤 **1 端口转发** 或 **1.1 防火墙** 中操作有误。要检查是否使用 CGNAT IPv4,请在路由器界面上查看 WAN IP 地址,并将其与你的 [公网 IP](https://www.whatsmyip.org/) 进行比较。如果两者相同,则表示你不在 CGNAT 后面。IPv6 支持尚未 **实现**。
|
||||
|
||||
### **7. 如何检查您的BeamMP-Server的连通性**
|
||||
|
||||
在下方输入服务器的公网 IPv4 和端口,然后点击“CheckBeamMP”。
|
||||
|
||||
<form action="https://check.beammp.com/api/v2/beammp" method="get" target="_blank">
|
||||
<label for="ip">IP 地址:</label>
|
||||
<input type="text" id="ip" name="ip"><br>
|
||||
<label for="port">端口:</label>
|
||||
<input type="text" id="port" name="port"><br>
|
||||
<input type="submit" value="CheckBeamMP">
|
||||
</form>
|
||||
|
||||
!!! warning "我想使用 RadminVPN、Hamachi 或类似的 VPN。"
|
||||
|
||||
```
|
||||
BeamMP 不支持这些 VPN,因为它们经常引发问题。其中一个问题是 UDP 流量无法转发。要解决此问题,请参考第 1 节。
|
||||
|
||||
!!! question "那为什么以前可以用?"
|
||||
|
||||
这是因为这些应用程序的开发者更新了软件并实施了 BeamMP 无法控制的更改。
|
||||
是否支持像 BeamMP-Server 这样的特定使用场景,由这些应用程序的开发者决定。
|
||||
```
|
||||
|
||||
## 还有问题吗?
|
||||
|
||||
在 [论坛](https://forum.beammp.com) 或我们的 [Discord 服务器](https://discord.gg/beammp) 的 `#support` 频道中发起一个讨论帖。
|
||||
@@ -21,6 +21,7 @@ AuthKey | 认证密钥格式为`xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`,其中所
|
||||
AllowGuests | true/false | 决定游客是否可以加入服务器。
|
||||
LogChat | true/false | 当启用(设置为“true”)时,聊天消息会被记录在 server.log 文件中。
|
||||
Debug | true /false | 当启用(true)时,将在日志中显示更多消息并提供更多信息。如果遇到问题,请启用此选项。启用此选项将显著增加日志文件的大小。
|
||||
IP | 连接到主机的其中一个网卡(NIC)的本地分类地址。(默认值:"0.0.0.0" 或 "::") | 服务器将尝试绑定到所提供的 IP。除非您清楚自己在做什么,否则请勿随意修改IP字段。此数值无需更改即可使服务器正常运行。
|
||||
Private | true/false | 当启用(true)时,您的服务器将不会显示在服务器列表中。任何拥有正确IP地址和端口的人仍然可以连接。
|
||||
InformationPacket | true/false | 当启用(true)时,服务器将允许未经身份验证的客户端直接通过服务器获取与服务器列表中相同的信息。
|
||||
Name | Any "text" | 在服务器列表中显示为您的服务器名称/标题。您可以使用特殊字符来为其添加颜色和样式。
|
||||
|
||||
Reference in New Issue
Block a user