Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ subprojects/fmt
subprojects/gtest
subprojects/sol2
subprojects/luajit
subprojects/emmyluacodestyle
subprojects/yaml-cpp
subprojects/zlib
/1/
38 changes: 38 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
* [Windows (MSVC / Clang)](#windows-msvc--clang)
* [Windows (MinGW / MSYS2)](#windows-mingw--msys2)
* [Cross-компиляция под Windows с Linux (MinGW)](#cross-компиляция-под-windows-с-linux-mingw)
* [LuaJIT и форматирование Lua](#luajit-и-форматирование-lua)
* [Unity-сборка](#unity-сборка)
* [Пересборка](#пересборка)
* [Тесты](#тесты)
Expand Down Expand Up @@ -140,6 +141,40 @@ meson setup build --cross-file toolchains/windows-mingw64-cross.txt -Dbuild_prof
meson compile -C build
```

### LuaJIT и форматирование Lua

Для сборки движка с Lua-триггерами и встроенным форматтером EmmyLuaCodeStyle используйте встроенные Meson-зависимости:

```bash
meson setup build_lua \
-Dbuild_profile=release \
-Dbuild_tests=false \
-Dluajit=builtin \
-Dlua_formatter=true
meson compile -C build_lua
```

`-Dluajit=builtin` включает LuaJIT и интеграцию через sol2. При включенном LuaJIT опция `lua_formatter` по умолчанию равна `true`; она указана в примере явно, чтобы конфигурация была очевидна. Meson использует subprojects из репозитория или загружает недостающие исходники через wrap-файлы.

Если LuaJIT установлен в системе и доступен через `pkg-config`, вместо встроенной версии можно использовать:

```bash
meson setup build_lua \
-Dbuild_profile=release \
-Dbuild_tests=false \
-Dluajit=system \
-Dlua_formatter=true
```

Чтобы оставить Lua-триггеры, но отключить форматтер:

```bash
meson configure build_lua -Dlua_formatter=false
meson compile -C build_lua
```

В итоговой сводке конфигурации Meson строки `LuaJIT` и `Lua formatter` показывают фактически выбранные режимы. Форматтер доступен в OLC только в сборке с LuaJIT.

---

## Unity-сборка
Expand Down Expand Up @@ -257,8 +292,10 @@ docker stop mud
| `nocrypt` | boolean | `false` | Отключить использование `crypt()` |
| `with_asan` | boolean | `false` | Address Sanitizer |
| `use_pch` | boolean | `true` | Предкомпилированные заголовки |
| `lua_formatter` | boolean | `true` | Встроенный EmmyLuaCodeStyle; используется только при включенном LuaJIT |
| `linker` | string | `` (системный) | Линковщик: `gold`, `mold`, `lld`, `bfd` |
| `full_world_path` | string | `` | Абсолютный путь к данным мира для создания симлинков |
| `sol2_root` | string | `` | Необязательный путь к заголовкам sol2; пустое значение использует Meson dependency/fallback |

### Зависимости

Expand All @@ -276,6 +313,7 @@ meson setup build -Ddependency1=builtin -Ddependency2=system -Ddependency3=disab
| `zlib` | `auto` | Поддержка MCCP через ZLib |
| `iconv` | `disabled` | Поддержка iconv |
| `telegram` | `disabled` | Telegram-интеграция (требует CURL + OpenSSL) |
| `luajit` | `disabled` | Lua-триггеры через LuaJIT и sol2; `builtin` собирает встроенные зависимости |
| `boost` | `disabled` | Boost (нужен для scripting) |
| `sqlite` | `disabled` | SQLite как источник данных мира |
| `yaml` | `disabled` | YAML как источник данных мира |
Expand Down
4 changes: 3 additions & 1 deletion docs/LUA_SCRIPTS_FOR_BUILDERS_RU.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Этот документ описывает Lua-триггеры, которые можно использовать вместо DG Script в world-файлах триггеров.

Lua-поддержка сейчас является прототипом и работает только в сборке с `-Dluajit_prototype=true`. Обычная сборка без LuaJIT должна продолжать читать DG-триггеры как раньше.
Lua-поддержка сейчас является прототипом и работает только в сборке с включенной опцией `luajit`, например `-Dluajit=builtin` или `-Dluajit=system`. Обычная сборка без LuaJIT должна продолжать читать DG-триггеры как раньше.

**Безопасность:** глобалы `os`, `io`, `debug`, `package` и `require` намеренно отключены. Для реального календарного времени используйте `mud.date("%j")`, `mud.date("*t")`, `mud.date("exact")` и т.п. (не os.date).

Expand Down Expand Up @@ -40,6 +40,8 @@ script: |

Lua-триггер можно писать как обычное тело функции: движок выполняет такой chunk с доступным `ctx` - контекстом владельца триггера, актера, объекта и других данных события. Старый явный формат `return function(ctx) ... end` продолжает работать.

В OLC-меню Lua-триггера доступен пункт `Проверить синтаксис и отформатировать Lua`. Он форматирует текущий текст встроенной библиотекой EmmyLuaCodeStyle с отступом в 2 пробела. При выходе из OLC с сохранением Lua-код проверяется и форматируется автоматически. Если проверка или форматирование завершается ошибкой, OLC показывает сообщение об ошибке, сохраняет исходную версию кода без форматирования и закрывает редактор. Форматтер работает в отдельном рабочем потоке, поэтому игровой цикл не останавливается; запросы от разных редакторов выполняются последовательно в порядке очереди. Во время автоматического форматирования команда `Q` отменяет форматирование, сохраняет исходный код и закрывает редактор. При разрыве соединения после подтверждения сохранения исходный код также сохраняется. При ручном запуске форматирования из меню ожидание можно отменить командой `Q` без сохранения. В сборке без LuaJIT пункт не показывается; встроенный форматтер можно отключить опцией Meson `-Dlua_formatter=false`.

Номер строки в ошибке Lua соответствует номеру в `tstat -n <vnum>` и в нумерованном выводе `/n` текстового редактора OLC. Пустые строки учитываются. Пока изменения в OLC не сохранены, runtime-сообщения относятся к предыдущей сохраненной версии триггера.

Номер строки в диагностике DG и Lua имеет разный смысл. Для DG строки команд нумерует сам движок. Для Lua номер сообщает LuaJIT: это строка, на которой парсер или выполняемый код обнаружил ошибку. Первопричина синтаксической ошибки может находиться раньше. Например, если на строке 7 написано незаконченное выражение `asdasd`, а на строке 8 начинается `mud.wait(1)`, Lua может сообщить об ошибке на строке 8: только встретив `mud`, парсер понял, что после `asdasd` ожидался оператор присваивания. Поэтому при синтаксической ошибке проверяйте не только указанную строку, но и несколько строк перед ней, включая незакрытые скобки, строки и блоки.
Expand Down
13 changes: 13 additions & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,7 @@ threads_dep = dependency('threads')
dependencies += threads_dep

luajit_opt = get_option('luajit')
lua_formatter_enabled = false
if luajit_opt != 'disabled'
if luajit_opt == 'builtin'
luajit_sub = subproject('luajit', default_options: ['default_library=static', 'luajit=false'])
Expand All @@ -238,6 +239,16 @@ if luajit_opt != 'disabled'
)
project_args += '-DWITH_LUAJIT_PROTOTYPE'
dependencies += [luajit_dep, sol2_dep]
if get_option('lua_formatter')
emmy_dep = dependency(
'emmyluacodestyle',
fallback: ['emmyluacodestyle', 'emmyluacodestyle_dep'],
default_options: ['warning_level=0'],
)
dependencies += emmy_dep
project_args += '-DWITH_LUA_FORMATTER'
lua_formatter_enabled = true
endif
endif

# Admin API
Expand Down Expand Up @@ -459,6 +470,7 @@ main_sources = files(
'src/engine/scripting/dg_triggers.cpp',
'src/engine/scripting/dg_wldcmd.cpp',
'src/engine/scripting/lua/lua_entity_bindings.cpp',
'src/engine/scripting/lua/lua_formatter.cpp',
'src/engine/scripting/lua/lua_mud_api.cpp',
'src/engine/scripting/lua/lua_script_engine.cpp',
'src/engine/scripting/lua/lua_trigger_context.cpp',
Expand Down Expand Up @@ -1071,6 +1083,7 @@ summary({
'fmt': fmt_opt,
'gtest': gtest_opt,
'LuaJIT': luajit_opt,
'Lua formatter': lua_formatter_enabled,
'SQLite': sqlite_opt,
'YAML': yaml_opt,
'Telegram': telegram_opt,
Expand Down
1 change: 1 addition & 0 deletions meson_options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ option('nocrypt', type: 'boolean', value: false, description: 'Disable use of cr
option('has_epoll', type: 'boolean', value: true, description: 'Use epoll (Linux or freebsd)')
option('scripting', type: 'boolean', value: false, description: 'Enable scripting support (Python + Boost.Python)')
option('sol2_root', type: 'string', value: '', description: 'Optional path to sol2 root for luajit_prototype; empty uses Meson dependency/fallback')
option('lua_formatter', type: 'boolean', value: true, description: 'Build the embedded EmmyLuaCodeStyle formatter when LuaJIT is enabled')
option('with_asan', type: 'boolean', value: false, description: 'Build with Address Sanitizer')
option('use_pch', type: 'boolean', value: true, description: 'Use precompiled headers for circle.library')

Expand Down
11 changes: 9 additions & 2 deletions src/engine/core/comm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@
#include "gameplay/mechanics/illumination.h"
#include "gameplay/clans/house.h"
#include "engine/olc/olc.h"
#include "engine/scripting/lua/lua_formatter.h"
#include "engine/olc/vedun/vedun.h"
#include "administration/ban.h"
#include "administration/proxy.h"
Expand Down Expand Up @@ -910,10 +911,16 @@ void stop_game(ush_int port) {
}
}
#endif
game_loop(epoll, mother_desc);
{
lua_scripting::LuaFormatterShutdownGuard lua_formatter_shutdown_guard;
game_loop(epoll, mother_desc);
}
#else
log("Polling using select().");
game_loop(mother_desc);
{
lua_scripting::LuaFormatterShutdownGuard lua_formatter_shutdown_guard;
game_loop(mother_desc);
}
#endif

// Shutdown OTEL providers to flush remaining telemetry
Expand Down
2 changes: 2 additions & 0 deletions src/engine/core/heartbeat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "gameplay/abilities/timed_abilities.h"
#include "gameplay/ai/mobact.h"
#include "engine/scripting/dg_event.h"
#include "engine/scripting/dg_olc.h"
#include "engine/scripting/lua/lua_script_engine.h"
#include "gameplay/mechanics/corpse.h"
#include "engine/db/global_objects.h"
Expand Down Expand Up @@ -276,6 +277,7 @@ Heartbeat::steps_t &pulse_steps() {
0,
std::make_shared<SimpleCall>(GlobalDrop::reload_tables)),
Heartbeat::PulseStep("Events processing", 1, 0, std::make_shared<SimpleCall>(process_events)),
Heartbeat::PulseStep("Lua formatter results", 1, 0, std::make_shared<SimpleCall>(ProcessLuaFormatterResults)),
Heartbeat::PulseStep("Lua scripting cleanup", 1, 0, std::make_shared<SimpleCall>(lua_scripting::LuaScriptEngine::HeartbeatCleanup)),
Heartbeat::PulseStep("Triggers check mobile",
PULSE_DG_SCRIPT,
Expand Down
4 changes: 4 additions & 0 deletions src/engine/olc/olc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ olc_data::olc_data()
script_mode(0),
trigger_position(0),
item_type(0),
lua_format_request_id(0),
lua_format_save_on_completion(false),
script(0),
storage(0) {

Expand Down Expand Up @@ -473,6 +475,7 @@ void strip_string(char *buffer) {
*/
void cleanup_olc(DescriptorData *d, byte cleanup_type) {
if (d->olc) {
TrigeditSavePendingLuaOnCleanup(d);

// Освободить редактируемый триггер
if (OLC_TRIG(d)) {
Expand Down Expand Up @@ -539,6 +542,7 @@ void cleanup_olc(DescriptorData *d, byte cleanup_type) {
true, d->character.get(), 0, 0, kToRoom);
}
delete d->olc;
d->olc = nullptr;
}
}

Expand Down
4 changes: 4 additions & 0 deletions src/engine/olc/olc.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
#ifndef _OLC_H_
#define _OLC_H_

#include <cstdint>

#include "engine/db/db.h"
#include "engine/structs/structs.h"

Expand Down Expand Up @@ -109,6 +111,8 @@ struct olc_data {
int script_mode;
int trigger_position;
int item_type;
std::uint64_t lua_format_request_id;
bool lua_format_save_on_completion;
ObjData::triggers_list_t script;
char *storage; // for holding commands etc..
};
Expand Down
Loading
Loading