Körperbewegung
This commit is contained in:
parent
b16b24e4f7
commit
95945c0306
78 changed files with 12503 additions and 0 deletions
79
mods/modlib/doc/b3d.md
Normal file
79
mods/modlib/doc/b3d.md
Normal file
|
@ -0,0 +1,79 @@
|
|||
# B3D Reader & Writer
|
||||
|
||||
## `b3d.read(file)`
|
||||
|
||||
Reads from `file`, which is expected to provide `file:read(nbytes)`. `file` is not closed.
|
||||
|
||||
Returns a B3D model object.
|
||||
|
||||
## `:write(file)`
|
||||
|
||||
Writes the B3D model object `self` to `file`.
|
||||
|
||||
`file` must provide `file:write(bytestr)`. It should be in binary mode.
|
||||
It is not closed after writing.
|
||||
|
||||
## `:write_string()`
|
||||
|
||||
Writes the B3D model object to a bytestring, which is returned.
|
||||
|
||||
## `:to_gltf()`
|
||||
|
||||
Returns a glTF JSON representation of `self` in Lua table format.
|
||||
|
||||
## `:write_gltf(file)`
|
||||
|
||||
Convenience function to write the glTF representation to `file` using modlib's `json` writer.
|
||||
|
||||
`file` must provide `file:write(str)`. It is not closed afterwards.
|
||||
|
||||
## Examples
|
||||
|
||||
### Converting B3D to glTF
|
||||
|
||||
This example loops over all files in `dir_path`, converting them to glTFs which are stored in `out_dir_path`.
|
||||
|
||||
```lua
|
||||
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
||||
local dir_path = modpath .. "/b3d"
|
||||
local out_dir_path = modpath .. "/gltf"
|
||||
for _, filename in ipairs(minetest.get_dir_list(dir_path, false --[[only files]])) do
|
||||
-- First read the B3D
|
||||
local in_file = assert(io.open(dir_path .. "/" .. filename, "rb"))
|
||||
local model = assert(b3d.read(in_file))
|
||||
in_file:close()
|
||||
-- Then write the glTF
|
||||
local out_file = io.open(out_dir_path .. "/" .. filename .. ".gltf", "wb")
|
||||
model:write_gltf(out_file)
|
||||
out_file:close()
|
||||
end
|
||||
```
|
||||
|
||||
### [Round-trip (minifying B3Ds)](https://github.com/appgurueu/modlib_test/blob/f11c8e580e90454bc1adaa11a58e0c0217217d90/b3d.lua)
|
||||
|
||||
This example from [`modlib_test`](https://github.com/appgurueu/modlib_test) reads, writes, and then reads again,
|
||||
in order to verify that no data is lost through writing.
|
||||
|
||||
Simply re-writing a model using modlib's B3D writer often reduces model sizes,
|
||||
since for example modlib does not write `0` weights for bones.
|
||||
|
||||
Keep in mind to use the `rb` and `wb` modes for I/O operations
|
||||
to force Windows systems to not perform a line feed normalization.
|
||||
|
||||
### [Extracting triangle sets](https://github.com/appgurueu/ghosts/blob/42a9eb9ee81fc6760a0278d23e4c47bc68bb4919/init.lua#L41-L79)
|
||||
|
||||
The [Ghosts](https://github.com/appgurueu/ghosts/) mod extracts triangle sets using the B3D module
|
||||
to then approximate the player shape using particles picked from these triangles.
|
||||
|
||||
### [Animating the player](https://github.com/appgurueu/character_anim/blob/c48b282c0b42b32294ec2fddc03aa93141cbd894/init.lua#L213)
|
||||
|
||||
[`character_anim`](https://github.com/appgurueu/character_anim/) uses the B3D module to determine the bone overrides required
|
||||
for animating the player entirely Lua-side using bone overrides.
|
||||
|
||||
### [Generating a Go board](https://github.com/appgurueu/go/blob/997ce85260d232a05dd668c32c6854bf34e3d5be/build/generate_models.lua)
|
||||
|
||||
This example from the [Go](https://github.com/appgurueu/go) mod generates a Go board
|
||||
where for each spot on the board there are two pieces (black and white),
|
||||
both of which can be moved out of the board using a bone.
|
||||
|
||||
It demonstrates how to use the writer (and how the table structure roughly looks like).
|
260
mods/modlib/doc/b3d_specification.txt
Normal file
260
mods/modlib/doc/b3d_specification.txt
Normal file
|
@ -0,0 +1,260 @@
|
|||
************************************************************************************
|
||||
* Blitz3d file format V0.01 *
|
||||
************************************************************************************
|
||||
|
||||
This document and the information contained within is placed in the Public Domain.
|
||||
|
||||
Please visit http://www.blitzbasic.co.nz for the latest version of this document.
|
||||
|
||||
Please contact marksibly@blitzbasic.co.nz for more information and general inquiries.
|
||||
|
||||
|
||||
|
||||
************************************************************************************
|
||||
* Introduction *
|
||||
************************************************************************************
|
||||
|
||||
The Blitz3D file format specifies a format for storing texture, brush and entity descriptions for
|
||||
use with the Blitz3D programming language.
|
||||
|
||||
The rationale behind the creation of this format is to allow for the generation of much richer and
|
||||
more complex Blitz3D scenes than is possible using established file formats - many of which do not
|
||||
support key features of Blitz3D, and all of which miss out on at least some features!
|
||||
|
||||
A Blitz3D (.b3d) file is split up into a sequence of 'chunks', each of which can contain data
|
||||
and/or other chunks.
|
||||
|
||||
Each chunk is preceded by an eight byte header:
|
||||
|
||||
char tag[4] ;4 byte chunk 'tag'
|
||||
int length ;4 byte chunk length (not including *this* header!)
|
||||
|
||||
If a chunk contains both data and other chunks, the data always appears first and is of a fixed
|
||||
length.
|
||||
|
||||
A file parser should ignore unrecognized chunks.
|
||||
|
||||
Blitz3D files are stored little endian (intel) style.
|
||||
|
||||
Many aspects of the file format are not quite a 'perfect fit' for the way Blitz3D works. This has
|
||||
been done mainly to keep the file format simple, and to make life easier for the authors of third
|
||||
party importers/exporters.
|
||||
|
||||
|
||||
|
||||
************************************************************************************
|
||||
* Chunk Types *
|
||||
************************************************************************************
|
||||
|
||||
This lists the types of chunks that can appear in a b3d file, and the data they contain.
|
||||
|
||||
Color values are always in the range 0 to 1.
|
||||
|
||||
string (char[]) values are 'C' style null terminated strings.
|
||||
|
||||
Quaternions are used to specify general orientations. The first value is the quaternion 'w' value,
|
||||
the next 3 are the quaternion 'vector'. A 'null' rotation should be specified as 1,0,0,0.
|
||||
|
||||
Anything that is referenced 'by index' always appears EARLIER in the file than anything that
|
||||
references it.
|
||||
|
||||
brush_id references can be -1: no brush.
|
||||
|
||||
In the following descriptions, {} is used to signify 'repeating until end of chunk'. Also, a chunk
|
||||
name enclosed in '[]' signifies the chunk is optional.
|
||||
|
||||
Here we go!
|
||||
|
||||
|
||||
BB3D
|
||||
int version ;file format version: default=1
|
||||
[TEXS] ;optional textures chunk
|
||||
[BRUS] ;optional brushes chunk
|
||||
[NODE] ;optional node chunk
|
||||
|
||||
The BB3D chunk appears first in a b3d file, and its length contains the rest of the file.
|
||||
|
||||
Version is in major*100+minor format. To check the version, just divide by 100 and compare it with
|
||||
the major version your software supports, eg:
|
||||
|
||||
if file_version/100>my_version/100
|
||||
RuntimeError "Can't handle this file version!"
|
||||
EndIf
|
||||
|
||||
if file_version Mod 100>my_version Mod 100
|
||||
;file is a more recent version, but should still be backwardly compatbile with what we can
|
||||
handle!
|
||||
EndIf
|
||||
|
||||
|
||||
TEXS
|
||||
{
|
||||
char file[] ;texture file name
|
||||
int flags,blend ;blitz3D TextureFLags and TextureBlend: default=1,2
|
||||
float x_pos,y_pos ;x and y position of texture: default=0,0
|
||||
float x_scale,y_scale ;x and y scale of texture: default=1,1
|
||||
float rotation ;rotation of texture (in radians): default=0
|
||||
}
|
||||
|
||||
The TEXS chunk contains a list of all textures used in the file.
|
||||
|
||||
The flags field value can conditional an additional flag value of '65536'. This is used to indicate that the texture uses secondary UV values, ala the TextureCoords command. Yes, I forgot about this one.
|
||||
|
||||
|
||||
BRUS
|
||||
int n_texs
|
||||
{
|
||||
char name[] ;eg "WATER" - just use texture name by default
|
||||
float red,green,blue,alpha ;Blitz3D Brushcolor and Brushalpha: default=1,1,1,1
|
||||
float shininess ;Blitz3D BrushShininess: default=0
|
||||
int blend,fx ;Blitz3D Brushblend and BrushFX: default=1,0
|
||||
int texture_id[n_texs] ;textures used in brush
|
||||
}
|
||||
|
||||
The BRUS chunk contains a list of all brushes used in the file.
|
||||
|
||||
|
||||
VRTS:
|
||||
int flags ;1=normal values present, 2=rgba values present
|
||||
int tex_coord_sets ;texture coords per vertex (eg: 1 for simple U/V) max=8
|
||||
int tex_coord_set_size ;components per set (eg: 2 for simple U/V) max=4
|
||||
{
|
||||
float x,y,z ;always present
|
||||
float nx,ny,nz ;vertex normal: present if (flags&1)
|
||||
float red,green,blue,alpha ;vertex color: present if (flags&2)
|
||||
float tex_coords[tex_coord_sets][tex_coord_set_size] ;tex coords
|
||||
}
|
||||
|
||||
The VRTS chunk contains a list of vertices. The 'flags' value is used to indicate how much extra
|
||||
data (normal/color) is stored with each vertex, and the tex_coord_sets and tex_coord_set_size
|
||||
values describe texture coordinate information stored with each vertex.
|
||||
|
||||
|
||||
TRIS:
|
||||
int brush_id ;brush applied to these TRIs: default=-1
|
||||
{
|
||||
int vertex_id[3] ;vertex indices
|
||||
}
|
||||
|
||||
The TRIS chunk contains a list of triangles that all share a common brush.
|
||||
|
||||
|
||||
MESH:
|
||||
int brush_id ;'master' brush: default=-1
|
||||
VRTS ;vertices
|
||||
TRIS[,TRIS...] ;1 or more sets of triangles
|
||||
|
||||
The MESH chunk describes a mesh. A mesh only has one VRTS chunk, but potentially many TRIS chunks.
|
||||
|
||||
|
||||
BONE:
|
||||
{
|
||||
int vertex_id ;vertex affected by this bone
|
||||
float weight ;how much the vertex is affected
|
||||
}
|
||||
|
||||
The BONE chunk describes a bone. Weights are applied to the mesh described in the enclosing ANIM -
|
||||
in 99% of cases, this will simply be the MESH contained in the root NODE chunk.
|
||||
|
||||
|
||||
KEYS:
|
||||
int flags ;1=position, 2=scale, 4=rotation
|
||||
{
|
||||
int frame ;where key occurs
|
||||
float position[3] ;present if (flags&1)
|
||||
float scale[3] ;present if (flags&2)
|
||||
float rotation[4] ;present if (flags&4)
|
||||
}
|
||||
|
||||
The KEYS chunk is a list of animation keys. The 'flags' value describes what kind of animation
|
||||
info is stored in the chunk - position, scale, rotation, or any combination of.
|
||||
|
||||
|
||||
ANIM:
|
||||
int flags ;unused: default=0
|
||||
int frames ;how many frames in anim
|
||||
float fps ;default=60
|
||||
|
||||
The ANIM chunk describes an animation.
|
||||
|
||||
|
||||
NODE:
|
||||
char name[] ;name of node
|
||||
float position[3] ;local...
|
||||
float scale[3] ;coord...
|
||||
float rotation[4] ;system...
|
||||
[MESH|BONE] ;what 'kind' of node this is - if unrecognized, just use a Blitz3D
|
||||
pivot.
|
||||
[KEYS[,KEYS...]] ;optional animation keys
|
||||
[NODE[,NODE...]] ;optional child nodes
|
||||
[ANIM] ;optional animation
|
||||
|
||||
The NODE chunk describes a Blitz3D Entity. The scene hierarchy is expressed by the nesting of NODE
|
||||
chunks.
|
||||
|
||||
NODE kinds are currently mutually exclusive - ie: a node can be a MESH, or a BONE, but not both!
|
||||
However, it can be neither...if no kind is specified, the node is just a 'null' node - in Blitz3D
|
||||
speak, a pivot.
|
||||
|
||||
The presence of an ANIM chunk in a NODE indicates that an animation starts here in the hierarchy.
|
||||
This allows animations of differing speeds/lengths to be potentially nested.
|
||||
|
||||
There are many more 'kind' chunks coming, including camera, light, sprite, plane etc. For now, the
|
||||
use of a Pivot in cases where the node kind is unknown will allow for backward compatibility.
|
||||
|
||||
|
||||
|
||||
************************************************************************************
|
||||
* Examples *
|
||||
************************************************************************************
|
||||
|
||||
A typical b3d file will contain 1 TEXS chunk, 1 BRUS chunk and 1 NODE chunk, like this:
|
||||
|
||||
BB3D
|
||||
1
|
||||
TEXS
|
||||
...list of textures...
|
||||
BRUS
|
||||
...list of brushes...
|
||||
NODE
|
||||
...stuff in the node...
|
||||
|
||||
A simple, non-animating, non-textured etc mesh might look like this:
|
||||
|
||||
BB3D
|
||||
1 ;version
|
||||
NODE
|
||||
"root_node" ;node name
|
||||
0,0,0 ;position
|
||||
1,1,1 ;scale
|
||||
1,0,0,0 ;rotation
|
||||
MESH ;the mesh
|
||||
-1 ;brush: no brush
|
||||
VRTS ;vertices in the mesh
|
||||
0 ;no normal/color info in verts
|
||||
0,0 ;no texture coords in verts
|
||||
{x,y,z...} ;vertex coordinates
|
||||
TRIS ;triangles in the mesh
|
||||
-1 ;no brush for this triangle
|
||||
{v0,v1,v2...} ;vertices
|
||||
|
||||
|
||||
A more complex 'skinned mesh' might look like this (only chunks shown):
|
||||
|
||||
BB3D
|
||||
TEXS ;texture list
|
||||
BRUS ;brush list
|
||||
NODE ;root node
|
||||
MESH ;mesh - the 'skin'
|
||||
ANIM ;anim
|
||||
NODE ;first child of root node - eg: "pelvis"
|
||||
BONE ;vertex weights for pelvis
|
||||
KEYS ;anim keys for pelvis
|
||||
NODE ;first child of pelvis - eg: "left-thigh"
|
||||
BONE ;bone
|
||||
KEYS ;anim keys for left-thigh
|
||||
NODE ;second child of pelvis - eg: "right-thigh"
|
||||
BONE ;vertex weights for right-thigh
|
||||
KEYS ;anim keys for right-thigh
|
||||
|
||||
...and so on.
|
132
mods/modlib/doc/bluon.md
Normal file
132
mods/modlib/doc/bluon.md
Normal file
|
@ -0,0 +1,132 @@
|
|||
# Bluon
|
||||
|
||||
Binary Lua object notation.
|
||||
|
||||
## `new(def)`
|
||||
|
||||
```lua
|
||||
def = {
|
||||
aux_is_valid = function(object)
|
||||
return is_valid
|
||||
end,
|
||||
aux_len = function(object)
|
||||
return length_in_bytes
|
||||
end,
|
||||
-- read type byte, stream providing :read(count), map of references -> id
|
||||
aux_read = function(type, stream, references)
|
||||
... = stream:read(...)
|
||||
return object
|
||||
end,
|
||||
-- object to be written, stream providing :write(text), list of references
|
||||
aux_write = function(object, stream, references)
|
||||
stream:write(...)
|
||||
end
|
||||
}
|
||||
```
|
||||
|
||||
## `:is_valid(object)`
|
||||
|
||||
Returns whether the given object can be represented by the instance as boolean.
|
||||
|
||||
## `:len(object)`
|
||||
|
||||
Returns the expected length of the object if serialized by the current instance in bytes.
|
||||
|
||||
## `:write(object, stream)`
|
||||
|
||||
Writes the object to a stream supporting `:write(text)`. Throws an error if invalid.
|
||||
|
||||
## `:read(stream)`
|
||||
|
||||
Reads a single bluon object from a stream supporting `:read(count)`. Throws an error if invalid bluon.
|
||||
|
||||
Checking whether the stream has been fully consumed by doing `assert(not stream:read(1))` is left up to the user.
|
||||
|
||||
## Format
|
||||
|
||||
Bluon uses a "tagged union" binary format:
|
||||
Values are stored as a one-byte tag followed by the contents of the union.
|
||||
For frequently used "constants", only a tag is used.
|
||||
|
||||
`nil` is an exception; since it can't appear in tables, it gets no tag.
|
||||
If the value to be written by Bluon is `nil`, Bluon simply writes *nothing*.
|
||||
|
||||
The following is an enumeration of tag numbers, which are assigned *in this order*.
|
||||
|
||||
* `false`: 0
|
||||
* `true`: 1
|
||||
* Numbers:
|
||||
* Constants: 0, nan, +inf, -inf
|
||||
* Integers: Little endian:
|
||||
* Unsigned: `U8`, `U16`, `U32`, `U64`
|
||||
* Negative: `-U8`, `-U16`, `-U32`, `-U64`
|
||||
* Floats: Little endian `F32`, `F64`
|
||||
* Strings:
|
||||
* Constant: `""`
|
||||
* Length is written as unsigned integer according to the tag: `S8`, `S16`, `S32`, `S64`
|
||||
* followed by the raw bytes
|
||||
* Tables:
|
||||
* Tags: `M0`, `M8`, `M16`, `M32`, `M64` times `L0`, `L8`, `L16`, `L32`, `L64`
|
||||
* `M` is more significant than `L`: The order of the cartesian product is `M0L0`, `M0L1`, ...
|
||||
* List and map part count encoded as unsigned integers according to the tag,
|
||||
list part count comes first
|
||||
* followed by all values in the list part written as Bluon
|
||||
* followed by all key-value pairs in the map part written as Bluon
|
||||
(first the key is written as Bluon, then the value)
|
||||
* Reference:
|
||||
* Reference ID as unsigned integer: `R8`, `R16`, `R32`, `R64`
|
||||
* References a previously encountered table or string by an index:
|
||||
All tables and strings are numbered in the order they occur in the Bluon
|
||||
* Reserved tags:
|
||||
* All tags <= 55 are reserved. This gives 200 free tags.
|
||||
|
||||
## Features
|
||||
|
||||
* Embeddable: Written in pure Lua
|
||||
* Storage efficient: No duplication of strings or reference-equal tables
|
||||
* Flexible: Can serialize circular references and strings containing null
|
||||
|
||||
## Simple example
|
||||
|
||||
```lua
|
||||
local object = ...
|
||||
-- Write to file
|
||||
local file = io.open(..., "wb")
|
||||
modlib.bluon:write(object, file)
|
||||
file:close()
|
||||
-- Write to text
|
||||
local rope = modlib.table.rope{}
|
||||
modlib.bluon:write(object, rope)
|
||||
text = rope:to_text()
|
||||
-- Read from text
|
||||
local inputstream = modlib.text.inputstream"\1"
|
||||
assert(modlib.bluon:read(object, rope) == true)
|
||||
```
|
||||
|
||||
## Advanced example
|
||||
|
||||
```lua
|
||||
-- Serializes all userdata to a constant string:
|
||||
local custom_bluon = bluon.new{
|
||||
aux_is_valid = function(object)
|
||||
return type(object) == "userdata"
|
||||
end,
|
||||
aux_len = function(object)
|
||||
return 1 + ("userdata"):len())
|
||||
end,
|
||||
aux_read = function(type, stream, references)
|
||||
assert(type == 100, "unsupported type")
|
||||
assert(stream:read(("userdata"):len()) == "userdata")
|
||||
return userdata()
|
||||
end,
|
||||
-- object to be written, stream providing :write(text), list of references
|
||||
aux_write = function(object, stream, references)
|
||||
assert(type(object) == "userdata")
|
||||
stream:write"\100userdata"
|
||||
end
|
||||
}
|
||||
-- Write to text
|
||||
local rope = modlib.table.rope{}
|
||||
custom_bluon:write(userdata(), rope)
|
||||
assert(rope:to_text() == "\100userdata")
|
||||
```
|
76
mods/modlib/doc/irr_obj_spec.md
Normal file
76
mods/modlib/doc/irr_obj_spec.md
Normal file
|
@ -0,0 +1,76 @@
|
|||
# Minetest Wavefront `.obj` file format specification
|
||||
|
||||
Minetest Wavefront `.obj` is a subset of [Wavefront `.obj`](http://paulbourke.net/dataformats/obj/).
|
||||
|
||||
It is inferred from the [Minetest Irrlicht `.obj` reader](https://github.com/minetest/irrlicht/blob/master/source/Irrlicht/COBJMeshFileLoader.cpp).
|
||||
|
||||
`.mtl` files are not supported since Minetest's media loading process ignores them due to the extension.
|
||||
|
||||
## Lines / "Commands"
|
||||
|
||||
Irrlicht only looks at the first characters needed to tell commands apart (imagine a prefix tree of commands).
|
||||
|
||||
Superfluous parameters are ignored.
|
||||
|
||||
Numbers are formatted as either:
|
||||
|
||||
* Float: An optional minus sign (`-`), one or more decimal digits, followed by the decimal dot (`.`) then again one or more digits
|
||||
* Integer: An optional minus sign (`-`) followed by one or more decimal digits
|
||||
|
||||
Indexing starts at one. Indices are formatted as integers. Negative indices relative to the end of a buffer are supported.
|
||||
|
||||
* Comments: `# ...`; unsupported commands are silently ignored as well
|
||||
* Groups: `g <name>` or `usemtl <name>`
|
||||
* Subsequent faces belong to a new group / material, no matter the supplied names
|
||||
* Each group gets their own material (texture); indices are determined by order of appearance
|
||||
* Empty groups (groups without faces) are ignored
|
||||
* Vertices (all numbers): `v <x> <y> <z>`, global to the model
|
||||
* Texture Coordinates (all numbers): `vt <x> <y>`, global to the model
|
||||
* Normals (all numbers): `vn <x> <y> <z>`, global to the model
|
||||
* Faces (all vertex/texcoord/normal indices); always local to the current group:
|
||||
* `f <v1> <v2> <v3>`
|
||||
* `f <v1>/<t1> <v2>/<t2> ... <vn>/<tn>`
|
||||
* `f <v1>//<n1> <v2>/<n2> ... <vn>/<nn>`
|
||||
* `f <v1>/<t1>/<n1> <v2>/<t2>/<n2> ... <vn>/<tn>/<nn>`
|
||||
|
||||
## Coordinate system orientation ("handedness")
|
||||
|
||||
Vertex & normal X-coordinates are inverted ($x' = -x$);
|
||||
texture Y-coordinates are inverted as well ($y' = 1 - y$).
|
||||
|
||||
## Example
|
||||
|
||||
```obj
|
||||
# A simple 2³ cube centered at the origin; each face receives a separate texture / tile
|
||||
# no care was taken to ensure "proper" texture orientation
|
||||
v -1 -1 -1
|
||||
v -1 -1 1
|
||||
v -1 1 -1
|
||||
v -1 1 1
|
||||
v 1 -1 -1
|
||||
v 1 -1 1
|
||||
v 1 1 -1
|
||||
v 1 1 1
|
||||
vn -1 0 0
|
||||
vn 0 -1 0
|
||||
vn 0 0 -1
|
||||
vn 1 0 0
|
||||
vn 0 1 0
|
||||
vn 0 0 1
|
||||
vt 0 0
|
||||
vt 1 0
|
||||
vt 0 1
|
||||
vt 1 1
|
||||
g negative_x
|
||||
f 1/1/1 3/3/1 2/2/1 4/4/1
|
||||
g negative_y
|
||||
f 1/1/2 5/3/2 2/2/2 6/4/2
|
||||
g negative_z
|
||||
f 1/1/3 5/3/3 3/2/3 7/4/3
|
||||
g positive_x
|
||||
f 5/1/4 7/3/4 2/2/4 8/4/4
|
||||
g positive_y
|
||||
f 3/1/5 7/3/5 4/2/5 8/4/5
|
||||
g positive_z
|
||||
f 2/1/6 6/3/6 4/2/6 8/4/6
|
||||
```
|
9
mods/modlib/doc/json.md
Normal file
9
mods/modlib/doc/json.md
Normal file
|
@ -0,0 +1,9 @@
|
|||
# JSON
|
||||
|
||||
Advantages over `minetest.write_json`/`minetest.parse_json`:
|
||||
|
||||
* Twice as fast in most benchmarks (for pre-5.6 at least)
|
||||
* Uses streams instead of strings
|
||||
* Customizable
|
||||
* Useful error messages
|
||||
* Pure Lua
|
31
mods/modlib/doc/minetest/conf.md
Normal file
31
mods/modlib/doc/minetest/conf.md
Normal file
|
@ -0,0 +1,31 @@
|
|||
# Configuration
|
||||
|
||||
## Legacy
|
||||
|
||||
1. Configuration is loaded from `<worldpath>/config/<modname>.<extension>`, the following extensions are supported and loaded (in the given order), with loaded configurations overriding properties of previous ones:
|
||||
1. [`json`](https://json.org)
|
||||
2. [`lua`](https://lua.org)
|
||||
3. [`luon`](https://github.com/appgurueu/luon), Lua but without the `return`
|
||||
4. [`conf`](https://github.com/minetest/minetest/blob/master/doc/lua_api.txt)
|
||||
2. Settings are loaded from `minetest.conf` and override configuration values
|
||||
|
||||
## Locations
|
||||
|
||||
0. Default configuration: `<modfolder>/conf.lua`
|
||||
1. World configuration: `config/<modname>.<format>`
|
||||
2. Mod configuration: `<modfolder>/conf.<format>`
|
||||
3. Minetest configuration: `minetest.conf`
|
||||
|
||||
## Formats
|
||||
|
||||
1. [`lua`](https://lua.org)
|
||||
* Lua, with the environment being the configuration object
|
||||
* `field = value` works
|
||||
* Return new configuration object to replace
|
||||
2. [`luon`](https://github.com/appgurueu/luon)
|
||||
* Single Lua literal
|
||||
* Booleans, numbers, strings and tables
|
||||
3. [`conf`](https://github.com/minetest/minetest/blob/master/doc/lua_api.txt)
|
||||
* Minetest-like configuration files
|
||||
4. [`json`](https://json.org)
|
||||
* Not recommended
|
79
mods/modlib/doc/minetest/schematic.md
Normal file
79
mods/modlib/doc/minetest/schematic.md
Normal file
|
@ -0,0 +1,79 @@
|
|||
# Schematic
|
||||
|
||||
A schematic format with support for metadata and baked light data.
|
||||
|
||||
## Table Format
|
||||
|
||||
The table format uses a table with the following mandatory fields:
|
||||
|
||||
* `size`: Size of the schematic in nodes, vector
|
||||
* `node_names`: List of node names
|
||||
* `nodes`: List of node indices (into the `node_names` table)
|
||||
* `param2s`: List of node `param2` values (numbers)
|
||||
|
||||
and the following optional fields:
|
||||
|
||||
* `light_values`: List of node `param1` (light) values (numbers)
|
||||
* `metas`: Map from indices in the cuboid to metadata tables as produced by `minetest.get_meta(pos):to_table()`
|
||||
|
||||
A "vector" is a table with fields `x`, `y`, `z` for the 3 coordinates.
|
||||
|
||||
The `nodes`, `param2s` and `light_values` lists are in the order dictated by `VoxelArea:iterp` (Z-Y-X).
|
||||
|
||||
The cuboid indices for the `metas` table are calculated as `(z * size.y) + y * size.x + x` where `x`, `y`, `z` are relative to the min pos of the cuboid.
|
||||
|
||||
## Binary Format
|
||||
|
||||
The binary format uses modlib's Bluon to write the table format.
|
||||
|
||||
Since `param2s` (and optionally `light_values`) are all bytes, they are converted from lists of numbers to (byte)strings before writing.
|
||||
|
||||
For uncompressed files, it uses `MLBS` (short for "ModLib Bluon Schematic") for the magic bytes,
|
||||
followed by the raw Bluon binary data.
|
||||
|
||||
For compressed files, it uses `MLZS` (short for "ModLib Zlib-compressed Schematic") for the magic bytes,
|
||||
followed by the zlib-compressed Bluon binary data.
|
||||
|
||||
## API
|
||||
|
||||
### `schematic.setmetatable(obj)`
|
||||
|
||||
Sets the metatable of a table `obj` to the schematic metatable.
|
||||
Useful if you've deserialized a schematic or want to create a schematic from the table format.
|
||||
|
||||
### `schematic.create(params, pos_min, pos_max)`
|
||||
|
||||
Creates a schematic from a map cuboid
|
||||
|
||||
* `params`: Table with fields
|
||||
* `metas` (default `true`): Whether to store metadata
|
||||
* `light_values`: Whether to bake light values (`param1`).
|
||||
Usually not recommended, default `false`.
|
||||
* `pos_min`: Minimum position of the cuboid, inclusive
|
||||
* `pos_max`: Maximum position of the cuboid, inclusive
|
||||
|
||||
### `schematic:place(pos_min)`
|
||||
|
||||
"Inverse" to `schematic.create`: Places the schematic `self` starting at `pos_min`.
|
||||
|
||||
Content IDs (nodes), param1s, param2s, and metadata in the area will be completely erased and replaced; if light data is present, param1s will simply be set, otherwise they will be recalculated.
|
||||
|
||||
### `schematic:write_zlib_bluon(path)`
|
||||
|
||||
Write a binary file containing the schematic in *zlib-compressed* binary format to `path`.
|
||||
**You should generally prefer this over `schematic:write_bluon`: zlib compression comes with massive size reductions.**
|
||||
|
||||
### `schematic.read_zlib_bluon(path)`
|
||||
|
||||
"Inverse": Read a binary file containing a schematic in *zlib-compressed* binary format from `path`, returning a `schematic` instance.
|
||||
**You should generally prefer this over `schematic.read_bluon`: zlib compression comes with massive size reductions.**
|
||||
|
||||
### `schematic:write_bluon(path)`
|
||||
|
||||
Write a binary file containing the schematic in uncompressed binary format to `path`.
|
||||
Useful only if you want to eliminate the time spent compressing.
|
||||
|
||||
### `schematic.read_bluon(path)`
|
||||
|
||||
"Inverse": Read a binary file containing a schematic in uncompressed binary format from `path`, returning a `schematic` instance.
|
||||
Useful only if you want to eliminate the time spent decompressing.
|
39
mods/modlib/doc/minetest/texmod.md
Normal file
39
mods/modlib/doc/minetest/texmod.md
Normal file
|
@ -0,0 +1,39 @@
|
|||
# Texture Modifiers
|
||||
|
||||
## Specification
|
||||
|
||||
Refer to the following "specifications", in this order of precedence:
|
||||
|
||||
1. [Minetest Docs](https://github.com/minetest/minetest_docs/blob/master/doc/texture_modifiers.adoc)
|
||||
2. [Minetest Lua API](https://github.com/minetest/minetest/blob/master/doc/lua_api.txt), section "texture modifiers"
|
||||
3. [Minetest Sources](https://github.com/minetest/minetest/blob/master/src/client/tile.cpp)
|
||||
|
||||
## Implementation
|
||||
|
||||
### Constructors ("DSL")
|
||||
|
||||
Constructors are kept close to the original forms and perform basic validation. Additionally, texture modifiers can directly be created using `texmod{type = "...", ...}`, bypassing the checks.
|
||||
|
||||
### Writing
|
||||
|
||||
The naive way to implement string building would be to have a
|
||||
`tostring` function recursively `tostring`ing the sub-modifiers of the current modifier;
|
||||
each writer would only need a stream (often passed in the form of a `write` function).
|
||||
|
||||
The problem with this is that applying escaping quickly makes this run in quadratic time.
|
||||
|
||||
A more efficient approach passes the escaping along with the `write` function. Thus a "writer" object `w` encapsulating this state is passed around.
|
||||
|
||||
The writer won't necessarily produce the *shortest* or most readable texture modifier possible; for example, colors will be converted to hexadecimal representation, and texture modifiers with optional parameters may have the default values be written.
|
||||
You should not rely on the writer to produce any particular of the various valid outputs.
|
||||
|
||||
### Reading
|
||||
|
||||
**The reader does not attempt to precisely match the behavior of Minetest's shotgun "parser".** It *may* be more strict in some instances, rejecting insane constructs Minetest's parser allows.
|
||||
It *may* however sometimes also be more lenient (though I haven't encountered an instance of this yet), accepting sane constructs which Minetest's parser rejects due to shortcomings in its implementation.
|
||||
|
||||
The parser is written *to spec*, in the given order of precedence.
|
||||
If a documented construct is not working, that's a bug. If a construct which is incorrect according to the docs is accepted, that's a bug too.
|
||||
Compatibility with Minetest's parser for all reasonable inputs is greatly valued. If an invalid input is notably used in the wild (or it is reasonable that it may occur in the wild) and supported by Minetest, this parser ought to support it too.
|
||||
|
||||
Recursive descent parsing is complicated by the two forms of escaping texture modifiers support: Reading each character needs to handle escaping. The current depth and whether the parser is inside an inventorycube need to be saved in state variables. These could be passed on the stack, but it's more comfortable (and possibly more efficient) to just share them across all functions and restore them after leaving an inventorycube / moving to a lower level.
|
23
mods/modlib/doc/persistence/lua_log_file.md
Normal file
23
mods/modlib/doc/persistence/lua_log_file.md
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Lua Log Files
|
||||
|
||||
A data log file based on Lua statements. High performance. Example from `test.lua`:
|
||||
|
||||
```lua
|
||||
local logfile = persistence.lua_log_file.new(mod.get_resource"logfile.test.lua", {})
|
||||
logfile:init()
|
||||
logfile.root = {}
|
||||
logfile:rewrite()
|
||||
logfile:set_root({a = 1}, {b = 2, c = 3})
|
||||
logfile:close()
|
||||
logfile:init()
|
||||
assert(table.equals(logfile.root, {[{a = 1}] = {b = 2, c = 3}}))
|
||||
```
|
||||
|
||||
Both strings and tables are stored in a reference table. Unused strings won't be garbage collected as Lua doesn't allow marking them as weak references.
|
||||
This means that setting lots of temporary strings will waste memory until you call `:rewrite()` on the log file. An alternative is to set the third parameter, `reference_strings`, to `false` (default value is `true`):
|
||||
|
||||
```lua
|
||||
persistence.lua_log_file.new(mod.get_resource"logfile.test.lua", {}, false)
|
||||
```
|
||||
|
||||
This will prevent strings from being referenced, possibly bloating file size, but saving memory.
|
41
mods/modlib/doc/persistence/sqlite3.md
Normal file
41
mods/modlib/doc/persistence/sqlite3.md
Normal file
|
@ -0,0 +1,41 @@
|
|||
# SQLite3 Database Persistence
|
||||
|
||||
Uses a SQLite3 database to persistently store a Lua table. Obtaining it is a bit trickier, as it requires access to the `lsqlite3` library, which may be passed:
|
||||
|
||||
```lua
|
||||
local modlib_sqlite3 = persistence.sqlite3(require"lsqlite3")
|
||||
```
|
||||
|
||||
(assuming `require` is that of an insecure environment if Minetest is used)
|
||||
|
||||
Alternatively, if you are not running Minetest, mod security is disabled, you have (temporarily) provided `require` globally, or added `modlib` to `secure.trusted_mods`, you can simply do the following:
|
||||
|
||||
```lua
|
||||
local modlib_sqlite3 = persistence.sqlite3()
|
||||
```
|
||||
|
||||
Modlib will then simply call `require"lsqlite3"` for you.
|
||||
|
||||
Then, you can proceed to create a new database:
|
||||
|
||||
```lua
|
||||
local database = persistence.modlib_sqlite3.new(mod.get_resource"database.test.sqlite3", {})
|
||||
-- Create or load
|
||||
database:init()
|
||||
-- Use it
|
||||
database:set_root("key", {nested = true})
|
||||
database:close()
|
||||
```
|
||||
|
||||
It uses a similar API to Lua log files:
|
||||
|
||||
* `new(filename, root)` - without `reference_strings` however (strings aren't referenced currently)
|
||||
* `init`
|
||||
* `set`
|
||||
* `set_root`
|
||||
* `rewrite`
|
||||
* `close`
|
||||
|
||||
The advantage over Lua log files is that the SQlite3 database keeps disk usage minimal. Unused tables are dropped from the database immediately through reference counting. The downside of this is that this, combined with the overhead of using SQLite3, of course takes time, making updates on the SQLite3 database slower than Lua log file updates (which just append to an append-only file).
|
||||
As simple and fast reference counting doesn't handle cycles, an additional `collectgarbage` stop-the-world method performing a full garbage collection on the database is provided which is called during `init`.
|
||||
The method `defragment_ids` should not have to be used in practice (if it has to be, it happens automatically) and should be used solely for debugging purposes (neater IDs).
|
47
mods/modlib/doc/schema.md
Normal file
47
mods/modlib/doc/schema.md
Normal file
|
@ -0,0 +1,47 @@
|
|||
# Schema
|
||||
|
||||
Place a file `schema.lua` in your mod, returning a schema table.
|
||||
|
||||
## Non-string entries and `minetest.conf`
|
||||
|
||||
Suppose you have the following schema:
|
||||
|
||||
```lua
|
||||
return {
|
||||
type = "table",
|
||||
entries = {
|
||||
[42] = {
|
||||
type = "boolean",
|
||||
description = "The Answer"
|
||||
default = true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
And a user sets the following config:
|
||||
|
||||
```conf
|
||||
mod.42 = false
|
||||
```
|
||||
|
||||
It won't work, as the resulting table will be `{["42"] = false}` instead of `{[42] = false}`. In order to make this work, you have to convert the keys yourself:
|
||||
|
||||
```lua
|
||||
return {
|
||||
type = "table",
|
||||
keys = {
|
||||
-- this will convert all keys to numbers
|
||||
type = "number"
|
||||
},
|
||||
entries = {
|
||||
[42] = {
|
||||
type = "boolean",
|
||||
description = "The Answer"
|
||||
default = true
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This is best left explicit. First, you shouldn't be using numbered field keys if you want decent `minetest.conf` support, and second, `modlib`'s schema module could only guess in this case, attempting conversion to number / boolean. What if both number and string field were set as possible entries? Should the string field be deleted? And so on.
|
Loading…
Add table
Add a link
Reference in a new issue