commit
8187568e69
@ -1,16 +1,21 @@
|
||||
# Documentation
|
||||
|
||||
Documentation for the in-development engine version 0.23.
|
||||
|
||||
[Documentation for the last stable version (0.22.x)](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.22/doc/en/main-page.md)
|
||||
|
||||
## Sections
|
||||
|
||||
- [Engine usage recommendations](engine-use-recommendations.md)
|
||||
- [Content-packs](content-packs.md)
|
||||
- [Block properties](block-properties.md)
|
||||
- [Item properties](item-properties.md)
|
||||
- [XML UI building](xml-ui-layouts.md)
|
||||
- [Assets preloading](assets-preload.md)
|
||||
- [Audio](audio.md)
|
||||
- [Scripting](scripting.md)
|
||||
- [Console](console.md)
|
||||
- [Block models](block-models.md)
|
||||
- [Rigging](rigging.md)
|
||||
- [Block properties](block-properties.md)
|
||||
- [Console](console.md)
|
||||
- [Content-packs](content-packs.md)
|
||||
- [Engine usage recommendations](engine-use-recommendations.md)
|
||||
- [Item properties](item-properties.md)
|
||||
- [Resources (resources.json)](resources.md)
|
||||
- [Rigging](rigging.md)
|
||||
- [Scripting](scripting.md)
|
||||
- [World generator engine](world-generator.md)
|
||||
- [XML UI building](xml-ui-layouts.md)
|
||||
|
||||
@ -10,14 +10,19 @@ Subsections:
|
||||
- [Entities and components](scripting/ecs.md)
|
||||
- [Libraries](#)
|
||||
- [block](scripting/builtins/libblock.md)
|
||||
- [item](scripting/builtins/libitem.md)
|
||||
- [entities](scripting/builtins/libentities.md)
|
||||
- [cameras](scripting/builtins/libcameras.md)
|
||||
- [entities](scripting/builtins/libentities.md)
|
||||
- [gui](scripting/builtins/libgui.md)
|
||||
- [hud](scripting/builtins/libhud.md)
|
||||
- [inventory](scripting/builtins/libinventory.md)
|
||||
- [item](scripting/builtins/libitem.md)
|
||||
- [mat4](scripting/builtins/libmat4.md)
|
||||
- [pack](scripting/builtins/libpack.md)
|
||||
- [player](scripting/builtins/libplayer.md)
|
||||
- [quat](scripting/builtins/libquat.md)
|
||||
- [time](scripting/builtins/libtime.md)
|
||||
- [vec2, vec3, vec4](scripting/builtins/libvecn.md)
|
||||
- [world](scripting/builtins/libworld.md)
|
||||
- [Module core:bit_converter](scripting/modules/core_bit_converter.md)
|
||||
- [Module core:data_buffer](scripting/modules/core_data_buffer.md)
|
||||
- [Module core:vector2, core:vector3](scripting/modules/core_vector2_vector3.md)
|
||||
@ -40,268 +45,3 @@ not part of Lua syntax.
|
||||
require "packid:module_name" -- load Lua module from pack-folder/modules/
|
||||
-- no extension included, just name
|
||||
```
|
||||
|
||||
## *world* library
|
||||
|
||||
## Библиотека *world*
|
||||
|
||||
```python
|
||||
world.get_list() -> tables array {
|
||||
name: str,
|
||||
icon: str
|
||||
}
|
||||
```
|
||||
|
||||
Retuns worlds information: name and preview/icon (loading automatically).
|
||||
|
||||
```python
|
||||
world.get_day_time() -> number
|
||||
```
|
||||
|
||||
Returns current day time in range \[0.0-1.0\] where 0.0 and 1.0 - midnight, 0.5 - noon.
|
||||
|
||||
```python
|
||||
world.set_day_time(time: number)
|
||||
```
|
||||
|
||||
Set day time value.
|
||||
|
||||
```python
|
||||
world.set_day_time_speed(value: number)
|
||||
```
|
||||
|
||||
Sets the specified speed for game time.
|
||||
|
||||
```python
|
||||
world.get_day_time_speed() -> number
|
||||
```
|
||||
|
||||
Returns the speed for game time.
|
||||
|
||||
```python
|
||||
world.get_total_time() -> number
|
||||
```
|
||||
|
||||
Returns total time passed in the world
|
||||
|
||||
```python
|
||||
world.get_seed() -> int
|
||||
```
|
||||
|
||||
Returns world seed.
|
||||
|
||||
``` python
|
||||
world.is_day() -> boolean
|
||||
```
|
||||
|
||||
Proves that this is the current time during the day. From 0.2(8 am) to 0.8(8 pm)
|
||||
|
||||
``` python
|
||||
world.is_night() -> bool
|
||||
```
|
||||
|
||||
Checks that it is the current time at night. From 0.8(8 pm) to 0.2(8 am)
|
||||
|
||||
```python
|
||||
world.exists() -> bool
|
||||
```
|
||||
|
||||
Checks the existence of a world by name.
|
||||
|
||||
|
||||
## *gui* library
|
||||
|
||||
The library contains functions for accessing the properties of UI elements. Instead of gui, you should use an object wrapper that provides access to properties through the __index, __newindex meta methods:
|
||||
|
||||
Example:
|
||||
|
||||
```lua
|
||||
print(document.some_button.text) -- where 'some_button' is an element id
|
||||
document.some_button.text = "new text"
|
||||
```
|
||||
|
||||
```python
|
||||
gui.str(text: str, context: str) -> str
|
||||
```
|
||||
|
||||
Returns translated text.
|
||||
|
||||
```python
|
||||
gui.get_viewport() -> {int, int}
|
||||
```
|
||||
|
||||
Returns size of the main container (window).
|
||||
|
||||
```python
|
||||
gui.get_env(document: str) -> table
|
||||
```
|
||||
|
||||
Returns environment (global variables table) of the specified document.
|
||||
|
||||
```python
|
||||
gui.get_locales_info() -> table of tables where
|
||||
key - locale id following isolangcode_ISOCOUNTRYCODE format
|
||||
value - table {
|
||||
name: str # name of the locale in its language
|
||||
}
|
||||
```
|
||||
|
||||
Returns information about all loaded locales (res/texts/\*).
|
||||
|
||||
## *inventory* library
|
||||
|
||||
Library for inventories interaction.
|
||||
|
||||
```python
|
||||
inventory.get(invid: int, slot: int) -> int, int
|
||||
```
|
||||
|
||||
Requires an inventory ID and slot index. Returns item ID and count. ID = 0 (core:empty) means that slot is empty.
|
||||
|
||||
```python
|
||||
inventory.set(invid: int, slot: int, itemid: int, count: int)
|
||||
```
|
||||
|
||||
Set slot content.
|
||||
|
||||
```python
|
||||
inventory.size(invid: int) -> int
|
||||
```
|
||||
|
||||
Returns inventory size (slots number). Throws an exception if there's no inventory having specified ID.
|
||||
|
||||
```python
|
||||
inventory.add(invid: int, itemid: int, count: int) -> int
|
||||
```
|
||||
|
||||
Add an item to the specified inventory. Returns remaining count if could not to add fully.
|
||||
|
||||
```python
|
||||
inventory.get_block(x: int, y: int, z: int) -> int
|
||||
```
|
||||
|
||||
Returns block inventory ID or 0.
|
||||
|
||||
```python
|
||||
inventory.bind_block(invid: int, x: int, y: int, z: int)
|
||||
```
|
||||
|
||||
Bind inventory to the specified block.
|
||||
|
||||
```python
|
||||
inventory.unbind_block(x: int, y: int, z: int)
|
||||
```
|
||||
|
||||
Unbind inventory from the specified block.
|
||||
|
||||
> [!WARNING]
|
||||
> Unbound inventories will be deleted on world close.
|
||||
|
||||
```python
|
||||
inventory.clone(invid: int) -> int
|
||||
```
|
||||
|
||||
Create inventory copy. Returns the created copy ID.
|
||||
|
||||
```python
|
||||
inventory.move(invA: int, slotA: int, invB: int, slotB: int)
|
||||
```
|
||||
|
||||
Move item from slotA of invA to slotB of invB. invA may be the same as invB.
|
||||
If slotB will be chosen automaticly if argument is not specified.
|
||||
|
||||
## *hud* library
|
||||
|
||||
|
||||
```python
|
||||
hud.open_inventory()
|
||||
```
|
||||
|
||||
Open player inventory
|
||||
|
||||
```python
|
||||
hud.close_inventory()
|
||||
```
|
||||
|
||||
Close inventory
|
||||
|
||||
```python
|
||||
hud.open_block(x: int, y: int, z: int) -> int, str
|
||||
```
|
||||
|
||||
Open block UI and inventory. Throws an exception if block has no UI layout.
|
||||
|
||||
Returns block inventory ID (if *"inventory-size"=0* a virtual inventory will be created), and UI layout ID.
|
||||
|
||||
```python
|
||||
hud.show_overlay(layoutid: str, playerinv: bool)
|
||||
```
|
||||
|
||||
Show overlay with layout specified. Shows player inventory also if playerinv is **true**
|
||||
|
||||
> [!NOTE]
|
||||
> Only one block may be open at same time
|
||||
|
||||
```python
|
||||
hud.open_permanent(layoutid: str)
|
||||
```
|
||||
|
||||
Add element to the screen. The element will be removed on world close only.
|
||||
**inventory** element will be bound to the player inventory.
|
||||
|
||||
```python
|
||||
hud.close(layoutid: str)
|
||||
```
|
||||
|
||||
Remove an element from the screen
|
||||
|
||||
|
||||
```python
|
||||
hud.get_block_inventory() -> int
|
||||
```
|
||||
|
||||
Get open block inventory ID or 0.
|
||||
|
||||
```python
|
||||
hud.get_player() -> int
|
||||
```
|
||||
|
||||
Gives the ID of the player that the UI is bound to.
|
||||
|
||||
```python
|
||||
hud.pause()
|
||||
```
|
||||
|
||||
Opens the pause menu
|
||||
|
||||
```python
|
||||
hud.resume()
|
||||
```
|
||||
|
||||
Closes the pause menu.
|
||||
|
||||
```python
|
||||
hud.is_paused() -> bool
|
||||
```
|
||||
|
||||
Returns true if pause menu is open.
|
||||
|
||||
```python
|
||||
hud.is_inventory_open() -> bool
|
||||
```
|
||||
|
||||
Returns true if inventory is open or overlay is shown.
|
||||
|
||||
### *time* library
|
||||
|
||||
```python
|
||||
time.uptime() -> float
|
||||
```
|
||||
|
||||
Returns time elapsed since the engine started.
|
||||
|
||||
```python
|
||||
time.delta() -> float
|
||||
```
|
||||
|
||||
Returns time elapsed since the last frame.
|
||||
|
||||
41
doc/en/scripting/builtins/libgui.md
Normal file
41
doc/en/scripting/builtins/libgui.md
Normal file
@ -0,0 +1,41 @@
|
||||
# *gui* library
|
||||
|
||||
The library contains functions for accessing the properties of UI elements. Instead of gui, you should use an object wrapper that provides access to properties through the __index, __newindex meta methods:
|
||||
|
||||
Example:
|
||||
|
||||
```lua
|
||||
print(document.some_button.text) -- where 'some_button' is an element id
|
||||
document.some_button.text = "new text"
|
||||
```
|
||||
|
||||
```python
|
||||
gui.str(text: str, context: str) -> str
|
||||
```
|
||||
|
||||
Returns translated text.
|
||||
|
||||
```python
|
||||
gui.get_viewport() -> {int, int}
|
||||
```
|
||||
|
||||
Returns size of the main container (window).
|
||||
|
||||
```python
|
||||
gui.get_env(document: str) -> table
|
||||
```
|
||||
|
||||
Returns environment (global variables table) of the specified document.
|
||||
|
||||
```lua
|
||||
gui.get_locales_info() -> table of tables {
|
||||
name: str
|
||||
}
|
||||
-- where
|
||||
-- key - locale id following isolangcode_ISOCOUNTRYCODE format
|
||||
-- value - table {
|
||||
-- name: str # locale display name
|
||||
-- }
|
||||
```
|
||||
|
||||
Returns information about all loaded locales (res/texts/\*).
|
||||
50
doc/en/scripting/builtins/libhud.md
Normal file
50
doc/en/scripting/builtins/libhud.md
Normal file
@ -0,0 +1,50 @@
|
||||
# *hud* library
|
||||
|
||||
```lua
|
||||
-- Open player inventory.
|
||||
hud.open_inventory()
|
||||
|
||||
-- Close inventory.
|
||||
hud.close_inventory()
|
||||
|
||||
-- Open block UI and inventory.
|
||||
-- Throws an exception if block has no UI layout.
|
||||
-- Returns block inventory ID (if *"inventory-size"=0* a virtual
|
||||
-- inventory will be created), and UI layout ID.
|
||||
hud.open_block(x: int, y: int, z: int) -> int, str
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> Only one block may be open at same time
|
||||
|
||||
```lua
|
||||
-- Show overlay with layout specified.
|
||||
-- Shows player inventory also if playerinv is true.
|
||||
hud.show_overlay(layoutid: str, playerinv: bool)
|
||||
|
||||
-- Add element to the screen.
|
||||
-- The element will be removed on world close only.
|
||||
-- inventory element will be bound to the player inventory.
|
||||
hud.open_permanent(layoutid: str)
|
||||
|
||||
-- Remove an element from the screen.
|
||||
hud.close(layoutid: str)
|
||||
|
||||
-- Get open block inventory ID or 0.
|
||||
hud.get_block_inventory() -> int
|
||||
|
||||
-- Gives the ID of the player that the UI is bound to.
|
||||
hud.get_player() -> int
|
||||
|
||||
-- Opens the pause menu
|
||||
hud.pause()
|
||||
|
||||
-- Closes the pause menu.
|
||||
hud.resume()
|
||||
|
||||
-- Returns true if pause menu is open.
|
||||
hud.is_paused() -> bool
|
||||
|
||||
-- Returns true if inventory is open or overlay is shown.
|
||||
hud.is_inventory_open() -> bool
|
||||
```
|
||||
56
doc/en/scripting/builtins/libinventory.md
Normal file
56
doc/en/scripting/builtins/libinventory.md
Normal file
@ -0,0 +1,56 @@
|
||||
# *inventory* library
|
||||
|
||||
Library for inventories interaction.
|
||||
|
||||
```lua
|
||||
-- ID = 0 (core:empty) means that slot is empty.
|
||||
inventory.get(
|
||||
-- inventory ID
|
||||
invid: int,
|
||||
-- slot index
|
||||
slot: int
|
||||
) -> int, int
|
||||
-- Returns item ID and count.
|
||||
|
||||
-- Set slot content.
|
||||
inventory.set(
|
||||
-- inventory ID
|
||||
invid: int,
|
||||
-- slot index
|
||||
slot: int,
|
||||
-- item index
|
||||
itemid: int,
|
||||
-- item count
|
||||
count: int
|
||||
)
|
||||
|
||||
-- Returns inventory size (slots number).
|
||||
-- Throws an exception if there's no inventory having specified ID.
|
||||
inventory.size(invid: int) -> int
|
||||
|
||||
-- Add an item to the specified inventory.
|
||||
-- Returns remaining count if could not to add fully.
|
||||
inventory.add(invid: int, itemid: int, count: int) -> int
|
||||
|
||||
-- Returns block inventory ID or 0.
|
||||
inventory.get_block(x: int, y: int, z: int) -> int
|
||||
|
||||
-- Bind inventory to the specified block.
|
||||
inventory.bind_block(invid: int, x: int, y: int, z: int)
|
||||
|
||||
-- Unbind inventory from the specified block.
|
||||
inventory.unbind_block(x: int, y: int, z: int)
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> Unbound inventories will be deleted on world close.
|
||||
|
||||
```lua
|
||||
-- Create inventory copy. Returns the created copy ID.
|
||||
inventory.clone(invid: int) -> int
|
||||
|
||||
-- Move item from slotA of invA to slotB of invB.
|
||||
-- invA may be the same as invB.
|
||||
-- If slotB will be chosen automaticly if argument is not specified.
|
||||
inventory.move(invA: int, slotA: int, invB: int, slotB: int)
|
||||
```
|
||||
13
doc/en/scripting/builtins/libtime.md
Normal file
13
doc/en/scripting/builtins/libtime.md
Normal file
@ -0,0 +1,13 @@
|
||||
# *time* library
|
||||
|
||||
```python
|
||||
time.uptime() -> float
|
||||
```
|
||||
|
||||
Returns time elapsed since the engine started.
|
||||
|
||||
```python
|
||||
time.delta() -> float
|
||||
```
|
||||
|
||||
Returns time elapsed since the last frame.
|
||||
40
doc/en/scripting/builtins/libworld.md
Normal file
40
doc/en/scripting/builtins/libworld.md
Normal file
@ -0,0 +1,40 @@
|
||||
# *world* library
|
||||
|
||||
```lua
|
||||
world.get_list() -> tables array {
|
||||
-- world name
|
||||
name: str,
|
||||
-- world icon/preview (loading automatically)
|
||||
icon: str
|
||||
}
|
||||
|
||||
-- Returns current day time in range \[0.0-1.0\]
|
||||
-- where 0.0 and 1.0 - midnight, 0.5 - noon.
|
||||
world.get_day_time() -> number
|
||||
|
||||
-- Set day time value.
|
||||
world.set_day_time(time: number)
|
||||
|
||||
-- Sets the specified day time cycle speed.
|
||||
world.set_day_time_speed(value: number)
|
||||
|
||||
-- Returns the day time cycle speed.
|
||||
world.get_day_time_speed() -> number
|
||||
|
||||
-- Returns total time passed in the world.
|
||||
world.get_total_time() -> number
|
||||
|
||||
-- Returns world seed.
|
||||
world.get_seed() -> int
|
||||
|
||||
-- Proves that this is the current time during the day
|
||||
-- from 0.333(8 am) to 0.833(8 pm).
|
||||
world.is_day() -> boolean
|
||||
|
||||
-- Checks that it is the current time at night
|
||||
-- from 0.833(8 pm) to 0.333(8 am).
|
||||
world.is_night() -> bool
|
||||
|
||||
-- Checks the existence of a world by name.
|
||||
world.exists() -> bool
|
||||
```
|
||||
464
doc/en/world-generator.md
Normal file
464
doc/en/world-generator.md
Normal file
@ -0,0 +1,464 @@
|
||||
# World Generator
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Basic concepts](#basic-concepts)
|
||||
- [Global variables](#global-variables)
|
||||
- [Configuration file](#configuration-file)
|
||||
- [Fragments](#fragments)
|
||||
- [Structures](#structures)
|
||||
- [Biomes](#biomes)
|
||||
* [Biome parameters](#biome-parameters)
|
||||
* [Biome selection](#biome-selection)
|
||||
- [Heightmap](#heightmap)
|
||||
* [Constructor](#constructor)
|
||||
* [Unary operations](#unary-operations)
|
||||
* [binary operations](#binary-operations)
|
||||
* [heightmap:dump(...)](#heightmapdump)
|
||||
* [heightmap:noise(...)](#heightmapnoise)
|
||||
* [heightmap:cellnoise(...)](#heightmapcellnoise)
|
||||
* [heightmap:resize(...)](#heightmapresize)
|
||||
* [heightmap:crop(...)](#heightmapcrop)
|
||||
* [heightmap:at(x, y)](#heightmapatx-y)
|
||||
- [VoxelFragment (fragment in Lua)](#voxelfragment-fragment-in-lua)
|
||||
- [Generating a height map](#generating-a-height-map)
|
||||
- [Manual structures placement](#manual-structures-placement)
|
||||
* [Structure/tunnel placements](#structuretunnel-placements)
|
||||
* [Small structures placement](#small-structures-placement)
|
||||
* [Wide structures placement](#wide-structures-placement)
|
||||
- [Structural air](#structural-air)
|
||||
|
||||
## Basic concepts
|
||||
|
||||
Concepts used in the text below.
|
||||
|
||||
- **Combined array/object** - TOML or JSON file that is combined from several versions in different packs, which allows adding data to it from outside. The fields of the combined object are overwritten in order from first to last, just like other resources in the packs. In the case of a combined array, a check for duplicates is **not** performed.
|
||||
- **Biome** - information that determines what blocks and what layers the terrain is generated from, as well as a set of plants, structures.
|
||||
- **Plant** - a block randomly placed on the surface.
|
||||
- **Small structure** - a structure whose size does not exceed the size of a chunk. Example: trees.
|
||||
|
||||
## Configuration file
|
||||
|
||||
The world generator is recognized if the file `generators/generator_name.toml` is present. Other files related to the generator are located in the directory `generators/generator_name.files/`:
|
||||
- biomes.toml - biome definitions
|
||||
- structures.toml - structure definitions
|
||||
- script.lua - generator script
|
||||
- fragments - directory where fragment files are located
|
||||
|
||||
The main properties described in the configuration file:
|
||||
- **caption** - the generator display name. By default, it is generated from the id.
|
||||
- **biome-parameters** - the number of biome selection parameters (from 0 to 4). Default: 0.
|
||||
- **sea-level** - sea level (below this level, sea-layers will be generated instead of air). Default: 0.
|
||||
- **biomes-bpd** - number of blocks per point of the biome selection parameter map. Default: 8.
|
||||
- **heights-bpd** - number of blocks per point of the height map. Default: 8.
|
||||
- **wide-structs-chunks-radius** - maximum radius for placing 'wide' structures, measured in chunks.
|
||||
|
||||
## Global variables
|
||||
|
||||
The following variables are available in the generator script:
|
||||
|
||||
- `SEED` - world generation seed
|
||||
- `__DIR__` - generator directory (`pack:generators/generator_name.files/`)
|
||||
- `__FILE__` - script file (`pack:generators/generator_name.files/script.lua`)
|
||||
|
||||
## Fragments
|
||||
|
||||
A fragment is a region of the world, like a chunk, saved for later use, limited by a certain width, height and length. A fragment can contain data not only blocks, but also the block inventories and entities. Unlike a chunk, the size of a fragment is arbitrary.
|
||||
|
||||
Fragment can be created using the `fragment.save` command, or the `generation.create_fragment` function.
|
||||
|
||||
Fragments used by the generator must present in the directory:
|
||||
`generators/generator_name.files/fragments/`
|
||||
|
||||
## Structures
|
||||
|
||||
A structure is a set of rules for inserting a fragment into the world by the generator. It currently has no properties, being created as empty objects in the `generators/generator_name.files/structures.json` file. Example:
|
||||
```lua
|
||||
{
|
||||
"tree0": {},
|
||||
"tree1": {},
|
||||
"tree2": {},
|
||||
"tower": {},
|
||||
"coal_ore0": {}
|
||||
}
|
||||
```
|
||||
|
||||
Currently, the name of the structure must match the name of the fragment used.
|
||||
|
||||
## Biomes
|
||||
|
||||
A biome defines what blocks and layers the terrain is generated from, as well as a set of plants and structures.
|
||||
|
||||
Biomes are defined in a combined object:
|
||||
`generators/generator_name.files/biomes.toml`
|
||||
|
||||
Let's look at the biome structure using the forest example from the base:demo generator:
|
||||
|
||||
```toml
|
||||
[forest]
|
||||
parameters = [
|
||||
{weight=1, value=1},
|
||||
{weight=0.5, value=0.2}
|
||||
]
|
||||
layers = [
|
||||
{below-sea-level=false, height=1, block="base:grass_block"},
|
||||
{below-sea-level=false, height=7, block="base:dirt"},
|
||||
{height=-1, block="base:stone"},
|
||||
{height=1, block="base:bazalt"}
|
||||
]
|
||||
sea-layers = [
|
||||
{height=-1, block="base:water"}
|
||||
]
|
||||
plant-chance = 0.4
|
||||
plants = [
|
||||
{weight=1, block="base:grass"},
|
||||
{weight=0.03, block="base:flower"}
|
||||
]
|
||||
structure-chance = 0.032
|
||||
structures = [
|
||||
{name="tree0", weight=1},
|
||||
{name="tree1", weight=1},
|
||||
{name="tree2", weight=1},
|
||||
{name="tower", weight=0.002}
|
||||
]
|
||||
```
|
||||
|
||||
- key 'forest' - biome name
|
||||
- parameters - weights and central values of the parameters for the biome. See the [biome selection](#biome-selection) section. The number of entries must match the number of biome selection parameters.
|
||||
- layers - block layers from top to bottom.
|
||||
- height - layer height in blocks. -1 is used to mark the filler layer, of which there can only be one. Its height is calculated automatically.
|
||||
- block - full block name
|
||||
- below-sea-level - whether the layer can be generated below sea level (example: turf). If false, when generated below sea level, the layer will be replaced by the next one.
|
||||
- sea-layers - ocean layers. The position of the top layer coincides with the sea level height.
|
||||
- plant-chance - probability of generating a plant on a surface block.
|
||||
- plants - plants randomly placed on the surface.
|
||||
- weight - weight directly affecting the chance of selecting a specific plant.
|
||||
- block - plant block
|
||||
- structure-chance - probability of generating a small structure on a surface block.
|
||||
- structures - structures randomly placed on the surface.
|
||||
- name - name of the structure declared in `structures.json`.
|
||||
- weight - weight directly affecting the chance of choosing a specific structure.
|
||||
|
||||
### Biome Parameters
|
||||
|
||||
The generator parameter `biome-parameters` defines the number of biome selection parameters (examples: temperature, humidity).
|
||||
|
||||
Biome parameter value maps are generated in the same way as height maps.
|
||||
|
||||
It is required to implement the function:
|
||||
```lua
|
||||
-- x, y - map start position (in dots)
|
||||
-- w, h - map width and height (in dots)
|
||||
-- bpd - (blocks per dot) number of blocks per dot (scale)
|
||||
function generate_biome_parameters(x, y, w, h, bpd)
|
||||
-- creating heightmaps for each biome parameter
|
||||
-- ...
|
||||
return comma-separated_maps
|
||||
end
|
||||
|
||||
-- example
|
||||
function generate_biome_parameters(x, y, w, h, s)
|
||||
-- temperature map
|
||||
local tempmap = Heightmap(w, h)
|
||||
tempmap.noiseSeed = SEED + 5324
|
||||
tempmap:noise({x, y}, 0.04*s, 6)
|
||||
tempmap:pow(3)
|
||||
-- humidity map
|
||||
local hummap = Heightmap(w, h)
|
||||
hummap.noiseSeed = SEED + 953
|
||||
hummap:noise({x, y}, 0.04*s, 6)
|
||||
hummap:pow(3)
|
||||
return tempmap, hummap
|
||||
end
|
||||
```
|
||||
|
||||
### Biome selection
|
||||
|
||||
After generating the parameter maps for each biome, scores are calculated for all parameters:
|
||||
|
||||
$score = \frac{|V - V_b|}{W_b}$
|
||||
|
||||
Where $V$ is the parameter value, $V_b$ is the central parameter value for the biome, $W_b$ is the biome weight for the parameter.
|
||||
|
||||
The generator selects the biome with the **least** sum of parameter scores.
|
||||
|
||||
>[!WARNING]
|
||||
> If the parameter values and weights are not set up correctly, biomes may have an effect similar to the depth conflict in 3D graphics when two surfaces overlap.
|
||||
>
|
||||
In the case of biomes, the pattern looks random due to the distortion of these 'surfaces' by the noise used to generate the parameter maps.
|
||||
>
|
||||
To get rid of the effect, you can either adjust the weights or parameter values of the biomes, or increase the difference in the generation of the parameter maps.
|
||||
|
||||
## Heightmap
|
||||
|
||||
Heightmap is a class for working with heightmaps (arbitrarily sized matrices of floating point numbers).
|
||||
|
||||
### Constructor
|
||||
|
||||
The heightmap constructor requires integer width and height.
|
||||
|
||||
```lua
|
||||
local map = Heightmap(width, height)
|
||||
```
|
||||
|
||||
### Unary Operations
|
||||
|
||||
Operations apply to all height values.
|
||||
|
||||
```lua
|
||||
map:abs()
|
||||
```
|
||||
|
||||
Casts height values to absolute.
|
||||
|
||||
### Binary Operations
|
||||
|
||||
Operations using a second map or a scalar.
|
||||
|
||||
Arithmetic operations:
|
||||
|
||||
```lua
|
||||
-- Addition
|
||||
map:add(value: Heightmap|number)
|
||||
|
||||
-- Subtraction
|
||||
map:sub(value: Heightmap|number)
|
||||
|
||||
-- Multiplication
|
||||
map:mul(value: Heightmap|number)
|
||||
|
||||
-- Exponentiation
|
||||
map:pow(value: Heightmap|number)
|
||||
```
|
||||
|
||||
Other operations:
|
||||
|
||||
```lua
|
||||
-- Minimum
|
||||
map:min(value: Heightmap|number)
|
||||
|
||||
-- Maximum
|
||||
map:max(value: Heightmap|number)
|
||||
|
||||
-- Mixing
|
||||
map:mixin(value: Heightmap|number, t: Heightmap|number)
|
||||
-- t - mixing factor from 0.0 to 1.0
|
||||
-- mixing is performed according to the formula:
|
||||
-- map_value * (1.0 - t) + value * t
|
||||
```
|
||||
|
||||
### heightmap:dump(...)
|
||||
|
||||
A method used for debugging, creates an image based on a heightmap by converting values from the range `[-1.0, 1.0]` to brightness values `[0, 255]`, saving it to the specified file.
|
||||
|
||||
```lua
|
||||
map:dump('export:test.png')
|
||||
```
|
||||
|
||||
### heightmap:noise(...)
|
||||
|
||||
A method that generates simplex noise, adding it to the existing values.
|
||||
|
||||
The noise seed can be specified in the `map.noiseSeed` field.
|
||||
|
||||
```lua
|
||||
map:noise(
|
||||
-- coordinate offset
|
||||
offset: {number, number},
|
||||
-- coordinate scaling factor
|
||||
scale: number,
|
||||
-- number of noise octaves (default: 1)
|
||||
[optional] octaves: integer,
|
||||
-- noise amplitude multiplier (default: 1.0)
|
||||
[optional] multiplier: number,
|
||||
-- X coordinate offset map for noise generation
|
||||
[optional] shiftMapX: Heightmap,
|
||||
-- Y coordinate offset map for noise generation
|
||||
[optional] shiftMapY: Heightmap,
|
||||
) -> nil
|
||||
```
|
||||
|
||||
Noise visualization with octaves 1, 2, 3, 4, and 5.
|
||||
|
||||

|
||||
|
||||
### heightmap:cellnoise(...)
|
||||
|
||||
Analog of heightmap:noise that generates cellular noise.
|
||||
|
||||
The noise seed can be specified in the `map.noiseSeed` field.
|
||||
|
||||

|
||||
|
||||
### heightmap:resize(...)
|
||||
|
||||
```lua
|
||||
map:resize(width, height, interpolation)
|
||||
```
|
||||
|
||||
Changes the heightmap size.
|
||||
|
||||
Available interpolation modes:
|
||||
- 'nearest' - no interpolation
|
||||
- 'linear' - bilinear interpolation
|
||||
|
||||
### heightmap:crop(...)
|
||||
|
||||
```lua
|
||||
map:crop(x, y, width, height)
|
||||
```
|
||||
|
||||
Crops the heightmap to the specified area.
|
||||
|
||||
### heightmap:at(x, y)
|
||||
|
||||
```lua
|
||||
map:at(x, y) --> number
|
||||
```
|
||||
|
||||
Returns the height value at the specified position.
|
||||
|
||||
## VoxelFragment (fragment in Lua)
|
||||
|
||||
A fragment is created by calling the function:
|
||||
```lua
|
||||
generation.create_fragment(
|
||||
-- point A
|
||||
a: vec3,
|
||||
-- point B
|
||||
b: vec3,
|
||||
-- automatically crop the fragment if possible
|
||||
crop: bool
|
||||
) -> VoxelFragment
|
||||
```
|
||||
|
||||
A fragment can be loaded from a file:
|
||||
```lua
|
||||
generation.load_fragment(
|
||||
-- fragment file
|
||||
filename: str
|
||||
) -> VoxelFragment
|
||||
```
|
||||
|
||||
A fragment can be saved to a file:
|
||||
```lua
|
||||
generation.save_fragment(
|
||||
-- fragment to save
|
||||
fragment: VoxelFragment,
|
||||
-- file
|
||||
filename: str
|
||||
) -> nil
|
||||
```
|
||||
|
||||
The fragment size is available as the `size` property.
|
||||
|
||||
A fragment can be cropped to fit its contents (air is ignored) by calling the `fragment:crop()` method.
|
||||
|
||||
## Generating a height map
|
||||
|
||||
By default, the engine generates a height map consisting of zeros.
|
||||
|
||||
To generate custom heightmaps, you need to implement the function:
|
||||
|
||||
```lua
|
||||
function generate_heightmap(
|
||||
x, y, -- offset of the heightmap
|
||||
w, h, -- size of the heightmap expected by the engine
|
||||
bpd, -- number of blocks per dot - scale
|
||||
[optional] inputs -- array of input maps of biome parameters
|
||||
-- (see the heightmap-inputs property of the generator)
|
||||
) --> Heightmap
|
||||
```
|
||||
|
||||
An example of generating a heightmap from simplex noise with reduction
|
||||
to the desired range:
|
||||
|
||||
```lua
|
||||
function generate_heightmap(x, y, w, h, bpd)
|
||||
-- create a heightmap with a given size
|
||||
local map = Heightmap(w, h)
|
||||
-- set the noise seed
|
||||
map.noiseSeed = SEED
|
||||
-- noise with a scale of 1/10 by 4 octaves with an amplitude of 0.5
|
||||
map:noise({x, y}, 0.1*bpd, 4, 0.5)
|
||||
-- shift heights to positive range
|
||||
map:add(0.5)
|
||||
return map
|
||||
end
|
||||
```
|
||||
|
||||
## Manual structures placement
|
||||
|
||||
### Structure/tunnel placements
|
||||
|
||||
Placement of a structure/line is an array of a given
|
||||
set of parameters.
|
||||
|
||||
Structure:
|
||||
```lua
|
||||
{structure_name, structure_position, rotation, [optional] priority}
|
||||
```
|
||||
|
||||
Where:
|
||||
- structure_name - a string containing the name of the structure, registered in structures.toml.
|
||||
- structure_position - a vec3 (an array of three numbers) relative to the position of the chunk.
|
||||
- rotation - a number from 0 to 3 indicating the rotation of the structure along the Y axis.
|
||||
- priority - a number determining the order in which structures are placed. Structures with lower priority are overlapped by structures with higher priority.
|
||||
|
||||
Tunnel:
|
||||
```lua
|
||||
{":line", filler_block, point_a, point_b, radius}
|
||||
```
|
||||
|
||||
Where:
|
||||
- filler_block - the numeric id of the block that the structure will consist of.
|
||||
- point_a, point_b - vec3, vec3 positions of the start and end of the tunnel.
|
||||
- radius - radius of the tunnel in blocks
|
||||
|
||||
### Small structures placement
|
||||
|
||||
```lua
|
||||
function place_structures(
|
||||
x, z, -- start position of the region in blocks
|
||||
w, d, -- size of the region in blocks
|
||||
heights, -- height map of the chunk
|
||||
chunk_height, -- height of the chunk
|
||||
) --> array of structure placements
|
||||
```
|
||||
|
||||
Structures can be placed outside the chunk, but not more than one chunk away.
|
||||
|
||||
Example:
|
||||
|
||||
```lua
|
||||
function place_structures(x, z, w, d, hmap, chunk_height)
|
||||
local placements = {}
|
||||
local height = hmap:at(w/2, h/2) * chunk_height
|
||||
|
||||
-- places the tower in the center of the chunk
|
||||
table.insert(placements, {
|
||||
'tower', {w/2, height, d/2}, math.random() * 4, 2
|
||||
})
|
||||
return placements
|
||||
end
|
||||
```
|
||||
|
||||
### Wide structures placement
|
||||
|
||||
Structures and tunnels can be placed outside a chunk, but no further than the number of chunks specified in the `wide-structs-chunks-radius` property of the generator.
|
||||
|
||||
Unlike the previous function, no heightmap is passed here, since the call occurs early in the chunk generation.
|
||||
|
||||
```lua
|
||||
function place_structures_wide(
|
||||
x, z, -- start position of the region in blocks
|
||||
w, d, -- size of the region in blocks
|
||||
chunk_height, -- height of the chunk
|
||||
) --> array of structure / tunnel placements
|
||||
```
|
||||
|
||||
## Structural Air
|
||||
|
||||
`core:struct_air` - a block that should be used in chunks to mark empty space that should not be filled with blocks when generated in the world.
|
||||
|
||||
<image src="../../res/textures/blocks/struct_air.png" width="128px" height="128px" style="image-rendering: pixelated">
|
||||
BIN
doc/images/cell-noise.gif
Normal file
BIN
doc/images/cell-noise.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 27 KiB |
BIN
doc/images/simplex-noise.gif
Normal file
BIN
doc/images/simplex-noise.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 140 KiB |
@ -1,16 +1,21 @@
|
||||
# Документация
|
||||
|
||||
Документация версии движка 0.23, находящейся в разработке.
|
||||
|
||||
[Документация стабильной версии (0.22.x)](https://github.com/MihailRis/VoxelEngine-Cpp/blob/release-0.22/doc/ru/main-page.md)
|
||||
|
||||
## Разделы
|
||||
|
||||
- [Рекомендации по использованию движка](engine-use-recommendations.md)
|
||||
- [XML разметка интерфейса](xml-ui-layouts.md)
|
||||
- [Аудио](audio.md)
|
||||
- [Движок генерации мира](world-generator.md)
|
||||
- [Консоль](console.md)
|
||||
- [Контент‐паки](content-packs.md)
|
||||
- [Модели блоков](block-models.md)
|
||||
- [Предзагрузка ассетов](assets-preload.md)
|
||||
- [Рекомендации по использованию движка](engine-use-recommendations.md)
|
||||
- [Ресурсы (resources.json)](resources.md)
|
||||
- [Риггинг](rigging.md)
|
||||
- [Свойства блоков](block-properties.md)
|
||||
- [Свойства предметов](item-properties.md)
|
||||
- [XML разметка интерфейса](xml-ui-layouts.md)
|
||||
- [Предзагрузка ассетов](assets-preload.md)
|
||||
- [Аудио](audio.md)
|
||||
- [Скриптинг](scripting.md)
|
||||
- [Консоль](console.md)
|
||||
- [Модели блоков](block-models.md)
|
||||
- [Риггинг](rigging.md)
|
||||
- [Ресурсы (resources.json)](resources.md)
|
||||
|
||||
@ -10,14 +10,19 @@
|
||||
- [Сущности и компоненты](scripting/ecs.md)
|
||||
- [Библиотеки](#)
|
||||
- [block](scripting/builtins/libblock.md)
|
||||
- [item](scripting/builtins/libitem.md)
|
||||
- [entities](scripting/builtins/libentities.md)
|
||||
- [cameras](scripting/builtins/libcameras.md)
|
||||
- [entities](scripting/builtins/libentities.md)
|
||||
- [gui](scripting/builtins/libgui.md)
|
||||
- [hud](scripting/builtins/libhud.md)
|
||||
- [inventory](scripting/builtins/libinventory.md)
|
||||
- [item](scripting/builtins/libitem.md)
|
||||
- [mat4](scripting/builtins/libmat4.md)
|
||||
- [pack](scripting/builtins/libpack.md)
|
||||
- [player](scripting/builtins/libplayer.md)
|
||||
- [quat](scripting/builtins/libquat.md)
|
||||
- [time](scripting/builtins/libtime.md)
|
||||
- [vec2, vec3, vec4](scripting/builtins/libvecn.md)
|
||||
- [world](scripting/builtins/libworld.md)
|
||||
- [Модуль core:bit_converter](scripting/modules/core_bit_converter.md)
|
||||
- [Модуль core:data_buffer](scripting/modules/core_data_buffer.md)
|
||||
- [Модули core:vector2, core:vector3](scripting/modules/core_vector2_vector3.md)
|
||||
@ -37,263 +42,3 @@
|
||||
```lua
|
||||
require "контентпак:имя_модуля" -- загружает lua модуль из папки modules (расширение не указывается)
|
||||
```
|
||||
|
||||
## Библиотека *world*
|
||||
|
||||
```python
|
||||
world.get_list() -> массив таблиц {
|
||||
name: str,
|
||||
icon: str
|
||||
}
|
||||
```
|
||||
|
||||
Возвращает информацию о мирах: название и предпросмотр (автоматически загружаемая текстура).
|
||||
|
||||
```python
|
||||
world.get_day_time() -> number
|
||||
```
|
||||
|
||||
Возвращает текущее игровое время от 0.0 до 1.0, где 0.0 и 1.0 - полночь, 0.5 - полдень.
|
||||
|
||||
```python
|
||||
world.set_day_time(time: number)
|
||||
```
|
||||
|
||||
Устанавливает указанное игровое время.
|
||||
|
||||
```python
|
||||
world.set_day_time_speed(value: number)
|
||||
```
|
||||
|
||||
Устанавливает указанную скорость для игрового времени.
|
||||
|
||||
```python
|
||||
world.get_day_time_speed() -> number
|
||||
```
|
||||
|
||||
Возвращает скорость для игрового времени.
|
||||
|
||||
```python
|
||||
world.get_total_time() -> number
|
||||
```
|
||||
|
||||
Возвращает общее суммарное время, прошедшее в мире
|
||||
|
||||
```python
|
||||
world.get_seed() -> int
|
||||
```
|
||||
|
||||
Возвращает зерно мира.
|
||||
|
||||
```python
|
||||
world.exists() -> bool
|
||||
```
|
||||
|
||||
Проверяет существование мира по имени.
|
||||
|
||||
```python
|
||||
world.is_day() -> bool
|
||||
```
|
||||
|
||||
Проверяет является ли текущее время днём. От 0.2(8 утра) до 0.8(8 вечера)
|
||||
|
||||
```python
|
||||
world.is_night() -> bool
|
||||
```
|
||||
|
||||
Проверяет является ли текущее время ночью. От 0.8(8 вечера) до 0.2(8 утра)
|
||||
|
||||
## Библиотека *gui*
|
||||
|
||||
Библиотека содержит функции для доступа к свойствам UI элементов. Вместо gui следует использовать объектную обертку, предоставляющую доступ к свойствам через мета-методы __index, __newindex:
|
||||
|
||||
```lua
|
||||
print(document.some_button.text) -- где 'some_button' - id элемета
|
||||
document.some_button.text = "новый текст"
|
||||
```
|
||||
|
||||
В скрипте макета `layouts/файл_макета.xml` - `layouts/файл_макета.xml.lua` уже доступна переменная **document** содержащая объект класса Document
|
||||
|
||||
```python
|
||||
gui.str(text: str, context: str) -> str
|
||||
```
|
||||
|
||||
Возращает переведенный текст.
|
||||
|
||||
```python
|
||||
gui.get_viewport() -> {int, int}
|
||||
```
|
||||
|
||||
Возвращает размер главного контейнера (окна).
|
||||
|
||||
```python
|
||||
gui.get_env(document: str) -> table
|
||||
```
|
||||
|
||||
Возвращает окружение (таблица глобальных переменных) указанного документа.
|
||||
|
||||
```python
|
||||
get_locales_info() -> таблица таблиц где
|
||||
ключ - id локали в формате isolangcode_ISOCOUNTRYCODE
|
||||
значение - таблица {
|
||||
name: str # название локали на её языке
|
||||
}
|
||||
```
|
||||
|
||||
Возвращает информацию о всех загруженных локалях (res/texts/\*).
|
||||
|
||||
## Библиотека *inventory*
|
||||
|
||||
Библиотека функций для работы с инвентарем.
|
||||
|
||||
```python
|
||||
inventory.get(invid: int, slot: int) -> int, int
|
||||
```
|
||||
|
||||
Принимает id инвентаря и индекс слота. Возвращает id предмета и его количество. id = 0 (core:empty) обозначает, что слот пуст.
|
||||
|
||||
```python
|
||||
inventory.set(invid: int, slot: int, itemid: int, count: int)
|
||||
```
|
||||
|
||||
Устанавливает содержимое слота.
|
||||
|
||||
```python
|
||||
inventory.size(invid: int) -> int
|
||||
```
|
||||
|
||||
Возращает размер инвентаря (число слотов). Если указанного инвентаря не существует, бросает исключение.
|
||||
|
||||
```python
|
||||
inventory.add(invid: int, itemid: int, count: int) -> int
|
||||
```
|
||||
|
||||
Добавляет предмет в инвентарь. Если не удалось вместить все количество, возвращает остаток.
|
||||
|
||||
```python
|
||||
inventory.get_block(x: int, y: int, z: int) -> int
|
||||
```
|
||||
|
||||
Функция возвращает id инвентаря указанного блока. Если блок не может иметь инвентарь - возвращает 0.
|
||||
|
||||
```python
|
||||
inventory.bind_block(invid: int, x: int, y: int, z: int)
|
||||
```
|
||||
|
||||
Привязывает указанный инвентарь к блоку.
|
||||
|
||||
```python
|
||||
inventory.unbind_block(x: int, y: int, z: int)
|
||||
```
|
||||
|
||||
Отвязывает инвентарь от блока.
|
||||
|
||||
> [!WARNING]
|
||||
> Инвентари, не привязанные ни к одному из блоков, удаляются при выходе из мира.
|
||||
|
||||
```python
|
||||
inventory.clone(invid: int) -> int
|
||||
```
|
||||
|
||||
Создает копию инвентаря и возвращает id копии. Если копируемого инвентаря не существует, возвращает 0.
|
||||
|
||||
```python
|
||||
inventory.move(invA: int, slotA: int, invB: int, slotB: int)
|
||||
```
|
||||
|
||||
Перемещает предмет из slotA инвентаря invA в slotB инвентаря invB.
|
||||
invA и invB могут указывать на один инвентарь.
|
||||
slotB будет выбран автоматически, если не указывать явно.
|
||||
|
||||
## Библиотека hud
|
||||
|
||||
```python
|
||||
hud.open_inventory()
|
||||
```
|
||||
|
||||
Открывает инвентарь
|
||||
|
||||
```python
|
||||
hud.close_inventory()
|
||||
```
|
||||
|
||||
Закрывает инвентарь
|
||||
|
||||
```python
|
||||
hud.open_block(x: int, y: int, z: int) -> int, str
|
||||
```
|
||||
|
||||
Открывает инвентарь и UI блока. Если блок не имеет макета UI - бросается исключение.
|
||||
|
||||
Возвращает id инвентаря блока (при *"inventory-size"=0* создаётся виртуальный инвентарь, который удаляется после закрытия), и id макета UI.
|
||||
|
||||
```python
|
||||
hud.show_overlay(layoutid: str, playerinv: bool)
|
||||
```
|
||||
|
||||
Показывает элемент в режиме оверлея. Также показывает инвентарь игрока, если playerinv - **true**
|
||||
|
||||
> [!NOTE]
|
||||
> Одновременно может быть открыт только один блок
|
||||
|
||||
```python
|
||||
hud.open_permanent(layoutid: str)
|
||||
```
|
||||
|
||||
Добавляет постоянный элемент на экран. Элемент не удаляется при закрытии инвентаря. Чтобы не перекрывать затенение в режиме инвентаря нужно установить z-index элемента меньшим чем -1. В случае тега inventory, произойдет привязка слотов к инвентарю игрока.
|
||||
|
||||
```python
|
||||
hud.close(layoutid: str)
|
||||
```
|
||||
|
||||
Удаляет элемент с экрана.
|
||||
|
||||
```python
|
||||
hud.get_block_inventory() -> int
|
||||
```
|
||||
|
||||
Дает ID инвентаря открытого блока или 0.
|
||||
|
||||
```python
|
||||
hud.get_player() -> int
|
||||
```
|
||||
|
||||
Дает ID игрока, к которому привязан пользовательский интерфейс.
|
||||
|
||||
```python
|
||||
hud.pause()
|
||||
```
|
||||
|
||||
Открывает меню паузы.
|
||||
|
||||
```python
|
||||
hud.resume()
|
||||
```
|
||||
|
||||
Закрывает меню паузы.
|
||||
|
||||
```python
|
||||
hud.is_paused() -> bool
|
||||
```
|
||||
|
||||
Возвращает true если открыто меню паузы.
|
||||
|
||||
```python
|
||||
hud.is_inventory_open() -> bool
|
||||
```
|
||||
|
||||
Возвращает true если открыт инвентарь или оверлей.
|
||||
|
||||
## Библиотека time
|
||||
|
||||
```python
|
||||
time.uptime() -> float
|
||||
```
|
||||
|
||||
Возвращает время с момента запуска движка в секундах.
|
||||
|
||||
```python
|
||||
time.delta() -> float
|
||||
```
|
||||
|
||||
Возвращает дельту времени (время прошедшее с предыдущего кадра)
|
||||
|
||||
38
doc/ru/scripting/builtins/libgui.md
Normal file
38
doc/ru/scripting/builtins/libgui.md
Normal file
@ -0,0 +1,38 @@
|
||||
# Библиотека *gui*
|
||||
|
||||
Библиотека содержит функции для доступа к свойствам UI элементов. Вместо gui следует использовать объектную обертку, предоставляющую доступ к свойствам через мета-методы __index, __newindex:
|
||||
|
||||
```lua
|
||||
print(document.some_button.text) -- где 'some_button' - id элемета
|
||||
document.some_button.text = "новый текст"
|
||||
```
|
||||
|
||||
В скрипте макета `layouts/файл_макета.xml` - `layouts/файл_макета.xml.lua` уже доступна переменная **document** содержащая объект класса Document
|
||||
|
||||
```python
|
||||
gui.str(text: str, context: str) -> str
|
||||
```
|
||||
|
||||
Возращает переведенный текст.
|
||||
|
||||
```python
|
||||
gui.get_viewport() -> {int, int}
|
||||
```
|
||||
|
||||
Возвращает размер главного контейнера (окна).
|
||||
|
||||
```python
|
||||
gui.get_env(document: str) -> table
|
||||
```
|
||||
|
||||
Возвращает окружение (таблица глобальных переменных) указанного документа.
|
||||
|
||||
```python
|
||||
gui.get_locales_info() -> таблица таблиц где
|
||||
ключ - id локали в формате isolangcode_ISOCOUNTRYCODE
|
||||
значение - таблица {
|
||||
name: str # название локали на её языке
|
||||
}
|
||||
```
|
||||
|
||||
Возвращает информацию о всех загруженных локалях (res/texts/\*).
|
||||
52
doc/ru/scripting/builtins/libhud.md
Normal file
52
doc/ru/scripting/builtins/libhud.md
Normal file
@ -0,0 +1,52 @@
|
||||
# Библиотека hud
|
||||
|
||||
```lua
|
||||
-- Открывает инвентарь.
|
||||
hud.open_inventory()
|
||||
|
||||
-- Закрывает инвентарь.
|
||||
hud.close_inventory()
|
||||
|
||||
-- Открывает инвентарь и UI блока.
|
||||
-- Если блок не имеет макета UI - бросается исключение.
|
||||
-- Возвращает id инвентаря блока
|
||||
-- (при *"inventory-size"=0* создаётся виртуальный инвентарь,
|
||||
-- который удаляется после закрытия), и id макета UI.
|
||||
hud.open_block(x: int, y: int, z: int) -> int, str
|
||||
```
|
||||
|
||||
> [!NOTE]
|
||||
> Одновременно может быть открыт только один блок
|
||||
|
||||
```lua
|
||||
-- Показывает элемент в режиме оверлея.
|
||||
-- Также показывает инвентарь игрока, если playerinv - **true**.
|
||||
hud.show_overlay(layoutid: str, playerinv: bool)
|
||||
|
||||
-- Добавляет постоянный элемент на экран. Элемент не удаляется при
|
||||
-- закрытии инвентаря. Чтобы не перекрывать затенение в режиме
|
||||
-- инвентаря нужно установить z-index элемента меньшим чем -1.
|
||||
-- В случае тега inventory, произойдет привязка слотов к инвентарю игрока.
|
||||
hud.open_permanent(layoutid: str)
|
||||
|
||||
-- Удаляет элемент с экрана.
|
||||
hud.close(layoutid: str)
|
||||
|
||||
-- Дает ID инвентаря открытого блока или 0.
|
||||
hud.get_block_inventory() -> int
|
||||
|
||||
-- Дает ID игрока, к которому привязан пользовательский интерфейс.
|
||||
hud.get_player() -> int
|
||||
|
||||
-- Открывает меню паузы.
|
||||
hud.pause()
|
||||
|
||||
-- Закрывает меню паузы.
|
||||
hud.resume()
|
||||
|
||||
-- Возвращает true если открыто меню паузы.
|
||||
hud.is_paused() -> bool
|
||||
|
||||
-- Возвращает true если открыт инвентарь или оверлей.
|
||||
hud.is_inventory_open() -> bool
|
||||
```
|
||||
66
doc/ru/scripting/builtins/libinventory.md
Normal file
66
doc/ru/scripting/builtins/libinventory.md
Normal file
@ -0,0 +1,66 @@
|
||||
# Библиотека *inventory*
|
||||
|
||||
Библиотека функций для работы с инвентарем.
|
||||
|
||||
```lua
|
||||
-- Возвращает id предмета и его количество. id = 0 (core:empty) обозначает, что слот пуст.
|
||||
inventory.get(
|
||||
-- id инвентаря
|
||||
invid: int,
|
||||
-- индекс слота
|
||||
slot: int
|
||||
) -> int, int
|
||||
|
||||
-- Устанавливает содержимое слота.
|
||||
inventory.set(
|
||||
-- id инвентаря
|
||||
invid: int,
|
||||
-- индекс слота
|
||||
slot: int,
|
||||
-- id предмета
|
||||
itemid: int,
|
||||
-- количество предмета
|
||||
count: int
|
||||
)
|
||||
|
||||
-- Возращает размер инвентаря (число слотов).
|
||||
-- Если указанного инвентаря не существует, бросает исключение.
|
||||
inventory.size(invid: int) -> int
|
||||
|
||||
-- Добавляет предмет в инвентарь.
|
||||
-- Если не удалось вместить все количество, возвращает остаток.
|
||||
inventory.add(
|
||||
-- id инвентаря
|
||||
invid: int,
|
||||
-- id предмета
|
||||
itemid: int,
|
||||
-- количество предмета
|
||||
count: int
|
||||
) -> int
|
||||
|
||||
-- Функция возвращает id инвентаря блока.
|
||||
-- Если блок не может иметь инвентарь - возвращает 0.
|
||||
inventory.get_block(x: int, y: int, z: int) -> int
|
||||
|
||||
-- Привязывает указанный инвентарь к блоку.
|
||||
inventory.bind_block(invid: int, x: int, y: int, z: int)
|
||||
|
||||
-- Отвязывает инвентарь от блока.
|
||||
inventory.unbind_block(x: int, y: int, z: int)
|
||||
```
|
||||
|
||||
> [!WARNING]
|
||||
> Инвентари, не привязанные ни к одному из блоков, удаляются при выходе из мира.
|
||||
|
||||
```lua
|
||||
-- Создает копию инвентаря и возвращает id копии.
|
||||
-- Если копируемого инвентаря не существует, возвращает 0.
|
||||
inventory.clone(invid: int) -> int
|
||||
|
||||
-- Перемещает предмет из slotA инвентаря invA в slotB инвентаря invB.
|
||||
-- invA и invB могут указывать на один инвентарь.
|
||||
-- slotB будет выбран автоматически, если не указывать явно.
|
||||
inventory.move(invA: int, slotA: int, invB: int, slotB: int)
|
||||
```
|
||||
|
||||
|
||||
13
doc/ru/scripting/builtins/libtime.md
Normal file
13
doc/ru/scripting/builtins/libtime.md
Normal file
@ -0,0 +1,13 @@
|
||||
# Библиотека time
|
||||
|
||||
```python
|
||||
time.uptime() -> float
|
||||
```
|
||||
|
||||
Возвращает время с момента запуска движка в секундах.
|
||||
|
||||
```python
|
||||
time.delta() -> float
|
||||
```
|
||||
|
||||
Возвращает дельту времени (время прошедшее с предыдущего кадра)
|
||||
38
doc/ru/scripting/builtins/libworld.md
Normal file
38
doc/ru/scripting/builtins/libworld.md
Normal file
@ -0,0 +1,38 @@
|
||||
# Библиотека *world*
|
||||
|
||||
```lua
|
||||
-- Возвращает информацию о мирах.
|
||||
world.get_list() -> массив таблиц {
|
||||
-- название мира
|
||||
name: str,
|
||||
-- предпросмотр (автоматически загружаемая текстура)
|
||||
icon: str
|
||||
}
|
||||
|
||||
-- Возвращает текущее игровое время от 0.0 до 1.0, где 0.0 и 1.0 - полночь, 0.5 - полдень.
|
||||
world.get_day_time() -> number
|
||||
|
||||
-- Устанавливает указанное игровое время.
|
||||
world.set_day_time(time: number)
|
||||
|
||||
-- Устанавливает указанную скорость смены времени суток.
|
||||
world.set_day_time_speed(value: number)
|
||||
|
||||
-- Возвращает скорость скорость смены времени суток.
|
||||
world.get_day_time_speed() -> number
|
||||
|
||||
-- Возвращает суммарное время, прошедшее в мире.
|
||||
world.get_total_time() -> number
|
||||
|
||||
-- Возвращает зерно мира.
|
||||
world.get_seed() -> int
|
||||
|
||||
-- Проверяет существование мира по имени.
|
||||
world.exists() -> bool
|
||||
|
||||
-- Проверяет является ли текущее время днём. От 0.333(8 утра) до 0.833(8 вечера).
|
||||
world.is_day() -> bool
|
||||
|
||||
-- Проверяет является ли текущее время ночью. От 0.833(8 вечера) до 0.333(8 утра).
|
||||
world.is_night() -> bool
|
||||
```
|
||||
469
doc/ru/world-generator.md
Normal file
469
doc/ru/world-generator.md
Normal file
@ -0,0 +1,469 @@
|
||||
# Генератор мира
|
||||
|
||||
## Содержание
|
||||
|
||||
- [Основные понятия](#основные-понятия)
|
||||
- [Глобальные переменные](#глобальные-переменные)
|
||||
- [Файл конфигурации](#файл-конфигурации)
|
||||
- [Фрагменты](#фрагменты)
|
||||
- [Структуры](#структуры)
|
||||
- [Биомы](#биомы)
|
||||
* [Параметры биомов](#параметры-биомов)
|
||||
* [Выбор биома](#выбор-биома)
|
||||
- [Heightmap (карта высот)](#heightmap-карта-высот)
|
||||
* [Конструктор](#конструктор)
|
||||
* [Унарные операции](#унарные-операции)
|
||||
* [Бинарные операции](#бинарные-операции)
|
||||
* [heightmap:dump(...)](#heightmapdump)
|
||||
* [heightmap:noise(...)](#heightmapnoise)
|
||||
* [heightmap:cellnoise(...)](#heightmapcellnoise)
|
||||
* [heightmap:resize(...)](#heightmapresize)
|
||||
* [heightmap:crop(...)](#heightmapcrop)
|
||||
* [heightmap:at(x, y)](#heightmapatx-y)
|
||||
- [VoxelFragment (фрагмент)](#voxelfragment-фрагмент)
|
||||
- [Генерация карты высот](#генерация-карты-высот)
|
||||
- [Ручная расстановка структур](#ручная-расстановка-структур)
|
||||
* [Размещения структур/тоннелей](#размещения-структуртоннелей)
|
||||
* [Расстановка малых структур](#расстановка-малых-структур)
|
||||
* [Расстановка 'широких' структур](#расстановка-широких-структур)
|
||||
- [Структурный воздух](#структурный-воздух)
|
||||
|
||||
## Основные понятия
|
||||
|
||||
Понятия используемые далее по тексту.
|
||||
|
||||
- **Комбинируемый массив/объект** - TOML или JSON файл, который комбинируется из нескольких версий в разных паках, что позволяет добавлять в него данные извне. Поля комбинированного объекта перезаписываются в порядке от первого к последнему, так же, как и другие ресурсы в паках. В случае комбинируемого массива, проверка на дубликаты **не** выполняется.
|
||||
- **Биом** - информация, определяющая то, из каких блоков и какими слоями генерируется ландшафт, а так же набор растений, структур.
|
||||
- **Растение** - случайно расставляемый на поверхности блок.
|
||||
- **Малая структура** - структура, размер которой не превышает размера чанка. Пример: деревья.
|
||||
|
||||
## Файл конфигурации
|
||||
|
||||
Генератор мира распознается при наличии файла `generators/имя_генератора.toml`. Другие файлы, относящиеся к генератору, должны находиться в директории `generators/имя_генератора.files/`:
|
||||
- biomes.toml - объявления биомов
|
||||
- structures.toml - объявления структур
|
||||
- script.lua - скрипт генератора
|
||||
- fragments - директория в которой располагаются файлы фрагментов
|
||||
|
||||
Основные свойства, описываемые в файле конфигурации:
|
||||
- **caption** - отображаемое имя генератора. По-умолчанию генерируется из id.
|
||||
- **biome-parameters** - количество параметров выбора биомов (от 0 до 4). По-умолчанию: 0.
|
||||
- **sea-level** - уровень моря (ниже этого уровня вместо воздуха будут генерироваться слои моря (sea-layers)). По-умолчанию: 0.
|
||||
- **biomes-bpd** - количество блоков на точку карты параметра выбора биомов. По-умолчанию: 8.
|
||||
- **heights-bpd** - количество блоков на точку карты высот. По-умолчанию: 8.
|
||||
- **wide-structs-chunks-radius** - масимальный радиус размещения 'широких' структур, измеряемый в чанках.
|
||||
|
||||
## Глобальные переменные
|
||||
|
||||
В скрипте генератора доступны следующие переменные:
|
||||
|
||||
- `SEED` - зерно генерации мира
|
||||
- `__DIR__` - директория генератора (`пак:generators/имя_генератора.files/`)
|
||||
- `__FILE__` - файл скрипта (`пак:generators/имя_генератора.files/script.lua`)
|
||||
|
||||
## Фрагменты
|
||||
|
||||
Фрагмент является сохраненной для дальнейшего использования, областью мира, как и чанк, ограниченную некоторой шириной, высотой и длиной. Фрагмент может содержать данные не только о блоках, попадающих в область, но и о инвентарях блоков области, а так же сущностях. В отличие от чанка, размер фрагмента произволен.
|
||||
|
||||
На данный момент, фрагмент может быть создан при помощи команды `fragment.save`, либо через функцию `generation.create_fragment`.
|
||||
|
||||
Фрагменты, используемые генератором, должны находиться в директории:
|
||||
`generators/имя_генератора.files/fragments/`
|
||||
|
||||
## Структуры
|
||||
|
||||
Структура - набор правил по вставке фрагмента в мир генератором. На данный момент не имеет свойств, создаваясь в виде пустых объектов в файле `generators/имя_генератора.files/structures.json`. Пример:
|
||||
```lua
|
||||
{
|
||||
"tree0": {},
|
||||
"tree1": {},
|
||||
"tree2": {},
|
||||
"tower": {},
|
||||
"coal_ore0": {}
|
||||
}
|
||||
```
|
||||
|
||||
На данный момент, имя структуры должно совпадать с именем использованного фрагмента.
|
||||
|
||||
## Биомы
|
||||
|
||||
Биом определяет то, из каких блоков и какими слоями генерируется ландшафт, а так же набор растений, структур.
|
||||
|
||||
Биомы объявляются в комбинируемом объекте:
|
||||
`generators/имя_генератора.files/biomes.toml`
|
||||
|
||||
Разберем структуру биома на примере леса из генератора base:demo:
|
||||
|
||||
```toml
|
||||
[forest]
|
||||
parameters = [
|
||||
{weight=1, value=1},
|
||||
{weight=0.5, value=0.2}
|
||||
]
|
||||
layers = [
|
||||
{below-sea-level=false, height=1, block="base:grass_block"},
|
||||
{below-sea-level=false, height=7, block="base:dirt"},
|
||||
{height=-1, block="base:stone"},
|
||||
{height=1, block="base:bazalt"}
|
||||
]
|
||||
sea-layers = [
|
||||
{height=-1, block="base:water"}
|
||||
]
|
||||
plant-chance = 0.4
|
||||
plants = [
|
||||
{weight=1, block="base:grass"},
|
||||
{weight=0.03, block="base:flower"}
|
||||
]
|
||||
structure-chance = 0.032
|
||||
structures = [
|
||||
{name="tree0", weight=1},
|
||||
{name="tree1", weight=1},
|
||||
{name="tree2", weight=1},
|
||||
{name="tower", weight=0.002}
|
||||
]
|
||||
```
|
||||
|
||||
- ключ forest - имя биома
|
||||
- parameters - веса и центральные значения параметров для биома. См. раздел [выбор биома](#выбор-биома). Количество записей должно соответствовать количеству параметров выбора биомов.
|
||||
- layers - слои блоков от верхнего к нижнему.
|
||||
- height - высота слоя в блоках. -1 используется для обозначения безразмерного (заполняющего) слоя, который может быть только один. Его высота вычисляется автоматически.
|
||||
- block - полное имя блока
|
||||
- below-sea-level - может ли слой быть сгенерированным ниже уровня моря (пример: дёрн). При значении false, при генерации ниже уровня моря, слой будет заменён на следующий.
|
||||
- sea-layers - слои океана. Положение верхнего слоя совпадает с высотой уровня моря.
|
||||
- plant-chance - вероятность генерации растения на блоке поверхности.
|
||||
- plants - растения, случайно расставляемые на поверхности.
|
||||
- weight - вес, напрямую влияющий на шанс выбора конкретного растения.
|
||||
- block - блок растения
|
||||
- structure-chance - вероятность генерации малой структуры на блоке поверхности.
|
||||
- structures - структуры, случайно расставляемые на поверхности.
|
||||
- name - имя структуры, объявленной в `structures.json`.
|
||||
- weight - вес, напрямую влияющий на шанс выбора конкретной структуры.
|
||||
|
||||
### Параметры биомов
|
||||
|
||||
Параметр генератора `biome-parameters` определяет количество параметров биомов, используемых при их выборе (примеры: температура, влажность).
|
||||
|
||||
Карты значений параметров биомов генеруются так же, как и карты высот.
|
||||
|
||||
Требуется реализовать функцию:
|
||||
```lua
|
||||
-- x, y - позиция начала карты (в точках)
|
||||
-- w, h - ширина и высота карты (в точках)
|
||||
-- bpd - (blocks per dot) число блоков на точку (масштаб)
|
||||
function generate_biome_parameters(x, y, w, h, bpd)
|
||||
-- создание карт высот (Heightmap) для каждого параметра биомов
|
||||
-- ...
|
||||
return карты_через_запятую
|
||||
end
|
||||
|
||||
-- пример
|
||||
function generate_biome_parameters(x, y, w, h, s)
|
||||
-- карта температур
|
||||
local tempmap = Heightmap(w, h)
|
||||
tempmap.noiseSeed = SEED + 5324
|
||||
tempmap:noise({x, y}, 0.04*s, 6)
|
||||
tempmap:pow(3)
|
||||
-- карта влажности
|
||||
local hummap = Heightmap(w, h)
|
||||
hummap.noiseSeed = SEED + 953
|
||||
hummap:noise({x, y}, 0.04*s, 6)
|
||||
hummap:pow(3)
|
||||
|
||||
return tempmap, hummap
|
||||
end
|
||||
```
|
||||
|
||||
### Выбор биома
|
||||
|
||||
После генерации карт параметров для каждого биома вычисляются оценки по всем параметрам:
|
||||
|
||||
$score = \frac{|V - V_b|}{W_b}$
|
||||
|
||||
Где $V$ - значение параметра, $V_b$ центральное значение параметра для биома, $W_b$ - вес биома для параметра.
|
||||
|
||||
Генератор выбирает биом с **наименьшей** суммой оценок для параметров.
|
||||
|
||||
|
||||
>[!WARNING]
|
||||
> При неудачной настройке значений и весов параметров у биомов может возникать эффект, имеющий ту же природу, что и конфликт глубины в 3D графике при наложении двух поверхностей.
|
||||
>
|
||||
В случае биомов, узор выглядит случайным из-за искривления этих 'поверхностей' шумом, используемым при генерации карт параметров.
|
||||
>
|
||||
Для избавления от эффекта можно либо скорректировать веса или значения параметров биомов, либо увеличить разницу в генерации карт параметров.
|
||||
|
||||
|
||||
## Heightmap (карта высот)
|
||||
|
||||
Heightmap это класс для работы с картами высот (матрицами чисел с плавающей точкой произвольного размера).
|
||||
|
||||
### Конструктор
|
||||
|
||||
Конструктор карты высот требует указания целочисленных ширины и высоты.
|
||||
|
||||
```lua
|
||||
local map = Heightmap(ширина, высота)
|
||||
```
|
||||
|
||||
### Унарные операции
|
||||
|
||||
Операции применяются ко всем значениям высоты.
|
||||
|
||||
```lua
|
||||
map:abs()
|
||||
```
|
||||
|
||||
Приводит значения высот к абсолютным.
|
||||
|
||||
|
||||
### Бинарные операции
|
||||
|
||||
Операции с применением второй карты или скаляра.
|
||||
|
||||
Арифметические операции:
|
||||
|
||||
```lua
|
||||
-- Прибавление
|
||||
map:add(value: Heightmap|number)
|
||||
|
||||
-- Вычитание
|
||||
map:sub(value: Heightmap|number)
|
||||
|
||||
-- Умножение
|
||||
map:mul(value: Heightmap|number)
|
||||
|
||||
-- Возведение в степень
|
||||
map:pow(value: Heightmap|number)
|
||||
```
|
||||
|
||||
Другие операции:
|
||||
|
||||
```lua
|
||||
-- Минимум
|
||||
map:min(value: Heightmap|number)
|
||||
|
||||
-- Максимум
|
||||
map:max(value: Heightmap|number)
|
||||
|
||||
-- Примешивание
|
||||
map:mixin(value: Heightmap|number, t: Heightmap|number)
|
||||
-- t - фактор смешивания от 0.0 до 1.0
|
||||
-- смешивание производится по формуле:
|
||||
-- map_value * (1.0 - t) + value * t
|
||||
```
|
||||
|
||||
### heightmap:dump(...)
|
||||
|
||||
Метод используемый для отладки, создает изображение на основе карты высот переводя значения из дипазона `[-1.0, 1.0]` в значения яркости `[0, 255]`, сохраняя в указанный файл.
|
||||
|
||||
```lua
|
||||
map:dump('export:test.png')
|
||||
```
|
||||
|
||||
### heightmap:noise(...)
|
||||
|
||||
Метод генерирующий симплекс-шум, прибавляя его к имеющимся значениям.
|
||||
|
||||
Зерно шума может быть указано в поле `map.noiseSeed`.
|
||||
|
||||
```lua
|
||||
map:noise(
|
||||
-- смещение координат
|
||||
offset: {number, number},
|
||||
-- коэфициент масштабирования координат
|
||||
scale: number,
|
||||
-- число октав шума (по-умолчанию: 1)
|
||||
[опционально] octaves: integer,
|
||||
-- множитель амплитуды шума (по-умолчанию: 1.0)
|
||||
[опционально] multiplier: number,
|
||||
-- карта смещений координаты X при генерации шума
|
||||
[опционально] shiftMapX: Heightmap,
|
||||
-- карта смещений координаты Y при генерации шума
|
||||
[опционально] shiftMapY: Heightmap,
|
||||
) -> nil
|
||||
```
|
||||
|
||||
Визуализация шума с октавами 1, 2, 3, 4 и 5.
|
||||
|
||||

|
||||
|
||||
### heightmap:cellnoise(...)
|
||||
|
||||
Аналог heightmap:noise генерирующий клеточный шум.
|
||||
|
||||
Зерно шума может быть указано в поле `map.noiseSeed`.
|
||||
|
||||

|
||||
|
||||
### heightmap:resize(...)
|
||||
|
||||
```lua
|
||||
map:resize(ширина, высота, интерполяция)
|
||||
```
|
||||
|
||||
Изменяет размер карты высот.
|
||||
|
||||
Доступные режимы интерполяции:
|
||||
- 'nearest' - без интерполяции
|
||||
- 'linear' - билинейная интерполяция
|
||||
|
||||
### heightmap:crop(...)
|
||||
|
||||
```lua
|
||||
map:crop(x, y, ширина, высота)
|
||||
```
|
||||
|
||||
Обрезает карту высот до заданной области.
|
||||
|
||||
### heightmap:at(x, y)
|
||||
|
||||
```lua
|
||||
map:at(x, y) --> number
|
||||
```
|
||||
|
||||
Возвращает значение высота на заданной позиции.
|
||||
|
||||
## VoxelFragment (фрагмент)
|
||||
|
||||
Фрагмент создается вызовом функции:
|
||||
```lua
|
||||
generation.create_fragment(
|
||||
-- точка A
|
||||
a: vec3,
|
||||
-- точка B
|
||||
b: vec3,
|
||||
-- автоматически обрезать фрагмент, если возможно
|
||||
crop: bool
|
||||
) -> VoxelFragment
|
||||
```
|
||||
|
||||
Фрагмент может быть загружен из файла:
|
||||
```lua
|
||||
generation.load_fragment(
|
||||
-- файл фрагмента
|
||||
filename: str
|
||||
) -> VoxelFragment
|
||||
```
|
||||
|
||||
Фрагмент может быть сохранен в файл:
|
||||
```lua
|
||||
generation.save_fragment(
|
||||
-- сохраняемый фрагмент
|
||||
fragment: VoxelFragment,
|
||||
-- файл
|
||||
filename: str
|
||||
) -> nil
|
||||
```
|
||||
|
||||
Размер фрагмента доступен как свойство `size`.
|
||||
|
||||
Фрагмент может быть обрезан до размеров содержимого (воздух игнорируется) вызовом метода `fragment:crop()`.
|
||||
|
||||
## Генерация карты высот
|
||||
|
||||
По-умолчанию, движок генерирует карту высот, состоящую из нулей.
|
||||
|
||||
Для генерации пользовательских карт высот требуется реализовать функцию:
|
||||
```lua
|
||||
function generate_heightmap(
|
||||
x, y, -- смещение карты высот
|
||||
w, h, -- размер карты высот, ожидаемый движком
|
||||
bpd, -- число блоков на точку карты (blocks per dot) - масштаб
|
||||
[опционально] inputs -- массив входных карт параметров биомов
|
||||
-- (см. свойство heightmap-inputs генератора)
|
||||
) --> Heightmap
|
||||
```
|
||||
|
||||
Пример генерации карты высот из простого симплекс-шума с приведением
|
||||
к нужному диапазону:
|
||||
|
||||
```lua
|
||||
function generate_heightmap(x, y, w, h, bpd)
|
||||
-- создаем карту высот с заданным размером
|
||||
local map = Heightmap(w, h)
|
||||
-- настраиваем зерно шума
|
||||
map.noiseSeed = SEED
|
||||
-- шум с масштабом 1/10 на 4 октавы с амплитудой 0.5
|
||||
map:noise({x, y}, 0.1*bpd, 4, 0.5)
|
||||
-- сдвигаем высоты к положительному диапазону
|
||||
map:add(0.5)
|
||||
return map
|
||||
end
|
||||
```
|
||||
|
||||
## Ручная расстановка структур
|
||||
|
||||
### Размещения структур/тоннелей
|
||||
|
||||
Размещение структуры / линии представляет собой массив из заданного
|
||||
набора параметров.
|
||||
|
||||
Структура:
|
||||
```lua
|
||||
{имя_структуры, позиция_структуры, поворот, [опционально] приоритет}
|
||||
```
|
||||
|
||||
Где:
|
||||
- имя_структуры - строка содержащая имя структуры, зарегистрированная в structures.toml.
|
||||
- позиция_структуры - vec3 (массив из трех чисел) относительно позиции чанка.
|
||||
- поворот - число от 0 до 3 обозначающая поворот структуры по оси Y.
|
||||
- приоритет - число определяющее порядок установки структур. Структуры с меньшем приоритетом перекрываются структурами с большим.
|
||||
|
||||
Тоннель:
|
||||
```lua
|
||||
{":line", блок_заполнитель, точка_а, точка_б, радиус}
|
||||
```
|
||||
|
||||
Где:
|
||||
- блок_заполнитель - числовой id блока, из которого будет состоять структура.
|
||||
- точка_а, точка_б - vec3, vec3 позиции начала и конца тоннеля.
|
||||
- радиус - радиус тоннеля в блоках
|
||||
|
||||
|
||||
### Расстановка малых структур
|
||||
|
||||
```lua
|
||||
function place_structures(
|
||||
x, z, -- позиция начала области в блоках
|
||||
w, d, -- размер области в блоках
|
||||
heights, -- карта высот чанка
|
||||
chunk_height, -- высота чанка
|
||||
) --> массив размещений структур
|
||||
```
|
||||
|
||||
Структуры могут размещаться за пределами чанка, но не дальше, чем на один чанк.
|
||||
|
||||
Пример:
|
||||
|
||||
```lua
|
||||
function place_structures(x, z, w, d, hmap, chunk_height)
|
||||
local placements = {}
|
||||
local height = hmap:at(w/2, h/2) * chunk_height
|
||||
|
||||
-- устанавливает башню по центру чанка
|
||||
table.insert(placements, {
|
||||
'tower', {w/2, height, d/2}, math.random() * 4, 2
|
||||
})
|
||||
return placements
|
||||
end
|
||||
```
|
||||
|
||||
### Расстановка 'широких' структур
|
||||
|
||||
Структуры и тоннели могут размещаться за пределами чанка, но не дальше, чем на число чанков, указанное в свойстве генератора `wide-structs-chunks-radius`.
|
||||
|
||||
В отличие от прошлой функции, сюда не передается карта высот,
|
||||
так как вызов происходит на ранних этапах генерации чанка.
|
||||
|
||||
```lua
|
||||
function place_structures_wide(
|
||||
x, z, -- позиция начала области в блоках
|
||||
w, d, -- размер области в блоках
|
||||
chunk_height, -- высота чанка
|
||||
) --> массив размещений структур / тоннелей
|
||||
```
|
||||
|
||||
## Структурный воздух
|
||||
|
||||
`core:struct_air` - блок, которые следует использовать в фрагментах для обозначения пустого пространства, которое не должно заполняться блоками при генерации в мире.
|
||||
|
||||
<image src="../../res/textures/blocks/struct_air.png" width="128px" height="128px" style="image-rendering: pixelated">
|
||||
@ -2,13 +2,13 @@ local _, dir = parse_path(__DIR__)
|
||||
local ores = require "base:generation/ores"
|
||||
ores.load(dir)
|
||||
|
||||
function place_structures(x, z, w, d, seed, hmap, chunk_height)
|
||||
function place_structures(x, z, w, d, hmap, chunk_height)
|
||||
local placements = {}
|
||||
ores.place(placements, x, z, w, d, seed, hmap, chunk_height)
|
||||
ores.place(placements, x, z, w, d, SEED, hmap, chunk_height)
|
||||
return placements
|
||||
end
|
||||
|
||||
function place_structures_wide(x, z, w, d, seed, chunk_height)
|
||||
function place_structures_wide(x, z, w, d, chunk_height)
|
||||
local placements = {}
|
||||
if math.random() < 0.05 then -- generate caves
|
||||
local sx = x + math.random() * 10 - 5
|
||||
@ -43,22 +43,22 @@ function place_structures_wide(x, z, w, d, seed, chunk_height)
|
||||
return placements
|
||||
end
|
||||
|
||||
function generate_heightmap(x, y, w, h, seed, s, inputs)
|
||||
function generate_heightmap(x, y, w, h, s, inputs)
|
||||
local umap = Heightmap(w, h)
|
||||
local vmap = Heightmap(w, h)
|
||||
umap.noiseSeed = seed
|
||||
vmap.noiseSeed = seed
|
||||
umap.noiseSeed = SEED
|
||||
vmap.noiseSeed = SEED
|
||||
vmap:noise({x+521, y+70}, 0.1*s, 3, 25.8)
|
||||
vmap:noise({x+95, y+246}, 0.15*s, 3, 25.8)
|
||||
|
||||
local map = Heightmap(w, h)
|
||||
map.noiseSeed = seed
|
||||
map.noiseSeed = SEED
|
||||
map:noise({x, y}, 0.8*s, 4, 0.02)
|
||||
map:cellnoise({x, y}, 0.1*s, 3, 0.3, umap, vmap)
|
||||
map:add(0.7)
|
||||
|
||||
local rivermap = Heightmap(w, h)
|
||||
rivermap.noiseSeed = seed
|
||||
rivermap.noiseSeed = SEED
|
||||
rivermap:noise({x+21, y+12}, 0.1*s, 4)
|
||||
rivermap:abs()
|
||||
rivermap:mul(2.0)
|
||||
@ -67,21 +67,21 @@ function generate_heightmap(x, y, w, h, seed, s, inputs)
|
||||
map:mul(rivermap)
|
||||
|
||||
local desertmap = Heightmap(w, h)
|
||||
desertmap.noiseSeed = seed
|
||||
desertmap.noiseSeed = SEED
|
||||
desertmap:cellnoise({x+52, y+326}, 0.3*s, 2, 0.2)
|
||||
desertmap:add(0.4)
|
||||
map:mixin(desertmap, inputs[1])
|
||||
return map
|
||||
end
|
||||
|
||||
function generate_biome_parameters(x, y, w, h, seed, s)
|
||||
function generate_biome_parameters(x, y, w, h, s)
|
||||
local tempmap = Heightmap(w, h)
|
||||
tempmap.noiseSeed = seed + 5324
|
||||
tempmap.noiseSeed = SEED + 5324
|
||||
tempmap:noise({x, y}, 0.04*s, 6)
|
||||
tempmap:mul(0.5)
|
||||
tempmap:add(0.5)
|
||||
local hummap = Heightmap(w, h)
|
||||
hummap.noiseSeed = seed + 953
|
||||
hummap.noiseSeed = SEED + 953
|
||||
hummap:noise({x, y}, 0.04*s, 6)
|
||||
tempmap:pow(3)
|
||||
hummap:pow(3)
|
||||
|
||||
@ -77,12 +77,12 @@ static int l_world_exists(lua::State* L) {
|
||||
|
||||
static int l_world_is_day(lua::State* L) {
|
||||
auto daytime = level->getWorld()->getInfo().daytime;
|
||||
return lua::pushboolean(L, daytime >= 0.2 && daytime <= 0.8);
|
||||
return lua::pushboolean(L, daytime >= 0.333 && daytime <= 0.833);
|
||||
}
|
||||
|
||||
static int l_world_is_night(lua::State* L) {
|
||||
auto daytime = level->getWorld()->getInfo().daytime;
|
||||
return lua::pushboolean(L, daytime < 0.2 || daytime > 0.8);
|
||||
return lua::pushboolean(L, daytime < 0.333 || daytime > 0.833);
|
||||
}
|
||||
|
||||
const luaL_Reg worldlib[] = {
|
||||
|
||||
@ -256,6 +256,7 @@ static std::unordered_map<std::string, lua_CFunction> methods {
|
||||
{"cellnoise", lua::wrap<l_noise<FNL_NOISE_CELLULAR>>},
|
||||
{"pow", lua::wrap<l_binop_func<util::pow>>},
|
||||
{"add", lua::wrap<l_binop_func<std::plus>>},
|
||||
{"sub", lua::wrap<l_binop_func<std::minus>>},
|
||||
{"mul", lua::wrap<l_binop_func<std::multiplies>>},
|
||||
{"min", lua::wrap<l_binop_func<util::min>>},
|
||||
{"max", lua::wrap<l_binop_func<util::max>>},
|
||||
|
||||
@ -24,10 +24,13 @@ static debug::Logger logger("generator-scripting");
|
||||
class LuaGeneratorScript : public GeneratorScript {
|
||||
State* L;
|
||||
const GeneratorDef& def;
|
||||
scriptenv env;
|
||||
scriptenv env = nullptr;
|
||||
|
||||
fs::path file;
|
||||
std::string dirPath;
|
||||
public:
|
||||
LuaGeneratorScript(State* L, const GeneratorDef& def, scriptenv env)
|
||||
: L(L), def(def), env(std::move(env)) {
|
||||
LuaGeneratorScript(State* L, const GeneratorDef& def, const fs::path& file, const std::string& dirPath)
|
||||
: L(L), def(def), file(file), dirPath(dirPath) {
|
||||
}
|
||||
|
||||
virtual ~LuaGeneratorScript() {
|
||||
@ -37,10 +40,33 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void initialize(uint64_t seed) override {
|
||||
env = create_environment(L);
|
||||
stackguard _(L);
|
||||
|
||||
pushenv(L, *env);
|
||||
pushstring(L, dirPath);
|
||||
setfield(L, "__DIR__");
|
||||
pushstring(L, dirPath + "/script.lua");
|
||||
setfield(L, "__FILE__");
|
||||
pushinteger(L, seed);
|
||||
setfield(L, "SEED");
|
||||
|
||||
pop(L);
|
||||
|
||||
if (fs::exists(file)) {
|
||||
std::string src = files::read_string(file);
|
||||
logger.info() << "script (generator) " << file.u8string();
|
||||
pop(L, execute(L, *env, src, file.u8string()));
|
||||
} else {
|
||||
// Use default (empty) script
|
||||
pop(L, execute(L, *env, "", "<empty>"));
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<Heightmap> generateHeightmap(
|
||||
const glm::ivec2& offset,
|
||||
const glm::ivec2& size,
|
||||
uint64_t seed,
|
||||
uint bpd,
|
||||
const std::vector<std::shared_ptr<Heightmap>>& inputs
|
||||
) override {
|
||||
@ -48,7 +74,6 @@ public:
|
||||
if (getfield(L, "generate_heightmap")) {
|
||||
pushivec_stack(L, offset);
|
||||
pushivec_stack(L, size);
|
||||
pushinteger(L, seed);
|
||||
pushinteger(L, bpd);
|
||||
if (!inputs.empty()) {
|
||||
size_t inputsNum = def.heightmapInputs.size();
|
||||
@ -58,7 +83,7 @@ public:
|
||||
rawseti(L, i+1);
|
||||
}
|
||||
}
|
||||
if (call_nothrow(L, 6 + (!inputs.empty()))) {
|
||||
if (call_nothrow(L, 5 + (!inputs.empty()))) {
|
||||
auto map = touserdata<LuaHeightmap>(L, -1)->getHeightmap();
|
||||
pop(L, 2);
|
||||
return map;
|
||||
@ -69,7 +94,7 @@ public:
|
||||
}
|
||||
|
||||
std::vector<std::shared_ptr<Heightmap>> generateParameterMaps(
|
||||
const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed, uint bpd
|
||||
const glm::ivec2& offset, const glm::ivec2& size, uint bpd
|
||||
) override {
|
||||
std::vector<std::shared_ptr<Heightmap>> maps;
|
||||
|
||||
@ -78,9 +103,8 @@ public:
|
||||
if (getfield(L, "generate_biome_parameters")) {
|
||||
pushivec_stack(L, offset);
|
||||
pushivec_stack(L, size);
|
||||
pushinteger(L, seed);
|
||||
pushinteger(L, bpd);
|
||||
if (call_nothrow(L, 6, biomeParameters)) {
|
||||
if (call_nothrow(L, 5, biomeParameters)) {
|
||||
for (int i = biomeParameters-1; i >= 0; i--) {
|
||||
maps.push_back(
|
||||
touserdata<LuaHeightmap>(L, -1-i)->getHeightmap());
|
||||
@ -166,7 +190,6 @@ public:
|
||||
std::vector<Placement> placeStructuresWide(
|
||||
const glm::ivec2& offset,
|
||||
const glm::ivec2& size,
|
||||
uint64_t seed,
|
||||
uint chunkHeight
|
||||
) override {
|
||||
std::vector<Placement> placements {};
|
||||
@ -176,9 +199,8 @@ public:
|
||||
if (getfield(L, "place_structures_wide")) {
|
||||
pushivec_stack(L, offset);
|
||||
pushivec_stack(L, size);
|
||||
pushinteger(L, seed);
|
||||
pushinteger(L, chunkHeight);
|
||||
if (call_nothrow(L, 6, 1)) {
|
||||
if (call_nothrow(L, 5, 1)) {
|
||||
int len = objlen(L, -1);
|
||||
for (int i = 1; i <= len; i++) {
|
||||
rawgeti(L, i);
|
||||
@ -194,8 +216,10 @@ public:
|
||||
}
|
||||
|
||||
std::vector<Placement> placeStructures(
|
||||
const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed,
|
||||
const std::shared_ptr<Heightmap>& heightmap, uint chunkHeight
|
||||
const glm::ivec2& offset,
|
||||
const glm::ivec2& size,
|
||||
const std::shared_ptr<Heightmap>& heightmap,
|
||||
uint chunkHeight
|
||||
) override {
|
||||
std::vector<Placement> placements {};
|
||||
|
||||
@ -204,10 +228,9 @@ public:
|
||||
if (getfield(L, "place_structures")) {
|
||||
pushivec_stack(L, offset);
|
||||
pushivec_stack(L, size);
|
||||
pushinteger(L, seed);
|
||||
newuserdata<LuaHeightmap>(L, heightmap);
|
||||
pushinteger(L, chunkHeight);
|
||||
if (call_nothrow(L, 7, 1)) {
|
||||
if (call_nothrow(L, 6, 1)) {
|
||||
int len = objlen(L, -1);
|
||||
for (int i = 1; i <= len; i++) {
|
||||
rawgeti(L, i);
|
||||
@ -224,28 +247,11 @@ public:
|
||||
};
|
||||
|
||||
std::unique_ptr<GeneratorScript> scripting::load_generator(
|
||||
const GeneratorDef& def, const fs::path& file, const std::string& dirPath
|
||||
const GeneratorDef& def,
|
||||
const fs::path& file,
|
||||
const std::string& dirPath
|
||||
) {
|
||||
auto L = create_state(*engine->getPaths(), StateType::GENERATOR);
|
||||
auto env = create_environment(L);
|
||||
stackguard _(L);
|
||||
|
||||
pushenv(L, *env);
|
||||
pushstring(L, dirPath);
|
||||
setfield(L, "__DIR__");
|
||||
pushstring(L, dirPath + "/script.lua");
|
||||
setfield(L, "__FILE__");
|
||||
|
||||
pop(L);
|
||||
|
||||
if (fs::exists(file)) {
|
||||
std::string src = files::read_string(file);
|
||||
logger.info() << "script (generator) " << file.u8string();
|
||||
pop(L, execute(L, *env, src, file.u8string()));
|
||||
} else {
|
||||
// Use default (empty) script
|
||||
pop(L, execute(L, *env, "", "<empty>"));
|
||||
}
|
||||
|
||||
return std::make_unique<LuaGeneratorScript>(L, def, std::move(env));
|
||||
return std::make_unique<LuaGeneratorScript>(L, def, file, dirPath);
|
||||
}
|
||||
|
||||
@ -123,17 +123,17 @@ class GeneratorScript {
|
||||
public:
|
||||
virtual ~GeneratorScript() = default;
|
||||
|
||||
virtual void initialize(uint64_t seed) = 0;
|
||||
|
||||
/// @brief Generate a heightmap with values in range 0..1
|
||||
/// @param offset position of the heightmap in the world
|
||||
/// @param size size of the heightmap
|
||||
/// @param seed world seed
|
||||
/// @param bpd blocks per dot
|
||||
/// @param inputs biome parameter maps passed to generate_heightmap
|
||||
/// @return generated heightmap (can't be nullptr)
|
||||
virtual std::shared_ptr<Heightmap> generateHeightmap(
|
||||
const glm::ivec2& offset,
|
||||
const glm::ivec2& size,
|
||||
uint64_t seed,
|
||||
uint bpd,
|
||||
const std::vector<std::shared_ptr<Heightmap>>& inputs
|
||||
) = 0;
|
||||
@ -141,13 +141,11 @@ public:
|
||||
/// @brief Generate a biomes parameters maps
|
||||
/// @param offset position of maps in the world
|
||||
/// @param size maps size
|
||||
/// @param seed world seed
|
||||
/// @param bpd blocks per dot
|
||||
/// @return generated maps (can't be nullptr)
|
||||
virtual std::vector<std::shared_ptr<Heightmap>> generateParameterMaps(
|
||||
const glm::ivec2& offset,
|
||||
const glm::ivec2& size,
|
||||
uint64_t seed,
|
||||
uint bpd
|
||||
) = 0;
|
||||
|
||||
@ -156,12 +154,10 @@ public:
|
||||
/// wide-structs-chunks-radius
|
||||
/// @param offset position of the area
|
||||
/// @param size size of the area (blocks)
|
||||
/// @param seed world seed
|
||||
/// @param chunkHeight chunk height to use as heights multiplier
|
||||
virtual std::vector<Placement> placeStructuresWide(
|
||||
const glm::ivec2& offset,
|
||||
const glm::ivec2& size,
|
||||
uint64_t seed,
|
||||
const glm::ivec2& offset,
|
||||
const glm::ivec2& size,
|
||||
uint chunkHeight
|
||||
) = 0;
|
||||
|
||||
@ -169,13 +165,15 @@ public:
|
||||
/// placed to nearest chunks also (position of out area).
|
||||
/// @param offset position of the area
|
||||
/// @param size size of the area (blocks)
|
||||
/// @param seed world seed
|
||||
/// @param heightmap area heightmap
|
||||
/// @param chunkHeight chunk height to use as heights multiplier
|
||||
/// @return structure & line placements
|
||||
virtual std::vector<Placement> placeStructures(
|
||||
const glm::ivec2& offset, const glm::ivec2& size, uint64_t seed,
|
||||
const std::shared_ptr<Heightmap>& heightmap, uint chunkHeight) = 0;
|
||||
const glm::ivec2& offset,
|
||||
const glm::ivec2& size,
|
||||
const std::shared_ptr<Heightmap>& heightmap,
|
||||
uint chunkHeight
|
||||
) = 0;
|
||||
};
|
||||
|
||||
/// @brief Structure voxel fragments and metadata
|
||||
|
||||
@ -31,6 +31,8 @@ WorldGenerator::WorldGenerator(
|
||||
seed(seed),
|
||||
surroundMap(0, BASIC_PROTOTYPE_LAYERS + def.wideStructsChunksRadius * 2)
|
||||
{
|
||||
def.script->initialize(seed);
|
||||
|
||||
uint levels = BASIC_PROTOTYPE_LAYERS + def.wideStructsChunksRadius * 2;
|
||||
|
||||
surroundMap = SurroundMap(0, levels);
|
||||
@ -228,7 +230,7 @@ void WorldGenerator::generateStructuresWide(
|
||||
return;
|
||||
}
|
||||
auto placements = def.script->placeStructuresWide(
|
||||
{chunkX * CHUNK_W, chunkZ * CHUNK_D}, {CHUNK_W, CHUNK_D}, seed, CHUNK_H
|
||||
{chunkX * CHUNK_W, chunkZ * CHUNK_D}, {CHUNK_W, CHUNK_D}, CHUNK_H
|
||||
);
|
||||
placeStructures(placements, prototype, chunkX, chunkZ);
|
||||
|
||||
@ -245,7 +247,7 @@ void WorldGenerator::generateStructures(
|
||||
const auto& heightmap = prototype.heightmap;
|
||||
|
||||
auto placements = def.script->placeStructures(
|
||||
{chunkX * CHUNK_W, chunkZ * CHUNK_D}, {CHUNK_W, CHUNK_D}, seed,
|
||||
{chunkX * CHUNK_W, chunkZ * CHUNK_D}, {CHUNK_W, CHUNK_D},
|
||||
heightmap, CHUNK_H
|
||||
);
|
||||
placeStructures(placements, prototype, chunkX, chunkZ);
|
||||
@ -297,7 +299,6 @@ void WorldGenerator::generateBiomes(
|
||||
auto biomeParams = def.script->generateParameterMaps(
|
||||
{floordiv(chunkX * CHUNK_W, bpd), floordiv(chunkZ * CHUNK_D, bpd)},
|
||||
{floordiv(CHUNK_W, bpd)+1, floordiv(CHUNK_D, bpd)+1},
|
||||
seed,
|
||||
bpd
|
||||
);
|
||||
for (auto index : def.heightmapInputs) {
|
||||
@ -339,7 +340,6 @@ void WorldGenerator::generateHeightmap(
|
||||
prototype.heightmap = def.script->generateHeightmap(
|
||||
{floordiv(chunkX * CHUNK_W, bpd), floordiv(chunkZ * CHUNK_D, bpd)},
|
||||
{floordiv(CHUNK_W, bpd)+1, floordiv(CHUNK_D, bpd)+1},
|
||||
seed,
|
||||
bpd,
|
||||
prototype.heightmapInputs
|
||||
);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user