More work!!!

This commit is contained in:
Starystars67
2026-06-27 00:49:53 +01:00
parent 97a7aaf643
commit c115bc9a42
302 changed files with 28263 additions and 10 deletions
@@ -0,0 +1,45 @@
::: warning "这个网站正在建设中!"
```
这个网站正在积极建设中。
觉得你能帮上忙吗?请用铅笔在右侧点击页面!
这也可以在任何页面上完成。
```
# 模组/游戏内脚本参考
BeamMP允许您创建自己的客户端插件。我们提供了一些功能,你可以用它来与其他多人模式和其他玩家通过服务器进行通信。
# 函数列表
脚本可用函数列表:
函数 | 说明
--- | ---
`TriggerServerEvent("eventName", "data")` | 在服务器lua环境中触发事件,两个参数都是字符串。
`TriggerClientEvent("eventName", "data")` | 在本地lua环境中触发事件,两个参数都是字符串。有利于插件之间的通信。
`AddEventHandler("eventName", Function)` | 当`eventName`被接收时(本地或从服务器),`function`将获得1个参数,一个包含事件数据的字符串。
# 代码片段
例如,使用包含的`ChatMessageIncluded`事件解析聊天,如下所示:
```lua
local function chatReceived(msg) -- Receive event with parameters
print("chat received: "..msg)
local i = string.find(s, ":") -- Find where our first ':' is, used to separate the sender and message
if i == nil then
print("error parsing message: separator could not be found!")
return -- Could not find separator, cancel function
end
print("index of separator: "..tostring(i))
local sender = string.sub(msg, 1, i-1) -- Substring our input to separate its 2 parts
local message = string.sub(msg, i+1, -1) -- Do whatever you want to with the message
print("sender: " .. sender)
print("message: ".. message)
end
AddEventHandler("ChatMessageReceived", chatReceived) -- Add our event handler to the list managed by BeamMP
```
@@ -0,0 +1,45 @@
::: warning "这个网站正在建设中!"
```
这个网站正在积极建设中。
觉得你能帮上忙吗?请用铅笔在右侧点击页面!
这也可以在任何页面上完成。
```
# 模组/游戏内脚本参考
BeamMP允许您创建自己的客户端插件。我们提供了一些功能,你可以用它来与其他多人模式和其他玩家通过服务器进行通信。
# 函数列表
脚本可用函数列表:
函数 | 说明
--- | ---
`TriggerServerEvent("eventName", "data")` | 在服务器lua环境中触发事件,两个参数都是字符串。
`TriggerClientEvent("eventName", "data")` | 在本地lua环境中触发事件,两个参数都是字符串。有利于插件之间的通信。
`AddEventHandler("eventName", Function)` | 当`eventName`被接收时(本地或从服务器),`function`将获得1个参数,一个包含事件数据的字符串。
# 代码片段
例如,使用包含的`ChatMessageIncluded`事件解析聊天,如下所示:
```lua
local function chatReceived(msg) -- Receive event with parameters
print("chat received: "..msg)
local i = string.find(s, ":") -- Find where our first ':' is, used to separate the sender and message
if i == nil then
print("error parsing message: separator could not be found!")
return -- Could not find separator, cancel function
end
print("index of separator: "..tostring(i))
local sender = string.sub(msg, 1, i-1) -- Substring our input to separate its 2 parts
local message = string.sub(msg, i+1, -1) -- Do whatever you want to with the message
print("sender: " .. sender)
print("message: ".. message)
end
AddEventHandler("ChatMessageReceived", chatReceived) -- Add our event handler to the list managed by BeamMP
```
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,385 @@
::: warning "这个网站正在建设中!"
```
这个网站正在积极建设中。
觉得你能帮上忙吗?请用铅笔在右侧点击页面!
这也可以在任何页面上完成。
```
# 服务器脚本参考
## 服务器端版本 2.X
::: warning
```
BeamMP 服务器版本 2.X 已不再提供支持。
本文档仅供参考。
请更新到最新版本以进行维护和支持。
```
---
> 这是 2.x 的脚本,仅当你的服务器端版本是老的/过时的(version 2.x.x), 时才能使用此方法,有关最新文档,请参见 [这里](https://docs.beammp.com/scripting/server/latest-server-reference)。 {.is-warning}
### 说明
要在服务器控制台中获得函数的输出,必须将其包装在`print()`语句中。例如:`print(GetPlayerName(0))`将返回服务器上第一个玩家的名字。
`<PlayersServerID>` 从0开始。
### 用于编写脚本的可用函数列表
#### GetPlayerName(playersServerID)
以字符串形式返回玩家的Discord名称
```lua
function onPlayerJoin(playerID)
local name = GetPlayerName(playerID)
-- Do something
end
```
#### GetPlayerDiscordID(playersServerID)
以字符串形式返回玩家的Discord名称
```lua
function onPlayerJoin(playerID)
local name = GetPlayerDiscordID(playerID)
-- Do something
end
```
#### GetPlayerHWID(playersServerID)
以字符串形式返回玩家的Discord ID
```lua
function onPlayerJoin(playerID)
local name = GetPlayerHWID(playerID)
-- Do something
end
```
#### GetPlayerVehicles(playersServerID)
返回玩家的车辆作为一个对象/数组
```lua
function onChatMessage(playerID, senderName, message)
local vehicleList = GetPlayerVehicles(playerID)
for vehicleID, vehicleData in pairs(vehicleList) do
-- Do something
-- Could also be used to check how many vehicles a player have
end
end
```
#### DropPlayer(playersServerID)
断开特定玩家的连接。“其实就是踢出玩家”
```lua
function onVehicleSpawn(playerID, vehicleID, vehicleData)
-- Do something
DropPlayer(playerID)
end
```
#### SendChatMessage(playersServerID, message)
通过网络向指定的用户发送消息。每个人都用-1
```lua
function onPlayerJoin(playerID)
SendChatMessage(-1, "Someone just joined!")
end
```
#### CancelEvent() -- DEPRECIATED
取消事件的发生。这可能很快就会发生。使用`return 1`来取消事件。
#### onInit()
如果在lua文件中声明,它将在c++成功加载当前lua文件后被调用
```lua
function onInit()
print("Server ready")
end
```
#### exit()
将关闭服务器
```lua
function onInit()
print("Server Ready. But who needs a server which is running")
exit() -- Stops the server
end
```
#### CreateThread(functionName, callInterval)
将在专用线程上执行该函数,它将每秒运行callInterval数次。它每秒钟都会跑一次。
```lua
function yourFunction()
for i = 1,10 do
SendChatMessage(-1, "Countdown: "..i)
Sleep(1000)
end
end
CreateThread("yourFunction", 30)
```
已弃用示例:将在专用线程上执行该函数
```lua
function yourFunction()
for i = 1,10 do
SendChatMessage(-1, "Countdown: "..i)
Sleep(1000)
end
end
CreateThread("yourFunction", 30)
```
#### StopThread(functionName)
将停止尝试调用当前脚本的线程函数
```lua
function yourFunction()
delayExpired = false
Sleep(10000)
delayExpired = true
end
CreateThread("yourFunction", 30)
-- Do something
if not delayExpired then
StopThread("yourFunction")
else
-- Do something
end
```
#### Sleep(millisecs) - DEPRECIATED
将暂停执行指定的时间(警告,如果没有创建线程,将暂停整个服务器)
```lua
function countdown()
for i = 1,10 do
SendChatMessage(-1, "Countdown: "..i)
Sleep(1000)
end
end
CreateThread("countdown", 10)
```
#### GetPlayerCount()
将返回多少玩家连接
```lua
function onPlayerJoin(playerID)
SendChatMessage(playerID, "You are the "..GetPlayerCount().."th player!"
end
```
#### RemoveVehicle(playerServerID, VehicleID)
这会导致一辆载具消失。
```lua
function onVehicleSpawn(playerID, vehicleID, vehicleData)
if --[[ Vehicle data equal something it shouldn't be ]] then
RemoveVehicle(playerID, vehicleIID)
end
end
```
#### GetPlayers()
将返回一个带有name的id表
```lua
local function onPlayerJoin(joinedPlayerID)
local players = GetPlayers()
for playerID, playerName in pairs(players) do
if playerID == joinedPlayerID then
-- Do something
end
end
end
```
#### RegisterEvent(eventName, functionName)
将该函数注册到指定的事件,都必须是字符串。
```lua
function anyEvent()
-- Do something
end
RegisterEvent("onAnyEventHappen", "anyEvent")
-- Do something
TriggerLocalEvent("onAnyEventHappen")
```
#### TriggerLocalEvent(eventName)
将调用同一插件文件夹中的每个注册函数。
```lua
function anyEvent()
-- Do something
end
RegisterEvent("onAnyEventHappen", "anyEvent")
-- Do something
TriggerLocalEvent("onAnyEventHappen")
```
#### TriggerGlobalEvent(eventName)
将使用此事件名称调用每个已注册的函数。
```lua
-- File A
function anyEvent()
-- Do something
end
RegisterEvent("onAnyEventHappen", "anyEvent")
```
```lua
-- File B
TriggerGlobalEvent("onAnyEventHappen")
```
#### TriggerClientEvent(playerServerID, eventName, data)
将使用给定的数据在指定的客户端(-1 表示广播)上触发该事件。
```lua
function onPlayerJoin(playerServerID)
TriggerClientEvent(playerServerID, "anyEvent", "You just joined the server")
end
RegisterEvent("onAnyEventHappen", "anyEvent")
```
#### Set(configID, newValue)
会将配置设置修改为下方表格中指定的新值。
```lua
function onChatMessage(playerID, senderName, message)
if playerID == adminPlayer then
if message == --[[ anything ]] then
Set(3, 10)
end
end
end
```
#### 可用于 `Set()` 命令的配置项列表
> Note that these will not save to the config file.
Config ID | 名称 | 只接受以下内容
--- | --- | ---
`0` | 调试设置 | true 或 false
`1` | 私人设置 | true 或 false
`2` | 每个玩家的最大车辆数 | 数字
`3` | 最大玩家数 | 数字
`4` | 地图 | 字符串
`5` | 名称 | 字符串
`6` | 描述 | 字符串
任何其他ID都会导致控制台警告 | |
### 用于编写脚本的可用事件列表
#### 默认事件
如何使用事件的示例:
```lua
function onInit()
RegisterEvent("onPlayerJoin", "onPlayerJoin")
end
function onPlayerJoin(playerServerID)
-- Do something
end
```
如果你不希望访客进入你的服务器:
```lua
function onInit()
print("noGuests Ready")
RegisterEvent("onPlayerAuth","onPlayerAuth")
end
function onPlayerAuth(name, role, isGuest)
if isGuest then
return "You must be signed in to join this server!"
end
end
```
事件 | 参数 | 描述
--- | --- | ---
`onPlayerAuth` | 玩家的名称、论坛角色、是否为访客账号(布尔值) | 有一名玩家已通过验证并正在请求加入。
`onPlayerConnecting` | 玩家的ID | 玩家正在加载(在加载地图之前)
`onPlayerJoining` | 玩家的ID | 玩家正在加载地图,很快就会加入
`onPlayerJoin` | 玩家的ID | 玩家已加入并加载
`onPlayerDisconnect` | 玩家的ID | 玩家退出了游戏
`onChatMessage` | 发消息的玩家的ID、昵称和聊天消息 | 发送了一条聊天消息。这对于创建命令系统非常有用
`onVehicleSpawn` | 玩家ID,车辆ID和车辆数据 | 当有人刷出一辆车时输出
`onVehicleEdited` | 玩家ID,车辆ID和车辆数据 | 当有人编辑车辆或替换现有车辆时,就会调用此操作
`onVehicleDeleted` | 玩家的ID和车辆ID | 当某人删除自己拥有的车辆时,就会调用此操作
#### 自定义事件
可以创建自定义事件以供自己使用。这与默认值的处理方式非常相似。
如何使用自定义事件的范例:
```lua
function onInit()
RegisterEvent("myCustomEvent", "myCustomEvent")
end
function myCustomEvent(playerServerID, customData)
-- Do something
end
```
接着可以使用各自的函数从客户端或服务器端调用该函数。
### 玩家
当玩家连接到你的服务器时,他们会被分配一个从 0 开始递增的 serverID。<br>serverID 会被重复利用;如果玩家离开后再次加入,他们不会获得新的 serverID,而是会被分配一个当前可用的 serverID。<br>当服务器重新启动时,serverID 会被重置。
#### 静态标识符
BeamMP 中的玩家拥有 3 个可通过其 serverID 获取的静态标识符,分别是他们的名称、discordID,以及硬件IDHWID)。<br>(尽管最后一个尚未实现,但在此处我们将假设它已实现。)<br>这三种 ID 类型各自具有不同的来源,以及在玩家识别用途上的优点和缺点。
ID 类型 | 优点 | 缺点 | 获取的函数
--- | --- | --- | :-:
name | 容易获得,直截了当 | 不安全 | GetPlayerName()
discordID | 非常安全 | 不方便 | GetPlayerDiscordID()
HWID | 超级安全 | 难获得 | GetPlayerHWID()
### 车辆
BeamMP 中的车辆有 3 个服务器会关注的属性:车辆所属者的 serverID、车辆的 vehicleID 以及车辆的数据。<br>所属者的 serverID 很简单,它就是玩家的 serverID。每辆车也有一个 vehicleID,但 vehicleID 并不是车辆唯一的;来自不同玩家的两辆车可能拥有相同的 vehicleID。<br>与 serverID 不同,vehicleID 会被重复使用。例如,如果我有 4 辆车,它们的 ID 分别是 0、1、2 和 3。如果我删除 vehicleID 为 2 的车辆,我就只剩下 0、1 和 3。当我生成一辆新车时,这辆新车会占用 ID 2。<br>最后,车辆的第三个属性是 data。data 包含车辆名称、部件以及其他数据,顾名思义。data 是以原始 JSON 字符串存储的,因此你需要使用 JSON 库来解析它,或者你也可以手动逐步解析字符串,提取所需的信息。
@@ -0,0 +1,75 @@
# 开始
为了开始开发BeamMP,你至少需要:
- 安装在本地的BeamNG.drive
- 安装在本地的BeamMP; 至少是启动器,另外还有服务器
- 安装在本地的Git, 和一个 GitHub.com 账号
- 一个代码编辑器, 例如VSCode或notepad++
---
# 模组,启动器和服务器之间的区别
BeamMP分为三个主要部分:
- 该模组与游戏中的其他载具模组或界面模组相同,均通过BeamNG引擎加载运行。其核心功能包括与启动器建立本地通信链路,以及渲染多人联机界面组件。技术架构方面,主体逻辑采用Lua脚本语言实现,界面层则基于JavaScript、HTML与CSS的复合式开发框架进行构建。相关代码仓库详见[https://github.com/BeamMP/BeamMP](https://github.com/BeamMP/BeamMP)。
- 本启动器核心功能集包括:与模组维持持续通信、在需要时建立目标服务器连接,以及通过BeamMP后端系统执行用户登录认证流程。该程序基于C++语言开发,部署前已由BeamMP团队完成预编译处理,完整源代码参见[https://github.com/BeamMP/BeamMP-Launcher](https://github.com/BeamMP/BeamMP-Launcher)。
- 服务端核心功能涵盖:与多个启动器实例建立通信链路、向BeamMP后端系统发送"心跳"信号同步IP/端口/版本/玩家数量等运行参数,并管理与调度服务端Lua插件运行。底层架构基于C++语言实现,已由BeamMP针对多操作系统平台及CPU指令集进行预编译生成,完整源码仓库位于[https://github.com/BeamMP/BeamMP-Server](https://github.com/BeamMP/BeamMP-Server)。
---
# 配置适用于模组开发的运行环境
## 为BeamNG使用未打包文件
为实现BeamNG模组开发的高效迭代,建议开发者采用`非打包目录`的实时更新工作流模式,避免每次代码变更后执行重复的压缩打包操作。
请通过文件管理器访问BeamNG用户目录:`%appdata%/Local/BeamNG.drive/0.xx/mods`,其中`xx`对应当前最新的BeamNG版本号。在`mods`目录内创建名为`unpacked`的专用开发文件夹。
有关用户目录的技术规范细则,请参阅BeamNG官方文档中心:[https://documentation.beamng.com/support/userfolder/](https://documentation.beamng.com/support/userfolder/)
## 在BeamMP启动器中启用开发模式
为防止自动更新机制覆盖本地Git仓库副本,请通过添加运行参数`--no-download`强制停用该功能;若需同时禁止启动器自动运行BeamNG主程序,并获取实时调试日志,推荐配置方案为附加开发调试参数`--dev`
命令行参数 | 说明
:-- | :--
`--help` or `-h` | 该指令将输出下列标准化参数清单
`--port <port>` or `-p` | 请将服务端默认监听端口修改为`<port>`,该项变更需同时在游戏客户端内进行同步配置。
`--verbose` or `-v` | 详细日志模式,输出调试级系统信息
`--no-download` | 强制禁用BeamMP Lua模组自动部署流程
`--no-update` | 激活维护模式锁定更新通道(需采用手动升级方式)
`--no-launch` | 强制解耦启动器与游戏进程链路(需进行独立启动流程)
`--dev` | 开发者模式,与 --verbose --no-download --no-launch --no-update相同
`--game <args...>` or `-- <args...>` | 实现运行参数向游戏进程的透传桥接
## 执行仓库克隆操作至目标解压目录
虽然您可手动从GitHub仓库(a0)https://github.com/BeamMP/BeamMP复制BeamMP模组文件,但强烈建议使用Git版本控制系统进行规范操作。请首先执行分叉(fork)操作。
最有效的方式是直接将存储库克隆到`unpacked`文件夹中。
`git`环境配置下,请遵循以下部署流程:<br>从`解压根目录`启动PowerShell/CMD终端<br>执行克隆操作:`git clone https://github.com/yourName/BeamMP`
现在试试开发模式吧。启动BeamMP启动器,手动启动BeamNG,一旦进入游戏,确保BeamMP是唯一有效的模组。你应该能够像往常一样使用BeamMP。
使用代码编辑器,您现在可以直接在`unpacked`文件夹中添加或更改代码。然后你可以通过按`Ctrl+L`重新加载Lua来尝试更改(如果你做了UI更改,则按`F5`)。
一旦您对更改满意,就可以通过git提交它们。有关如何使用Git的教程和文档,请参阅Git- scm网站。一旦您的更改被提交并推送(到您的分支),您就可以发出拉取请求。
如果您遇到任何问题,请在[Discord](https://discord.gg/beammp)的#scripting频道中提问
---
# 设置本地服务器
在使用BeamMP时,使用本地服务器可能是有益的。您可以遵循常规的[服务器安装](../../server/create-a-server.md),同时省略纯本地连接的前两个步骤。
`serverConfig`中将服务器设置为私有。使用任意字符串作为`AuthKey`
---
# 贡献指南
有关代码格式、提交信息格式、通用开发最佳实践等详细信息,请参阅各仓库中的`CONTRIBUTING.md`文件。该文件包含更详细的贡献指南,各仓库中的`README.md`文件通常也会提供具体的构建步骤说明(针对需要编译的项目)。
+21
View File
@@ -0,0 +1,21 @@
---
title: 指南
description: 这组页面为BeamMP提供了一些基本指南
status: 新的
---
::: warning "这个网站正在建设中!"
```
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,101 @@
# 创建多人模式
## 文件夹结构和基础文件
基本的文件夹和文件结构应该是这样的:
```
Resources/
├─ Client/
│ └─ examplePlugin.zip/
│ ├─ scripts/
│ │ └─ modScript.lua
│ └─ lua/
│ └─ ge/
│ └─ extensions/
│ └─ examplePlugin.lua
└─ Server/
└─ examplePlugin/
├─ examplePlugin.lua
└─ further_lua/
└─ further.lua
```
服务器端lua是最基本的,如果您想添加自定义事件,您还至少需要一个客户端lua以及一个modscript.lua
Server目录需创建多个子文件夹存放各服务端模组。推荐只在根目录保留一个主Lua文件,新增的Lua文件可归类到对应子目录。实际使用中不必严格遵循此规范,若同一层级存在多个Lua文件时,服务器会按文件名称的字母表顺序自动加载。
Client目录专门存放将发送给客户端的ZIP格式模组包,当客户端接收后会自动以模组形式加载。该目录若存在其他类型文件会导致服务器启动时报错(但不会阻断服务运行),不过这些无关文件仅会被服务端忽略。核心配置脚本modScript.lua由BeamNG游戏引擎解析,用于指引游戏加载指定插件模块。
:::范例 "" [Download the examplePlugin.zip](../../../../assets/content/ResourcesForExamplePlugin.zip)
## 服务器端 lua
更多完整示例可参考examplePlugin模块的实现,现提供一个基础调试示例,实例的功能是显示玩家身份标识
```lua
function onInit() --runs when plugin is loaded
MP.RegisterEvent("onPlayerAuth", "onPlayerAuth") --Provided by BeamMP
print("examplePlugin loaded")
end
--A player has authenticated and is requesting to join
--The player's name (string), forum role (string), guest account (bool), identifiers (table -> ip, beammp)
function onPlayerAuth(player_name, role, isGuest, identifiers)
local ip = identifiers.ip
local beammp = identifiers.beammp or "N/A"
print("onPlayerAuth: player_name: " .. player_name .. " | role: " .. role .. " | isGuest: " .. tostring(isGuest) .. " | identifiers: ip: " .. ip .. " - beammp: " .. beammp)
end
```
`onPlayerAuth`会在玩家尝试加入时触发,详细信息请参考脚本文档中的[onPlayerAuth条目](../../../scripting/server/latest-server-reference/#onplayerauth)
以下是使用onPlayerAuth的另一个示例,该示例将通过向客户端返回信息来禁止游客加入服务器,返回的信息会直接显示给玩家:
```lua
function onPlayerAuth(playerName, playerRole, isGuest, identifiers)
if isGuest then
return "No guests allowed, please use a BeamMP account"
end
end
```
关于BeamMP服务端函数的详细信息请查阅[最新版服务端技术文档](../../../scripting/server/latest-server-reference.md)
## 客户端 lua
该实现主要遵循[BeamNG扩展模块](https://documentation.beamng.com/modding/programming/extensions/)的技术规范。
```lua
local M = {}
if extensions.isExtensionLoaded("examplePlugin") then
log("E", "examplePlugin", "examplePlugin loaded on client side")
return
end
return M
```
终端输出提示:examplePlugin已完成加载。
建议查阅[BeamNG调试输出官方文档](https://documentation.beamng.com/modding/programming/debugging/#a-add-a-log)获取详细说明
## modScript.lua
通常只包含两行
```lua
load('examplePlugin')
setExtensionUnloadMode('examplePlugin', 'manual')
```
如果你想在日志中看到你的modScript被BeamNG处理,你可以添加一个日志打印
```lua
load('examplePlugin')
setExtensionUnloadMode('examplePlugin', 'manual')
log('I', 'modScript', "examplePlugin loaded")
```