Translate latest-server-reference.md via GitLocalize

This commit is contained in:
TheHawk
2026-03-26 22:22:36 +00:00
committed by gitlocalize-app[bot]
parent 38cf27e694
commit 14d46efbd0

View File

@@ -8,7 +8,7 @@
Это можно сделать на любой странице.
```
# Справочник по серверным скриптам
# Справочник по Серверным Скриптам
## Версия сервера 3.X
@@ -16,13 +16,13 @@
Выпуск BeamMP-Server v3.0.0 вносит радикальные изменения в работу системы плагинов Lua. Нет возможности использовать старый lua с новым сервером, поэтому вам придется мигрировать.
Система плагинов сервера использует [Lua 5.3](https://www.lua.org/manual/5.3/) . В этом разделе подробно описывается, как начать писать плагины, изучаются некоторые базовые концепции и начинается работа с вашим первым плагином. **Рекомендуется прочитать этот раздел, даже если вы знакомы с системой до версии 3.0.0, так как некоторые вещи кардинально изменились** .
Система плагинов сервера использует [Lua 5.3](https://www.lua.org/manual/5.3/). В этом разделе подробно описывается, как начать писать плагины, изучаются некоторые базовые концепции и начинается работа с вашим первым плагином. **Рекомендуется прочитать этот раздел, даже если вы знакомы с системой до версии 3.0.0, так как некоторые вещи кардинально изменились**.
Руководство по миграции с lua до версии 3.0.0 см. в разделе [«Миграция со старой версии Lua»](#migrating-from-old-lua) .
Руководство по миграции с lua до версии 3.0.0 см. в разделе [«Миграция со старой версии Lua»](#migrating-from-old-lua).
### Структура каталога
Серверные плагины, в отличие от модов, располагаются (по умолчанию) в `Resources/Server` , тогда как моды, которые пишутся для BeamNG.drive и отправляются клиентам, находятся в `Resources/Client` . Каждый плагин должен иметь свою собственную подпапку в `Resources/Server` , например, для плагина с именем "MyPlugin" структура будет следующей:
Серверные плагины, в отличие от модов, располагаются (по умолчанию) в `Resources/Server`, тогда как моды, которые пишутся для BeamNG.drive и отправляются клиентам, находятся в `Resources/Client`. Каждый плагин должен иметь свою собственную подпапку в `Resources/Server`, например, для плагина с именем "MyPlugin" структура будет следующей:
```
Resources
@@ -35,13 +35,13 @@ Resources
Здесь мы также отображаем другой плагин под названием "SomeOtherPlugin", чтобы проиллюстрировать, как ваша папка `Resources/Server` может иметь несколько различных папок плагинов. Мы продолжим использовать эту структуру каталогов в качестве примера на протяжении всего этого руководства.
Вы также заметите `main.lua` . У вас может быть столько файлов Lua `.lua` , сколько вам нужно. Все файлы Lua в главном каталоге вашего плагина загружаются в *алфавитном порядке* (поэтому `aaa.lua` запускается перед `bbb.lua` ).
Вы также заметите `main.lua`. У вас может быть столько файлов Lua `.lua`, сколько вам нужно. Все файлы Lua в главном каталоге вашего плагина загружаются в *алфавитном порядке* (поэтому `aaa.lua` запускается перед `bbb.lua`).
### Файлы Lua
Каждый файл Lua `.lua` в папке плагина загружается при запуске сервера. Это означает, что операторы вне функций оцениваются («запускаются») немедленно.
Файлы Lua в подпапках игнорируются, но могут быть `require()` .
Файлы Lua в подпапках игнорируются, но могут быть `require()`.
Например, наш `main.lua` выглядит так:
@@ -53,7 +53,7 @@ end
print("What's up!")
```
Когда сервер запустится и загрузится `main.lua` , он *немедленно* запустит `print("What's up!")` , но пока **НЕ** *вызовет* функцию `PrintMyName` (потому что она не была вызвана)!
Когда сервер запустится и загрузится `main.lua`, он *немедленно* запустит `print("What's up!")`, но пока **НЕ** *вызовет* функцию `PrintMyName` (потому что она не была вызвана)!
### События
@@ -81,7 +81,7 @@ MP.RegisterEvent("onChatMessage", "MyChatMessageHandler")
Это фактически гарантирует, что любое сообщение, которое в точности равно "darn", не будет отправлено и не будет показано в чате (обратите внимание, что для настоящего фильтра ненормативной лексики вам нужно будет проверить, *содержит* ли сообщение "darn", а не *является* ли оно "darn"). Отмена события приводит к тому, что оно не происходит, например, сообщение чата не будет показано никому другому, транспортное средство не будет создано и т. д.
### Пользовательские события
### Пользовательские События
Вы можете зарегистрироваться на любое понравившееся вам мероприятие, например:
@@ -125,11 +125,11 @@ MP.CreateEventTimer("EverySecond", 1000)
Это приведет к тому, что "CountSeconds" будет вызываться каждую секунду. Вы также можете отменить таймеры событий с помощью `MP.CancelEventTimer` (см. справочник API).
С консоли сервера вы можете запустить `status` , чтобы увидеть, сколько таймеров событий запущено в данный момент, а также информацию об ожидающих обработчиках событий. Эта команда покажет больше информации в будущем.
С консоли сервера вы можете запустить `status`, чтобы увидеть, сколько таймеров событий запущено в данный момент, а также информацию об ожидающих обработчиках событий. Эта команда покажет больше информации в будущем.
### Отладка
Lua трудно отлаживать. К сожалению, для встроенного Lua не существует отладчика промышленного уровня, такого как `gdb` .
Lua трудно отлаживать. К сожалению, для встроенного Lua не существует отладчика промышленного уровня, такого как `gdb`.
В общем случае вы, конечно, можете в любое время просто `print()` значения, которые хотите проверить.
@@ -147,9 +147,9 @@ Lua трудно отлаживать. К сожалению, для встро
lua @MyPlugin>
```
Как видите, мы перешли в состояние Lua для `MyPlugin` . С этого момента и до тех пор, пока мы не войдем в `exit()` (с версии 3.1.0 `:exit` ), мы будем в `MyPlugin` и сможем выполнить Lua там.
Как видите, мы перешли в состояние Lua для `MyPlugin`. С этого момента и до тех пор, пока мы не войдем в `exit()` (с версии 3.1.0 `:exit`), мы будем в `MyPlugin` и сможем выполнить Lua там.
Например, если у нас есть глобальный объект с именем `MyValue` , мы можем вывести это значение следующим образом:
Например, если у нас есть глобальный объект с именем `MyValue`, мы можем вывести это значение следующим образом:
```
lua @MyPlugin> print(MyValue)
@@ -159,13 +159,13 @@ lua @MyPlugin> print(MyValue)
Начиная с версии 3.1.0: Вы можете нажать клавишу TAB для автодополнения функций и переменных.
ВНИМАНИЕ: К сожалению, если состояние Lua в данный момент занято выполнением другого кода (например, цикла `while` ), это может полностью повесить консоль до тех пор, пока она не завершит эту работу, поэтому будьте очень осторожны, переключаясь на состояния, которые могут ожидать чего-то.
ВНИМАНИЕ: К сожалению, если состояние Lua в данный момент занято выполнением другого кода (например, цикла `while`), это может полностью повесить консоль до тех пор, пока она не завершит эту работу, поэтому будьте очень осторожны, переключаясь на состояния, которые могут ожидать чего-то.
Кроме того, вы можете запустить `status` в обычной консоли ( `>` ), которая покажет вам, среди прочего, некоторую статистику о Lua.
Кроме того, вы можете запустить `status` в обычной консоли (`> `), которая покажет вам, среди прочего, некоторую статистику о Lua.
### Пользовательские команды
### Пользовательские Команды
Для реализации пользовательских команд для консоли сервера можно использовать событие `onConsoleInput` . Это может быть полезно, когда вы хотите добавить способ для владельца сервера подать сигнал на ваш плагин или отобразить внутреннее состояние пользовательским способом.
Для реализации пользовательских команд для консоли сервера можно использовать событие `onConsoleInput`. Это может быть полезно, когда вы хотите добавить способ для владельца сервера подать сигнал на ваш плагин или отобразить внутреннее состояние пользовательским способом.
Вот пример:
@@ -190,7 +190,7 @@ MP.RegisterEvent("onConsoleInput", "handleConsoleInput")
hello, world
```
Мы реализовали собственную `print` . В качестве упражнения попробуйте создать функцию, подобную `say` , которая отправляет сообщение чата всем игрокам или даже конкретному игроку (с помощью `MP.SendChatMessage` ).
Мы реализовали собственную `print`. В качестве упражнения попробуйте создать функцию, подобную `say`, которая отправляет сообщение чата всем игрокам или даже конкретному игроку (с помощью `MP.SendChatMessage`).
**Внимание:** для ваших собственных плагинов обычно рекомендуется "пространство имен". Наш пример `print` в плагине с именем `mystuff` может называться `mystuff.print` или `ms.print` или что-то подобное.
@@ -198,11 +198,11 @@ hello, world
Формат документации: `function_name(arg_name: arg_type, arg_name: arg_type) -> return_types`
### Встроенные функции
### Встроенные Функции
#### `print(...)` , `printRaw(...)`
#### `print(...)`, `printRaw(...)`
Выводит сообщение на консоль сервера с префиксом `[DATE TIME] [LUA]` . Если вам не нужен этот префикс, вы можете использовать `printRaw(...)` .
Выводит сообщение на консоль сервера с префиксом `[DATE TIME] [LUA]`. Если вам не нужен этот префикс, вы можете использовать `printRaw(...)`.
Пример:
@@ -217,15 +217,15 @@ print("Hello, I'm", name, "and I'm", 32)
#### `exit()`
Корректно завершает работу сервера. Вызывает срабатывание события `onShutdown` .
Корректно завершает работу сервера. Вызывает срабатывание события `onShutdown`.
### Функции МП
#### `MP.CreateTimer() -> Timer`
Создает объект таймера, который можно использовать для отслеживания того, сколько времени заняло что-то / сколько времени прошло. Он запускается после создания и может быть сброшен/перезапущен с помощью `mytimer:Start()` .
Создает объект таймера, который можно использовать для отслеживания того, сколько времени заняло что-то / сколько времени прошло. Он запускается после создания и может быть сброшен/перезапущен с помощью `mytimer:Start()`.
Текущее прошедшее время в секундах можно получить с помощью `mytimer:GetCurrent()` .
Текущее прошедшее время в секундах можно получить с помощью `mytimer:GetCurrent()`.
Пример:
@@ -239,11 +239,11 @@ print(mytimer:GetCurrent()) -- print how much time elapsed
#### `MP.GetOSName() -> string`
Возвращает имя текущей ОС: `Windows` , `Linux` или `Other` .
Возвращает имя текущей ОС: `Windows`, `Linux` или `Other`.
#### `MP.GetServerVersion() -> number,number,number`
Возвращает текущую версию сервера в формате major, minor, patch. Например, версия v3.0.0 вернет `3, 0, 0` .
Возвращает текущую версию сервера в формате major, minor, patch. Например, версия v3.0.0 вернет `3, 0, 0`.
Пример:
@@ -260,13 +260,13 @@ print(major, minor, patch)
#### `MP.RegisterEvent(event_name: string, function_name: string)`
Запоминает функцию с именем Имя `Function Name` как обработчик события с именем `Event Name` .
Запоминает функцию с именем Имя `Function Name` как обработчик события с именем `Event Name`.
Вы можете зарегистрировать столько обработчиков события, сколько захотите.
Список событий, предоставляемых сервером, можно посмотреть [здесь](#events-1) .
Список событий, предоставляемых сервером, можно посмотреть [здесь](#events-1).
Если событие с таким именем не существует, оно создается, и, таким образом, RegisterEvent не может завершиться неудачей. Это можно использовать для создания пользовательских событий. Подробнее см. в разделах [Пользовательские события](#custom-events) и [События](#events) .
Если событие с таким именем не существует, оно создается, и, таким образом, RegisterEvent не может завершиться неудачей. Это можно использовать для создания пользовательских событий. Подробнее см. в разделах [Пользовательские события](#custom-events) и [События](#events).
Пример:
@@ -285,7 +285,7 @@ MP.RegisterEvent("onChatMessage", "ChatHandler")
Запускает таймер внутри сервера, который запускает событие `event_name` каждые `interval_ms` миллисекунд.
Таймеры событий можно отменить с помощью `MP.CancelEventTimer` .
Таймеры событий можно отменить с помощью `MP.CancelEventTimer`.
Интервалы <25 мс не рекомендуются, так как несколько таких интервалов, скорее всего, не будут обслуживаться вовремя надежно. Хотя несколько таймеров могут быть запущены для одного и того же события, рекомендуется создавать как можно меньше таймеров событий. Например, если вам нужно одно событие, которое запускается каждые полсекунды, и одно, которое запускается каждую секунду, рассмотрите возможность создания просто события каждые полсекунды и запуска триггера every-second-functiosecond.
@@ -296,7 +296,7 @@ MP.RegisterEvent("onChatMessage", "ChatHandler")
Необязательный `CallStrategy` может быть указан в качестве третьего аргумента. Это может быть:
- `MP.CallStrategy.BestEffort` (по умолчанию): попытается запустить событие с указанным интервалом, но откажется ставить обработчики в очередь, если выполнение обработчика займет слишком много времени.
- `MP.CallStrategy.Precise` : будет ставить обработчики событий в очередь с точным указанным интервалом. Может привести к заполнению очереди, если обработчику требуется больше времени, чем интервал. Используйте только если вам НУЖЕН точный интервал.
- `MP.CallStrategy.Precise`: будет ставить обработчики событий в очередь с точным указанным интервалом. Может привести к заполнению очереди, если обработчику требуется больше времени, чем интервал. Используйте только если вам НУЖЕН точный интервал.
#### `MP.CancelEventTimer(event_name: string)`
@@ -308,7 +308,7 @@ MP.RegisterEvent("onChatMessage", "ChatHandler")
Запускает локальное событие, которое приводит к вызову всех обработчиков этого события *в текущем состоянии lua* (обычно в текущем плагине, если состояние не было передано через PluginConfig.toml).
Вы можете передать этой функции аргументы ( `...` ), которые копируются и отправляются всем обработчикам как аргументы функции.
Вы можете передать этой функции аргументы (`...`), которые копируются и отправляются всем обработчикам как аргументы функции.
Этот вызов является синхронным и вернет управление после завершения всех обработчиков событий.
@@ -327,16 +327,16 @@ print(Results)
Запускает глобальное событие, которое приводит к вызову всех обработчиков этого события *во всех плагинах* (включая *этот* плагин).
Вы можете передать этой функции аргументы ( `...` ), которые копируются и отправляются всем обработчикам как аргументы функции.
Вы можете передать этой функции аргументы (`...`), которые копируются и отправляются всем обработчикам как аргументы функции.
Этот вызов асинхронный и возвращает объект, подобный будущему. Локальные обработчики (обработчики в том же плагине, что и вызывающий) запускаются синхронно и немедленно.
Возвращаемая таблица имеет две функции:
- `IsDone() -> boolean` сообщает, все ли обработчики завершились. Вы можете подождать, пока это не станет правдой, проверив это и `MP.Sleep` -ing на некоторое время в цикле.
- `IsDone() -> boolean` сообщает, все ли обработчики завершились. Вы можете подождать, пока это не станет правдой, проверив это и `MP.Sleep`-ing на некоторое время в цикле.
- `GetResults() -> table` возвращает неаннотированную неименованную таблицу со всеми возвращаемыми значениями всех обработчиков. Это практически массив.
Обязательно вызывайте их с помощью синтаксиса `Obj:Function()` ( `:` , NOT `.` ).
Обязательно вызывайте их с помощью синтаксиса `Obj:Function()` (`:`, NOT `.`).
Пример:
@@ -362,9 +362,9 @@ print(Results)
#### `MP.SendChatMessage(player_id: number, message: string)`
Отправляет сообщение чата, которое может видеть только указанный игрок (или все, если идентификатор `-1` ). В игре это не будет отображаться как направленное сообщение.
Отправляет сообщение чата, которое может видеть только указанный игрок (или все, если идентификатор `-1`). В игре это не будет отображаться как направленное сообщение.
Вы можете использовать это, например, чтобы сообщить игроку *, почему* вы отменили появление его транспортного средства, отправить сообщение в чате или что-то подобное, или чтобы отобразить некоторую информацию о вашем сервере.
Вы можете использовать это, например, чтобы сообщить игроку, *почему* вы отменили появление его транспортного средства, отправить сообщение в чате или что-то подобное, или чтобы отобразить некоторую информацию о вашем сервере.
Пример:
@@ -406,11 +406,11 @@ end
Вызовет указанное событие с указанными данными на указанном клиенте (-1 для трансляции). Это событие затем может быть обработано в клиентском lua mod, см. документацию "Client Scripting" для этого.
Вернет `true` если сообщение удалось отправить (для `id = -1` , поэтому для трансляций это всегда `true` ), и `false` если игрок с таким идентификатором не существует или отключен, но у него все еще есть идентификатор (это известная проблема).
Вернет `true` если сообщение удалось отправить (для `id = -1`, поэтому для трансляций это всегда `true`), и `false` если игрок с таким идентификатором не существует или отключен, но у него все еще есть идентификатор (это известная проблема).
Если возвращается `false` , нет смысла повторять это событие, и не следует ожидать ответа (если таковой ожидался).
Если возвращается `false`, нет смысла повторять это событие, и не следует ожидать ответа (если таковой ожидался).
Начиная с версии 3.1.0, второе возвращаемое значение содержит сообщение об ошибке, если функция не удалась. Также, начиная с этой версии, версия функции `*Json` принимает таблицу в качестве аргумента данных и преобразует ее в json. Это просто сокращение для `MP.TriggerClientEvent(..., Util.JsonEncode(mytable))` .
Начиная с версии 3.1.0, второе возвращаемое значение содержит сообщение об ошибке, если функция не удалась. Также, начиная с этой версии, версия функции `*Json` принимает таблицу в качестве аргумента данных и преобразует ее в json. Это просто сокращение для `MP.TriggerClientEvent(..., Util.JsonEncode(mytable))`.
#### `MP.GetPlayerCount() -> number`
@@ -624,7 +624,7 @@ end
Является ли игрок гостем. Гость — это тот, кто не вошел в систему, а вместо этого решил играть как гость. Обычно его имя — `guest` за которым следует длинный номер.
Поскольку гости анонимны, вы можете запретить им присоединяться. В этом случае рекомендуется использовать аргумент [`onPlayerAuth`](#onplayerauth) `is_guest` .
Поскольку гости анонимны, вы можете запретить им присоединяться. В этом случае рекомендуется использовать аргумент [`onPlayerAuth`](#onplayerauth) `is_guest`.
#### `MP.DropPlayer(player_id: number, [reason: string])`
@@ -653,7 +653,7 @@ end
Возвращает таблицу с информацией об игроке, такой как идентификатор форума BeamMP, IP-адрес и идентификатор учетной записи Discord. Discord ID будет возвращен только в том случае, если пользователь связал его со своей учетной записью форума.
Вы можете найти идентификатор форума пользователя, перейдя по адресу `https://forum.beammp.com/u/USERNAME.json` и выполнив поиск по запросу `"user": {"id": 123456}` . Идентификатор BeamMP уникален для проигрывателя и не может быть изменен в отличие от имени пользователя.
Вы можете найти идентификатор форума пользователя, перейдя по адресу `https://forum.beammp.com/u/USERNAME.json` и выполнив поиск по запросу `"user": {"id": 123456}`. Идентификатор BeamMP уникален для проигрывателя и не может быть изменен в отличие от имени пользователя.
Пример:
@@ -676,7 +676,7 @@ print(MP.GetPlayerIdentifiers(player_id))
#### `MP.Set(setting: number, ...)`
Временно устанавливает параметр ServerConfig. Для этого полезна таблица `MP.Settings` .
Временно устанавливает параметр ServerConfig. Для этого полезна таблица `MP.Settings`.
Пример:
@@ -712,9 +712,9 @@ print(MP.Settings)
#### `Util.Json*`
Начиная с BeamMP-Server `v3.1.0` .
Начиная с BeamMP-Server `v3.1.0`.
Это встроенная библиотека JSON, которая обычно намного быстрее любой библиотеки Lua JSON. За кулисами используется библиотека C++ `nlohmann::json` , которая совместима с JSON, полностью протестирована и постоянно подвергается фаззингу.
Это встроенная библиотека JSON, которая обычно намного быстрее любой библиотеки Lua JSON. За кулисами используется библиотека C++ `nlohmann::json`, которая совместима с JSON, полностью протестирована и постоянно подвергается фаззингу.
#### `Util.JsonEncode(table: table) -> string`
@@ -786,7 +786,7 @@ print(Util.JsonPrettify(myjson))
#### `Util.JsonMinify(json: string) -> string`
Удаляет отступы, переносы строк и любые другие пробелы. Не обязательно, если вы не вызвали `Util.JsonPrettify` , так как весь вывод из `Util.Json*` уже минифицирован.
Удаляет отступы, переносы строк и любые другие пробелы. Не обязательно, если вы не вызвали `Util.JsonPrettify`, так как весь вывод из `Util.Json*` уже минифицирован.
Пример:
@@ -804,7 +804,7 @@ print(Util.JsonMinify(pretty))
#### `Util.JsonFlatten(json: string) -> string`
Создает объект JSON, ключи которого сводятся к указателям JSON в соответствии с RFC 6901. Вы можете восстановить оригинал с помощью `Util.JsonUnflatten()` . Чтобы это работало, все значения должны быть примитивами.
Создает объект JSON, ключи которого сводятся к указателям JSON в соответствии с RFC 6901. Вы можете восстановить оригинал с помощью `Util.JsonUnflatten()`. Чтобы это работало, все значения должны быть примитивами.
Пример:
@@ -831,11 +831,11 @@ flattened pretty: {
#### `Util.JsonUnflatten(json: string) -> string`
Восстанавливает произвольную вложенность значения JSON, которое было сглажено перед использованием функции `Util.JsonFlatten()` .
Восстанавливает произвольную вложенность значения JSON, которое было сглажено перед использованием функции `Util.JsonFlatten()`.
#### `Util.JsonDiff(a: string, b: string) -> string`
Создает разницу JSON в соответствии с RFC 6902 (http://jsonpatch.com/). Затем эту разницу можно применить как патч через `Util.JsonDiffApply()` . Возвращает разницу.
Создает разницу JSON в соответствии с RFC 6902 (http://jsonpatch.com/). Затем эту разницу можно применить как патч через `Util.JsonDiffApply()`. Возвращает разницу.
#### `Util.JsonDiffApply(base: string, diff: string) -> string`
@@ -843,7 +843,7 @@ flattened pretty: {
### `Util.Random*`
Начиная с BeamMP-Server `v3.1.0` .
Начиная с BeamMP-Server `v3.1.0`.
#### `Util.Random() -> float`
@@ -914,7 +914,7 @@ Util.LogDebug("hi")
[19/04/24 11:06:50.142] [Test] [DEBUG] hi
```
Поддерживает ту же самую печать/сброс данных, что и `print()` .
Поддерживает ту же самую печать/сброс данных, что и `print()`.
#### `Util.DebugExecutionTime() -> table`
@@ -979,15 +979,15 @@ MP.CreateEventTimer("printStuff", 5000)
### Функции ФС
Функции `FS` — это функции **файловой** **системы** , которые стремятся превзойти возможности Lua по умолчанию.
Функции `FS` — это функции **файловой** **системы**, которые стремятся превзойти возможности Lua по умолчанию.
Пожалуйста, всегда используйте `/` в качестве разделителя при указании путей, так как это кроссплатформенно (windows, linux, macos, ...).
#### `FS.CreateDirectory(path: string) -> bool,string`
Создает указанный каталог и любые родительские каталоги, если они не существуют. Поведение примерно эквивалентно обычной команде linux `mkdir -p` .
Создает указанный каталог и любые родительские каталоги, если они не существуют. Поведение примерно эквивалентно обычной команде linux `mkdir -p`.
В случае успеха возвращает `true` и `""` . Если создание каталога не удалось, возвращается `false` и сообщение об ошибке ( `string` ).
В случае успеха возвращает `true` и `""`. Если создание каталога не удалось, возвращается `false` и сообщение об ошибке (`string`).
Пример:
@@ -1010,7 +1010,7 @@ end
Удаляет указанный файл или папку.
Возвращает `true` , если произошла ошибка, с сообщением об ошибке во втором возвращаемом значении.
Возвращает `true`, если произошла ошибка, с сообщением об ошибке во втором возвращаемом значении.
Пример:
@@ -1024,15 +1024,15 @@ end
#### `FS.Rename(pathA: string, pathB: string) -> bool,string`
Переименовывает (или перемещает) `pathA` в `pathB` .
Переименовывает (или перемещает) `pathA` в `pathB`.
Возвращает `true` , если произошла ошибка, с сообщением об ошибке во втором возвращаемом значении.
Возвращает `true`, если произошла ошибка, с сообщением об ошибке во втором возвращаемом значении.
#### `FS.Copy(pathA: string, pathB: string) -> bool,string`
Копирует `pathA` в `pathB` .
Копирует `pathA` в `pathB`.
Возвращает `true` , если произошла ошибка, с сообщением об ошибке во втором возвращаемом значении.
Возвращает `true`, если произошла ошибка, с сообщением об ошибке во втором возвращаемом значении.
#### `FS.GetFilename(path: string) -> string`
@@ -1078,11 +1078,11 @@ input -> output
#### `FS.IsDirectory(path: string) -> bool`
Возвращает `true` , если указанный путь является каталогом, `false` если нет. Обратите внимание, что `false` НЕ подразумевает, что путь является файлом (см. `FS.IsFile()` ).
Возвращает `true`, если указанный путь является каталогом, `false` если нет. Обратите внимание, что `false` НЕ подразумевает, что путь является файлом (см. `FS.IsFile()`).
#### `FS.IsFile(path: string) -> bool`
Возвращает `true` , если указанный путь является обычным файлом (не символической ссылкой, жесткой ссылкой, блочным устройством и т. д.), `false` если нет. Обратите внимание, что `false` НЕ подразумевает, что путь является каталогом (см. `FS.IsDirectory()` ).
Возвращает `true`, если указанный путь является обычным файлом (не символической ссылкой, жесткой ссылкой, блочным устройством и т. д.), `false` если нет. Обратите внимание, что `false` НЕ подразумевает, что путь является каталогом (см. `FS.IsDirectory()`).
#### `FS.ListDirectories(path: string) -> table`
@@ -1138,7 +1138,7 @@ FS.ConcatPaths("a", "b", "/c/d/e/", "/f/", "g", "h.txt")
a/b/c/d/e/f/g/h.txt
```
Также разрешает `..` , если он существует в пути в любой точке. Эта функция безопаснее, чем конкатенация строк в lua, и учитывает разделители платформы.
Также разрешает `..`, если он существует в пути в любой точке. Эта функция безопаснее, чем конкатенация строк в lua, и учитывает разделители платформы.
Пожалуйста, всегда используйте `/` в качестве разделителя при указании путей, так как это кроссплатформенно (windows, linux, macos, ...).
@@ -1147,7 +1147,7 @@ a/b/c/d/e/f/g/h.txt
#### Объяснение
- Аргументы: Список аргументов, переданных обработчикам этого события.
- Отменяемое: Можно ли отменить событие. Если его можно отменить, обработчик может сделать это, вернув `1` , например `return 1` .
- Отменяемое: Можно ли отменить событие. Если его можно отменить, обработчик может сделать это, вернув `1`, например `return 1`.
#### Краткое изложение событий
@@ -1178,13 +1178,13 @@ a/b/c/d/e/f/g/h.txt
Срабатывает при отключении сервера. В настоящее время происходит после того, как все игроки были выгнаны.
#### События, связанные с игрой
#### События, Связанные с Игрой
##### `onPlayerAuth`
Аргументы: `player_name: string` , `player_role: string` , `is_guest: bool` , `identifiers: table -> beammp, ip` Возможность отмены: ДА
Аргументы: `player_name: string`, `player_role: string`, `is_guest: bool`, `identifiers: table -> beammp, ip` Возможность отмены: ДА
Первое событие, которое срабатывает, когда игрок хочет присоединиться. Игроку может быть отказано в присоединении, если вернуть `1` или причину ( `string` ) из функции-обработчика.
Первое событие, которое срабатывает, когда игрок хочет присоединиться. Игроку может быть отказано в присоединении, если вернуть `1` или причину (`string`) из функции-обработчика.
```lua
function myPlayerAuthorizer(name, role, is_guest, identifiers)
@@ -1197,13 +1197,13 @@ MP.RegisterEvent("onPlayerAuth", "myPlayerAuthorizer")
Аргументы: `player_id: number` Возможность отмены: НЕТ
Срабатывает, когда игрок впервые начинает подключение, после `onPlayerAuth` .
Срабатывает, когда игрок впервые начинает подключение, после `onPlayerAuth`.
##### `onPlayerJoining`
Аргументы: `player_id: number` Возможность отмены: НЕТ
Срабатывает, когда игрок завершил загрузку всех модов, после `onPlayerConnecting` .
Срабатывает, когда игрок завершил загрузку всех модов, после `onPlayerConnecting`.
##### `onPlayerDisconnect`
@@ -1213,33 +1213,33 @@ MP.RegisterEvent("onPlayerAuth", "myPlayerAuthorizer")
##### `onChatMessage`
Аргументы: `player_id: number` , `player_name: string` , `message: string` Возможность отмены: ДА
Аргументы: `player_id: number`, `player_name: string`, `message: string` Возможность отмены: ДА
Срабатывает, когда игрок отправляет сообщение в чате. При отмене сообщение в чате не будет показано никому, даже игроку, который его отправил.
##### `onVehicleSpawn`
Аргументы: `player_id: number` , `vehicle_id: number` , `data: string` Возможность отмены: ДА
Аргументы: `player_id: number`, `vehicle_id: number`, `data: string` Возможность отмены: ДА
Срабатывает, когда игрок создает новое транспортное средство. Аргумент `data` содержит конфигурацию автомобиля и данные о положении/вращении для транспортного средства в виде строки json.
##### `onVehicleEdited`
Аргументы: `player_id: number` , `vehicle_id: number` , `data: string` Возможность отмены: ДА
Аргументы: `player_id: number`, `vehicle_id: number`, `data: string` Возможность отмены: ДА
Срабатывает, когда игрок редактирует свое транспортное средство и применяет редактирование. Аргумент `data` содержит обновленную конфигурацию автомобиля в виде строки json, но **не** включает данные о положении или вращении. Вы можете использовать [MP.GetPositionRaw](#mpgetpositionrawpid-number-vid-number-tablestring) для получения данных о положении и вращении.
##### `onVehicleDeleted`
Аргументы: `player_id: number` , `vehicle_id: number` Возможность отмены: НЕТ
Аргументы: `player_id: number`, `vehicle_id: number` Возможность отмены: НЕТ
Срабатывает, когда игрок удаляет свое транспортное средство.
##### `onVehicleReset`
Аргументы: `player_id: number` , `vehicle_id: number` , `data: string` Возможность отмены: НЕТ
Аргументы: `player_id: number`, `vehicle_id: number`, `data: string` Возможность отмены: НЕТ
Срабатывает, когда игрок сбрасывает свое транспортное средство. `data` — это обновленное положение и вращение автомобиля, однако **не** включают конфигурацию транспортных средств. Вы можете использовать [MP.GetPlayerVehicles](#mpgetplayervehiclesplayer_id-number-table) , чтобы получить конфигурацию транспортных средств.
Срабатывает, когда игрок сбрасывает свое транспортное средство. `data` — это обновленное положение и вращение автомобиля, однако **не** включают конфигурацию транспортных средств. Вы можете использовать [MP.GetPlayerVehicles](#mpgetplayervehiclesplayer_id-number-table), чтобы получить конфигурацию транспортных средств.
##### `onFileChanged`
@@ -1249,13 +1249,13 @@ MP.RegisterEvent("onPlayerAuth", "myPlayerAuthorizer")
Срабатывает при изменении файла в каталоге `Resources/Server` *или любом его подкаталоге* .
Любое изменение файла в каталоге `Resources/Server/<plugin>` (не в его подпапке) вызовет перезагрузку состояния Lua и событие `onFileChanged` .
Любое изменение файла в каталоге `Resources/Server/<plugin>` (не в его подпапке) вызовет перезагрузку состояния Lua и событие `onFileChanged`.
Любой файл в подпапках `Resources/Server/<plugin>` , например `Resources/Server/<plugin>/lua/stuff.lua` , не вызовет перезагрузку состояния, а только вызовет событие `onFileChanged` . Таким образом, вы можете перезагрузить его самостоятельно правильным образом (или не перезагружать).
Любой файл в подпапках `Resources/Server/<plugin>`, например `Resources/Server/<plugin>/lua/stuff.lua`, не вызовет перезагрузку состояния, а только вызовет событие `onFileChanged`. Таким образом, вы можете перезагрузить его самостоятельно правильным образом (или не перезагружать).
Это относится ко всем файлам, а не только к файлам `.lua` .
Это относится ко всем файлам, а не только к файлам `.lua`.
`path` указывается относительно корня сервера, например `Resources/Server/myplugin/myfile.txt` . Вы можете выполнить дальнейшую обработку этой строки с помощью семейства функций `FS.*` , например, извлечь имя или расширение ( `FS.GetExtension(...)` , `FS.GetFilename(...)` , ...).
`path` указывается относительно корня сервера, например `Resources/Server/myplugin/myfile.txt`. Вы можете выполнить дальнейшую обработку этой строки с помощью семейства функций `FS.*`, например, извлечь имя или расширение ( `FS.GetExtension(...)`, `FS.GetFilename(...)`, ...).
Примечание: файлы, добавленные после запуска сервера, *не* отслеживаются, начиная с версии 3.1.0.
@@ -1269,7 +1269,7 @@ MP.RegisterEvent("onPlayerAuth", "myPlayerAuthorizer")
#### Найти и заменить
Сначала вам следует выполнить поиск и замену всех функций MP. Подстановка должна добавить `MP.` перед всеми функциями MP, за исключением `print()` .
Сначала вам следует выполнить поиск и замену всех функций MP. Подстановка должна добавить `MP.` перед всеми функциями MP, за исключением `print()`.
Пример:
@@ -1287,7 +1287,7 @@ print(#players) -- note how print() doesn't change
#### Прощайте, темы, привет, таймеры событий!
Как обсуждалось во введении, потоки — это таймеры событий. Для любых вызовов `CreateThread` замените его вызовом `CreateEventTimer` . Внимательно проверьте время, которое имел ваш старый CreateThread (число было X в секунду), и подумайте о том, какое значение тайм-аута таймера событий для этого (которое указывается в миллисекундах). Также имейте в виду, что вместо имени функции он принимает имя события, поэтому вам придется также зарегистрировать событие.
Как обсуждалось во введении, потоки — это таймеры событий. Для любых вызовов `CreateThread` замените его вызовом `CreateEventTimer`. Внимательно проверьте время, которое имел ваш старый CreateThread (число было X в секунду), и подумайте о том, какое значение тайм-аута таймера событий для этого (которое указывается в миллисекундах). Также имейте в виду, что вместо имени функции он принимает имя события, поэтому вам придется также зарегистрировать событие.
Пример: