commit
e477ae51e5
@ -48,6 +48,13 @@
|
|||||||
- "pipe" - профиль "труба". Примеры блоков: бревно, труба, лампочка
|
- "pipe" - профиль "труба". Примеры блоков: бревно, труба, лампочка
|
||||||
- "pane" - профиль "панель". Примеры блоков: панель, дверь, табличка
|
- "pane" - профиль "панель". Примеры блоков: панель, дверь, табличка
|
||||||
|
|
||||||
|
### Испускаемые частицы - *particles*
|
||||||
|
|
||||||
|
Частицы указываются в виде JSON объекта. Имена свойств можно найти [в разделе, посвященном частицам](particles.md).
|
||||||
|
|
||||||
|
При приближении к блоку движок создаст эмиттер, который будет работать
|
||||||
|
до разрушения блока или отдаления камеры на некоторое расстояние.
|
||||||
|
|
||||||
## Освещение
|
## Освещение
|
||||||
|
|
||||||
### Излучение - *emission*:
|
### Излучение - *emission*:
|
||||||
|
|||||||
@ -19,3 +19,4 @@
|
|||||||
- [Свойства блоков](block-properties.md)
|
- [Свойства блоков](block-properties.md)
|
||||||
- [Свойства предметов](item-properties.md)
|
- [Свойства предметов](item-properties.md)
|
||||||
- [Скриптинг](scripting.md)
|
- [Скриптинг](scripting.md)
|
||||||
|
- [Частицы](particles.md)
|
||||||
|
|||||||
66
doc/ru/particles.md
Normal file
66
doc/ru/particles.md
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
# Частицы
|
||||||
|
|
||||||
|
Частицы представляют собой таблицу, все поля которой опциональны.
|
||||||
|
|
||||||
|
|
||||||
|
| Поле | Описание | По-умолчанию |
|
||||||
|
| --------------- | ---------------------------------------------------------------------------- | --------------- |
|
||||||
|
| texture | Текстура частицы. | "" |
|
||||||
|
| frames | Кадры анимации (массив имен текстур). Должны находиться в одном атласе. | {} |
|
||||||
|
| lighting | Освещение. | true |
|
||||||
|
| collision | Обнаружение столкновений. | true |
|
||||||
|
| max_distance | Максимальная дистанция от камеры, при которой происходит спавн частиц. | 16.0 |
|
||||||
|
| spawn_interval | Интервал спавна частиц в секундах. | 1.0 |
|
||||||
|
| lifetime | Среднее время жизни частиц в секундах. | 5.0 |
|
||||||
|
| lifetime_spread | Максимальное отклонение времени жизни частицы (от 0.0 до 1.0). | 0.2 |
|
||||||
|
| velocity | Начальная линейная скорость частиц. | {0, 0, 0} |
|
||||||
|
| acceleration | Ускорение частиц. | {0, -16, 0} |
|
||||||
|
| explosion | Сила разлёта частиц при спавне. | {2, 2, 2} |
|
||||||
|
| size | Размер частиц. | {0.1, 0.1, 0.1} |
|
||||||
|
| spawn_shape | Форма области спавна частиц. (ball/sphere/box) | ball |
|
||||||
|
| spawn_spread | Размер области спавна частиц. | {0, 0, 0} |
|
||||||
|
| random_sub_uv | Размер случайного подрегиона текстуры (1 - будет использована вся текстура). | 1.0 |
|
||||||
|
|
||||||
|
## Библиотека *gfx.particles*
|
||||||
|
|
||||||
|
```lua
|
||||||
|
gfx.particles.emit(
|
||||||
|
-- позиция эмиттера: статические координаты или uid сущности
|
||||||
|
origin: vec3 | int,
|
||||||
|
-- количество частиц (-1 - бесконечно)
|
||||||
|
count: int,
|
||||||
|
-- таблица настроек частиц
|
||||||
|
preset: table,
|
||||||
|
-- дополнительная таблица настроек частиц
|
||||||
|
[опционально] extension: table
|
||||||
|
) -> int
|
||||||
|
```
|
||||||
|
|
||||||
|
Создаёт эмиттер частиц, возвращая его id.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
gfx.particles.stop(id: int)
|
||||||
|
```
|
||||||
|
|
||||||
|
Останавливает эмиттер без возможности возобновления. Эмиттер будет удален
|
||||||
|
позже автоматически.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
gfx.particles.is_alive(id: int) -> bool
|
||||||
|
```
|
||||||
|
|
||||||
|
Проверяет, работает ли эмиттер. Возвращает false если работа прекращена или
|
||||||
|
эмиттер не существует.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
gfx.particles.get_origin(id: int) -> vec3 | int
|
||||||
|
```
|
||||||
|
|
||||||
|
Возвращает статическую позицию или uid сущности, к которой привязан эмиттер.
|
||||||
|
Если эмиттера не существует, возвращает nil.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
gfx.particles.set_origin(id: int, origin: vec3 | int)
|
||||||
|
```
|
||||||
|
|
||||||
|
Устанавливает статическую позицию или uid сущности, к которой будет привязан эмиттер.
|
||||||
@ -21,6 +21,7 @@
|
|||||||
- [pack](scripting/builtins/libpack.md)
|
- [pack](scripting/builtins/libpack.md)
|
||||||
- [player](scripting/builtins/libplayer.md)
|
- [player](scripting/builtins/libplayer.md)
|
||||||
- [quat](scripting/builtins/libquat.md)
|
- [quat](scripting/builtins/libquat.md)
|
||||||
|
- [rules](scripting/builtins/librules.md)
|
||||||
- [time](scripting/builtins/libtime.md)
|
- [time](scripting/builtins/libtime.md)
|
||||||
- [utf8](scripting/builtins/libutf8.md)
|
- [utf8](scripting/builtins/libutf8.md)
|
||||||
- [vec2, vec3, vec4](scripting/builtins/libvecn.md)
|
- [vec2, vec3, vec4](scripting/builtins/libvecn.md)
|
||||||
|
|||||||
72
doc/ru/scripting/builtins/librules.md
Normal file
72
doc/ru/scripting/builtins/librules.md
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
# Библиотека *rules*
|
||||||
|
|
||||||
|
```lua
|
||||||
|
rules.create(
|
||||||
|
-- имя правила
|
||||||
|
name: str,
|
||||||
|
-- значение по-умолчанию
|
||||||
|
default: bool,
|
||||||
|
-- функция-обработчик изменения значения
|
||||||
|
[опционально] handler: function
|
||||||
|
) -> int
|
||||||
|
```
|
||||||
|
|
||||||
|
Создаёт правило. Если указан обработчик, возвращает id для возможности удаления.
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> Созданием правила считается вызов rules.create с назначением значения по-умолчанию.
|
||||||
|
> Не созданные правила могут быть использованы, но сброс через rules.reset приведёт
|
||||||
|
> к установке значения nil.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
rules.listen(
|
||||||
|
-- имя правила
|
||||||
|
name: str,
|
||||||
|
-- функция-обработчик изменения значения
|
||||||
|
handler: function
|
||||||
|
) -> int
|
||||||
|
```
|
||||||
|
|
||||||
|
Добавляет обработчик изменения значения правила.
|
||||||
|
Возвращает id для возможности удаления.
|
||||||
|
Также позволяет подписаться на правило до его создания.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
rules.unlisten(name: str, id: int)
|
||||||
|
```
|
||||||
|
|
||||||
|
Удаляет обработчик правила по id, если он существует.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
rules.get(name: str) -> bool | nil
|
||||||
|
```
|
||||||
|
|
||||||
|
Возвращает значение правила или nil, если оно ещё не было создано.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
rules.set(name: str, value: bool)
|
||||||
|
```
|
||||||
|
|
||||||
|
Устанавливает значение правила, вызывая обработчики. Может использоваться и
|
||||||
|
до создания правила.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
rules.reset(name: str)
|
||||||
|
```
|
||||||
|
|
||||||
|
Сбрасывает значение правила к значению по-умолчанию.
|
||||||
|
|
||||||
|
|
||||||
|
## Стандартные правила
|
||||||
|
|
||||||
|
|
||||||
|
| Имя | Описание | По-умолчанию |
|
||||||
|
| -------------------- | --------------------------------------------------------------- | ------------ |
|
||||||
|
| cheat-commands | Разрешить команды, имена которых есть в массиве console.chears. | true |
|
||||||
|
| show-content-access | Разрешить панель доступа к контенту. | true |
|
||||||
|
| allow-flight | Разрешить полёт | true |
|
||||||
|
| allow-noclip | Разрешить включение noclip. | true |
|
||||||
|
| allow-attack | Разрешить атаковать сущности. | true |
|
||||||
|
| allow-destroy | Разрешить разрушение блоков. | true |
|
||||||
|
| allow-cheat-movement | Разрешить специальные клавиши быстрого перемещения. | true |
|
||||||
|
| allow-debug-cheats | Разрешить нечестные элементы управления на дебаг-панели. | true |
|
||||||
@ -13,6 +13,7 @@ camera.mode="key:f4"
|
|||||||
player.noclip="key:n"
|
player.noclip="key:n"
|
||||||
player.flight="key:f"
|
player.flight="key:f"
|
||||||
player.attack="mouse:left"
|
player.attack="mouse:left"
|
||||||
|
player.destroy="mouse:left"
|
||||||
player.build="mouse:right"
|
player.build="mouse:right"
|
||||||
player.pick="mouse:middle"
|
player.pick="mouse:middle"
|
||||||
player.drop="key:q"
|
player.drop="key:q"
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
function on_block_broken(id, x, y, z, playerid)
|
function on_block_broken(id, x, y, z, playerid)
|
||||||
particles.emit({x+0.5, y+0.5, z+0.5}, 64, {
|
gfx.particles.emit({x+0.5, y+0.5, z+0.5}, 64, {
|
||||||
lifetime=1.0,
|
lifetime=1.0,
|
||||||
spawn_interval=0.0001,
|
spawn_interval=0.0001,
|
||||||
explosion={4, 4, 4},
|
explosion={4, 4, 4},
|
||||||
|
|||||||
@ -61,7 +61,7 @@ function submit(text)
|
|||||||
if name == nil then
|
if name == nil then
|
||||||
name = text
|
name = text
|
||||||
end
|
end
|
||||||
if not rules.get("cheat-commands") and table.has(console.cheats, name) then
|
if not rules.get("allow-cheats") and table.has(console.cheats, name) then
|
||||||
console.log("cheat commands are disabled")
|
console.log("cheat commands are disabled")
|
||||||
document.prompt.text = ""
|
document.prompt.text = ""
|
||||||
document.prompt.focused = true
|
document.prompt.focused = true
|
||||||
|
|||||||
@ -33,7 +33,7 @@ console.add_command(
|
|||||||
local str = "Available commands:"
|
local str = "Available commands:"
|
||||||
|
|
||||||
for i,k in ipairs(commands) do
|
for i,k in ipairs(commands) do
|
||||||
if rules.get("cheat-commands") or not table.has(console.cheats, k) then
|
if rules.get("allow-cheats") or not table.has(console.cheats, k) then
|
||||||
str = str .. "\n " .. build_scheme(console.get_command_info(k))
|
str = str .. "\n " .. build_scheme(console.get_command_info(k))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -113,7 +113,7 @@ console.add_command(
|
|||||||
|
|
||||||
console.add_command(
|
console.add_command(
|
||||||
"time.daycycle operation:[stop|reset]",
|
"time.daycycle operation:[stop|reset]",
|
||||||
"Control time.daycycle",
|
"Control time.daycycle. Operations: stop, reset",
|
||||||
function(args, kwargs)
|
function(args, kwargs)
|
||||||
local operation = args[1]
|
local operation = args[1]
|
||||||
if operation == "stop" then
|
if operation == "stop" then
|
||||||
@ -198,7 +198,7 @@ console.add_command(
|
|||||||
)
|
)
|
||||||
|
|
||||||
console.add_command(
|
console.add_command(
|
||||||
"fragment.crop filename:str",
|
"fragment.crop file:str",
|
||||||
"Crop fragment",
|
"Crop fragment",
|
||||||
function(args, kwargs)
|
function(args, kwargs)
|
||||||
local filename = args[1]
|
local filename = args[1]
|
||||||
|
|||||||
@ -229,7 +229,10 @@ function _rules.create(name, value, handler)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function _rules.unlisten(name, id)
|
function _rules.unlisten(name, id)
|
||||||
local rule = _rules.get_rule(name)
|
local rule = _rules.rules[name]
|
||||||
|
if rule == nil then
|
||||||
|
return
|
||||||
|
end
|
||||||
rule.listeners[utf8.encode(id)] = nil
|
rule.listeners[utf8.encode(id)] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -237,7 +240,7 @@ function _rules.clear()
|
|||||||
_rules.rules = {}
|
_rules.rules = {}
|
||||||
_rules.nextid = 1
|
_rules.nextid = 1
|
||||||
|
|
||||||
_rules.create("cheat-commands", true)
|
_rules.create("allow-cheats", true)
|
||||||
end
|
end
|
||||||
|
|
||||||
function __vc_create_hud_rules()
|
function __vc_create_hud_rules()
|
||||||
@ -250,9 +253,12 @@ function __vc_create_hud_rules()
|
|||||||
_rules.create("allow-noclip", true, function(value)
|
_rules.create("allow-noclip", true, function(value)
|
||||||
input.set_enabled("player.noclip", value)
|
input.set_enabled("player.noclip", value)
|
||||||
end)
|
end)
|
||||||
_rules.create("allow-destruct", true, function(value)
|
_rules.create("allow-attack", true, function(value)
|
||||||
input.set_enabled("player.attack", value)
|
input.set_enabled("player.attack", value)
|
||||||
end)
|
end)
|
||||||
|
_rules.create("allow-destroy", true, function(value)
|
||||||
|
input.set_enabled("player.destroy", value)
|
||||||
|
end)
|
||||||
_rules.create("allow-cheat-movement", true, function(value)
|
_rules.create("allow-cheat-movement", true, function(value)
|
||||||
input.set_enabled("movement.cheat", value)
|
input.set_enabled("movement.cheat", value)
|
||||||
end)
|
end)
|
||||||
|
|||||||
@ -29,7 +29,8 @@ movement.crouch=Crouch
|
|||||||
movement.cheat=Cheat
|
movement.cheat=Cheat
|
||||||
hud.inventory=Inventory
|
hud.inventory=Inventory
|
||||||
player.pick=Pick Block
|
player.pick=Pick Block
|
||||||
player.attack=Attack / Break
|
player.attack=Attack
|
||||||
|
player.destroy=Destroy
|
||||||
player.build=Place Block
|
player.build=Place Block
|
||||||
player.fast_interaction=Accelerated interaction
|
player.fast_interaction=Accelerated interaction
|
||||||
player.flight=Flight
|
player.flight=Flight
|
||||||
|
|||||||
@ -91,7 +91,8 @@ movement.crouch=Красться
|
|||||||
movement.cheat=Чит
|
movement.cheat=Чит
|
||||||
hud.inventory=Инвентарь
|
hud.inventory=Инвентарь
|
||||||
player.pick=Подобрать Блок
|
player.pick=Подобрать Блок
|
||||||
player.attack=Атаковать / Сломать
|
player.attack=Атаковать
|
||||||
|
player.destroy=Сломать
|
||||||
player.build=Поставить Блок
|
player.build=Поставить Блок
|
||||||
player.fast_interaction=Ускоренное взаимодействие
|
player.fast_interaction=Ускоренное взаимодействие
|
||||||
player.flight=Полёт
|
player.flight=Полёт
|
||||||
|
|||||||
@ -25,6 +25,7 @@ inline const std::string BIND_CAM_MODE = "camera.mode";
|
|||||||
inline const std::string BIND_PLAYER_NOCLIP = "player.noclip";
|
inline const std::string BIND_PLAYER_NOCLIP = "player.noclip";
|
||||||
inline const std::string BIND_PLAYER_FLIGHT = "player.flight";
|
inline const std::string BIND_PLAYER_FLIGHT = "player.flight";
|
||||||
inline const std::string BIND_PLAYER_ATTACK = "player.attack";
|
inline const std::string BIND_PLAYER_ATTACK = "player.attack";
|
||||||
|
inline const std::string BIND_PLAYER_DESTROY = "player.destroy";
|
||||||
inline const std::string BIND_PLAYER_BUILD = "player.build";
|
inline const std::string BIND_PLAYER_BUILD = "player.build";
|
||||||
inline const std::string BIND_PLAYER_PICK = "player.pick";
|
inline const std::string BIND_PLAYER_PICK = "player.pick";
|
||||||
inline const std::string BIND_PLAYER_FAST_INTERACTOIN =
|
inline const std::string BIND_PLAYER_FAST_INTERACTOIN =
|
||||||
|
|||||||
@ -494,7 +494,9 @@ void PlayerController::updateInteraction(float delta) {
|
|||||||
bool xkey = Events::active(BIND_PLAYER_FAST_INTERACTOIN);
|
bool xkey = Events::active(BIND_PLAYER_FAST_INTERACTOIN);
|
||||||
float maxDistance = xkey ? 200.0f : 10.0f;
|
float maxDistance = xkey ? 200.0f : 10.0f;
|
||||||
bool longInteraction = interactionTimer <= 0 || xkey;
|
bool longInteraction = interactionTimer <= 0 || xkey;
|
||||||
bool lclick = Events::jactive(BIND_PLAYER_ATTACK) ||
|
bool lclick = Events::jactive(BIND_PLAYER_DESTROY) ||
|
||||||
|
(longInteraction && Events::active(BIND_PLAYER_DESTROY));
|
||||||
|
bool lattack = Events::jactive(BIND_PLAYER_ATTACK) ||
|
||||||
(longInteraction && Events::active(BIND_PLAYER_ATTACK));
|
(longInteraction && Events::active(BIND_PLAYER_ATTACK));
|
||||||
bool rclick = Events::jactive(BIND_PLAYER_BUILD) ||
|
bool rclick = Events::jactive(BIND_PLAYER_BUILD) ||
|
||||||
(longInteraction && Events::active(BIND_PLAYER_BUILD));
|
(longInteraction && Events::active(BIND_PLAYER_BUILD));
|
||||||
@ -512,7 +514,7 @@ void PlayerController::updateInteraction(float delta) {
|
|||||||
scripting::on_item_use(player.get(), item);
|
scripting::on_item_use(player.get(), item);
|
||||||
}
|
}
|
||||||
if (selection.entity) {
|
if (selection.entity) {
|
||||||
updateEntityInteraction(selection.entity, lclick, rclick);
|
updateEntityInteraction(selection.entity, lattack, rclick);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -599,6 +599,23 @@ namespace lua {
|
|||||||
setglobal(L, name);
|
setglobal(L, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline void openlib(
|
||||||
|
lua::State* L,
|
||||||
|
const std::string& package,
|
||||||
|
const std::string& name,
|
||||||
|
const luaL_Reg* libfuncs
|
||||||
|
) {
|
||||||
|
if (!hasglobal(L, package)) {
|
||||||
|
createtable(L, 0, 1);
|
||||||
|
setglobal(L, package);
|
||||||
|
}
|
||||||
|
getglobal(L, package);
|
||||||
|
createtable(L, 0, 0);
|
||||||
|
luaL_setfuncs(L, libfuncs, 0);
|
||||||
|
setfield(L, name);
|
||||||
|
pop(L);
|
||||||
|
}
|
||||||
|
|
||||||
inline const char* require_string_field(
|
inline const char* require_string_field(
|
||||||
lua::State* L, const std::string& name, int idx=-1
|
lua::State* L, const std::string& name, int idx=-1
|
||||||
) {
|
) {
|
||||||
|
|||||||
@ -24,7 +24,7 @@ void scripting::on_frontend_init(Hud* hud, WorldRenderer* renderer) {
|
|||||||
auto L = lua::get_main_state();
|
auto L = lua::get_main_state();
|
||||||
|
|
||||||
lua::openlib(L, "hud", hudlib);
|
lua::openlib(L, "hud", hudlib);
|
||||||
lua::openlib(L, "particles", particleslib);
|
lua::openlib(L, "gfx", "particles", particleslib);
|
||||||
|
|
||||||
if (lua::getglobal(L, "__vc_create_hud_rules")) {
|
if (lua::getglobal(L, "__vc_create_hud_rules")) {
|
||||||
lua::call_nothrow(L, 0, 0);
|
lua::call_nothrow(L, 0, 0);
|
||||||
|
|||||||
@ -26,7 +26,7 @@ dv::value ParticlesPreset::serialize() const {
|
|||||||
if (frames.empty()) {
|
if (frames.empty()) {
|
||||||
root["texture"] = texture;
|
root["texture"] = texture;
|
||||||
} else {
|
} else {
|
||||||
auto& arr = root.list("animation");
|
auto& arr = root.list("frames");
|
||||||
for (const auto& frame : frames) {
|
for (const auto& frame : frames) {
|
||||||
arr.add(frame);
|
arr.add(frame);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,7 +43,7 @@ struct ParticlesPreset : public Serializable {
|
|||||||
/// @brief Particle size
|
/// @brief Particle size
|
||||||
glm::vec3 size {0.1f};
|
glm::vec3 size {0.1f};
|
||||||
/// @brief Spawn spread shape
|
/// @brief Spawn spread shape
|
||||||
ParticleSpawnShape spawnShape;
|
ParticleSpawnShape spawnShape = BALL;
|
||||||
/// @brief Spawn spread
|
/// @brief Spawn spread
|
||||||
glm::vec3 spawnSpread {};
|
glm::vec3 spawnSpread {};
|
||||||
/// @brief Texture name
|
/// @brief Texture name
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user