1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
|
# API documentation for the Documentation System core framework
## Core concepts
As a modder, you are free to write basically about everything and are also
relatively free in the presentation of information. The Documentation
System has no restrictions on content whatsoever.
### Categories and entries
In the documentation system, everything is built on categories and entries.
An entry is a single piece of documentation and is the basis of all actual
documentation. Categories group multiple entries of the same topic together.
Categories also define a template function which is used to determine how the
final result in the tab “Entry list” looks like. Entries themselves have
a data field attached to them, this is a table containing arbitrary metadata
which is used to construct the final formspec which is used on the Entry tab.
## Advanced concepts
### Viewed and hidden entries
The mod keeps track of which entries have been viewed on a per-player basis.
Any entry which has been accessed by a player is instantly marked as “viewed”.
It also allows entries to be hidden. Hidden entries are not visible or
otherwise accessible to players until they become revealed by function calls.
Marking an entry as viewed or revealed is not reversible with this API.
The viewed and hidden states are stored in the file `doc.mt` inside the
world directory. You can safely delete this file if you want to reset
the player states.
### Entry aliases
Entry aliases are alternative identifiers for entry identifiers. With the
exception of the alias functions themselves, for function demanding an
`entry_id` you can either supply the original `entry_id` or any alias of the
`entry_id`.
## Possible use cases
Here are some possible use cases to give you a rough idea what
this mod is capable of and how certain use cases should be implemented.
### Simple use case: Minetest basics
Let's say you want to write in free form short help texts about the basic
concepts of Minetest or your subgame. First you could define a category
called “Basics”, the data for each of its entry is just a free form text.
The template function simply creates a formspec where this free form
text is displayed.
This is one of the most simple use cases and the mod `doc_basics` does
exactly that.
### Complex use case: Blocks
You could create a category called “Blocks”, and this category is supposed to
contain entries for every single block (i.e. node) in the game. For this use
case, a free form approach would be very inefficient and error-prone, as a
lot of data can be reused.
Here the template function comes in handy: The internal entry data
contain a lot of different things about a block, like block name, identifier,
custom description and most importantly, the definition table of the block.
Finally, the template function takes all that data and turns it into
sentences which are just concatenated, telling as many useful facts about
this block as possible.
## Functions
This is a list of all publicly available functions.
### Overview
The most important functions are `doc.new_category` and `doc.new_entry`. All other functions
are mostly used for utility and examination purposes.
These functions are available:
* `doc.new_category`: Adds a new category
* `doc.new_entry`: Adds a new entry
* `doc.set_category_order`: Sets the order of categories in the category list
* `doc.show_entry`: Shows a particular entry to a player
* `doc.show_category`: Shows the entry list of a category to a player
* `doc.show_doc`: Opens the main Documentation System form for a player
* `doc.get_category_definition`: Returns the definition table of a category
* `doc.get_entry_definition`: Returns the definition table of an entry
* `doc.entry_exists`: Checks whether an entry exists
* `doc.entry_viewed`: Checks whether an entry has been viewed/read by a player
* `doc.entry_revealed`: Checks whether an entry is visible and normally accessible to a player
* `doc.mark_entry_as_viewed`: Manually marks an entry as viewed/read by a player
* `doc.mark_entry_as_revealed`: Make a hidden entry visible and accessible to a player
* `doc.mark_all_entries_as_revealed`: Make all hidden entries visible and accessible to a player
* `doc.add_entry_alias`: Add an alternative name which can be used to access an entry
* `doc.add_entry_aliases`: Add multiple alternative names which can be used to access an entry
* `doc.get_category_count`: Returns the total number of categories
* `doc.get_entry_count`: Returns the total number of entries in a category
* `doc.get_viewed_count`: Returns the number of entries a player has viewed in a category
* `doc.get_revealed_count`: Returns the number of entries a player has access to in a category
* `doc.get_hidden_count`: Returns the number of entries which are hidden from a player in a category
* `doc.get_selection`: Returns the currently viewed entry/category of a player
If not mentioned otherwise, the return value of all functions is `nil`.
#### Special widgets
This API provides functions to add unique “widgets” for functionality
you may find useful when creating entry templates. You find these
functions in `doc.widgets`.
Currently there is a widget for scrollable multi-line text and a
widget providing an image gallery.
### `doc.new_category(id, def)`
Adds a new category. You have to define an unique identifier, a name
and a template function to build the entry formspec from the entry
data.
**Important**: You must call this function *before* any player joins.
#### Parameters
* `id`: Unique category identifier as a string
* `def`: Definition table with the following fields:
* `name`: Category name to be shown in the interface
* `description`: (optional) Short description of the category,
will be shown as tooltip. Recommended style (in English):
First letter capitalized, no punctuation at the end,
max. 100 characters
* `build_formspec`: The template function (see below). Takes entry data
as its first parameter (has the data type of the entry data) and the
name of the player who views the entry as its second parameter. It must
return a formspec which is inserted in the Entry tab.
* `sorting`: (optional) Sorting algorithm for display order of entries
* `"abc"`: Alphabetical (default)
* `"nosort"`: Entries appear in no particular order
* `"custom"`: Manually define the order of entries in `sorting_data`
* `"function"`: Sort by function defined in `sorting_data`
* `sorting_data`: (optional) Additional data for special sorting methods.
* If `sorting=="custom"`, this field must contain a table (list form) in which
the entry IDs are specified in the order they are supposed to appear in the
entry list. All entries which are missing in this table will appear in no
particular order below the final specified one.
* If `sorting=="function"`, this field is a compare function to be used as
the `comp` parameter of `table.sort`. The parameters given are two entries.
* This field is not required if `sorting` has any other value
* `hide_entries_by_default` (optional): If `true`, all entries
added to this category will start as hidden, unless explicitly specified otherwise
(default: `false`)
Note: For function-based sorting, the entries provided to the compare function
will have the following format:
{
name = n, -- entry name
data = d, -- arbitrary entry data
}
#### Using `build_formspec`
For `build_formspec` you can either define your own function which
procedurally generates the entry formspec or you use one of the
following predefined convenience functions:
* `doc.entry_builders.text`: Expects entry data to be a string.
It will be inserted directly into the entry. Useful for entries with
a free form text.
* `doc.entry_builders.text_and_gallery`: For entries with text and
an optional standard gallery (3 rows, 3:2 aspect ratio). Expects
entry data to be a table with these fields:
* `text`: The entry text
* `images`: The images of the gallery, the format is the same as the
`imagedata` parameter of `doc.widgets.gallery`. Can be `nil`, in
which case no gallery is shown for the entry
* `doc.entry_builders.formspec`: Entry data is expected to contain the
complete entry formspec as a string. Useful if your entries. Useful
if you expect your entries to differ wildly in layouts.
##### Formspec restrictions
When building your formspec, you have to respect the size limitations.
The documentation system uses a size of 12×9 and you must make sure
all entry widgets are inside a boundary box. The remaining space is
reserved for widgets of the Documentation System and should not be used
to avoid overlapping.
Read from the following variables to calculate the final formspec coordinates:
* `doc.FORMSPEC.WIDTH`: Width of Documentation System formspec
* `doc.FORMSPEC.HEIGHT`: Height of Documentation System formspec
* `doc.FORMSPEC.ENTRY_START_X`: Leftmost X point of bounding box
* `doc.FORMSPEC.ENTRY_START_Y`: Topmost Y point of bounding box
* `doc.FORMSPEC.ENTRY_END_X`: Rightmost X point of bounding box
* `doc.FORMSPEC.ENTRY_END_Y`: Bottom Y point of bounding box
* `doc.FORMSPEC.ENTRY_WIDTH`: Width of the entry widgets bounding box
* `doc.FORMSPEC.ENTRY_HEIGHT`: Height of the entry widgets bounding box
Finally, to avoid naming collisions, you must make sure that all identifiers
of your own formspec elements do *not* begin with “`doc_`”.
##### Receiving formspec events
You can even use the formspec elements you have added with `build_formspec` to
receive formspec events, just like with any other formspec. For receiving, use
the standard function `minetest.register_on_player_receive_fields` to register
your event handling. The `formname` parameter will be `doc:entry`. Use
`doc.get_selection` to get the category ID and entry ID of the entry in question.
### `doc.new_entry(category_id, entry_id, def)`
Adds a new entry into an existing category. You have to define the category
to which to insert the entry, the entry's identifier, a name and some
data which defines the entry. Note you do not directly define here how the
end result of an entry looks like, this is done by `build_formspec` from
the category definition.
**Important**: You must call this function *before* any player joins.
#### Parameters
* `category_id`: Identifier of the category to add the entry into
* `entry_id`: Unique identifier of the new entry, as a string
* `def`: Definition table, it has the following fields:
* `name`: Entry name to be shown in the interface
* `hidden`: (optional) If `true`, entry will not be displayed in entry list
initially (default: `false`); it can be revealed later
* `data`: Arbitrary data attached to the entry. Any data type is allowed;
The data in this field will be used to create the actual formspec
with `build_formspec` from the category definition
### `doc.set_category_order(category_list)`
Sets the order of categories in the category list.
The Documentation System starts with this default order:
{"basics", "online", "nodes", "tools", "craftitems"}
This function can be called at any time, but it recommended to only call
this function once for the entire server session and to only call it
from subgame mods, to avoid contradictions. If this function is called a
second time by any mod, a warning is written into the log.
#### Parameters
* `category_list`: List of category IDs in the order they should appear
in the category list. All unspecified categories will be appended to
the end
### `doc.show_doc(playername)`
Opens the main documentation formspec for the player (“Category list” tab).
#### Parameters
* `playername`: Name of the player to show the formspec to
### `doc.show_category(playername, category_id)`
Opens the documentation formspec for the player at the specified category
(“Entry list” tab).
#### Parameters
* `playername`: Name of the player to show the formspec to
* `category_id`: Category identifier of the selected category
### `doc.show_entry(playername, category_id, entry_id, ignore_hidden)`
Opens the documentation formspec for the player showing the specified entry
of a category (“Entry” tab). If the entry is hidden, an error message
is displayed unless `ignore_hidden==true`.
#### Parameters
* `playername`: Name of the player to show the formspec to
* `category_id`: Category identifier of the selected category
* `entry_id`: Entry identifier of the entry to show
* `ignore_hidden`: (optional) If `true`, shows entry even if it is still hidden
to the player; this will automatically reveal the entry to this player for the
rest of the game
### `doc.get_category_definition(category_id)`
Returns the definition of the specified category.
#### Parameters
* `category_id`: Category identifier of the category to the the definition
for
#### Return value
The category's definition table as specified in the `def` argument of
`doc.new_category`. The table fields are the same.
### `doc.get_entry_definition(category_id, entry_id)`
Returns the definition of the specified entry.
#### Parameters
* `category_id`: Category identifier of entry's category
* `entry_id`: Entry identifier of the entry to get the definition for
#### Return value
The entry's definition table as specified in the `def` argument of
`doc.new_entry`. The table fields are the same.
### `doc.entry_exists(category_id, entry_id)`
Checks whether the specified entry exists and returns `true` or `false`.
#### Parameters
* `category_id`: Category identifier of the category to check
* `entry_id`: Entry identifier of the entry to check for its existence
#### Return value
Returns `true` if and only if:
* The specified category exists
* It contains the specified entry
Otherwise, returns `false`.
### `doc.entry_viewed(playername, category_id, entry_id)`
Tells whether the specified entry is marked as “viewed” (or read) by
the player.
#### Parameters
* `playername`: Name of the player to check
* `category_id`: Category identifier of the category to check
* `entry_id`: Entry identifier of the entry to check
#### Return value
`true`, if entry is viewed, `false` otherwise.
### `doc.entry_revealed(playername, category_id, entry_id)`
Tells whether the specified entry is marked as “revealed” to the player
and thus visible and accessible to the player.
#### Parameters
* `playername`: Name of the player to check
* `category_id`: Category identifier of the category to check
* `entry_id`: Entry identifier of the entry to check
#### Return value
`true`, if entry is revealed, `false` otherwise.
### `doc.mark_entry_as_viewed(playername, category_id, entry_id)`
Marks a particular entry as “viewed” (or read) by a player. This will
also automatically reveal the entry to the player for the rest of
the game.
#### Parameters
* `playername`: Name of the player for whom to mark an entry as “viewed”
* `category_id`: Category identifier of the category of the entry to mark
* `entry_id`: Entry identifier of the entry to mark
### `doc.mark_entry_as_revealed(playername, category_id, entry_id)`
Marks a particular entry as “revealed” to a player. If the entry is
declared as hidden, it will become visible in the list of entries for
this player and will always be accessible with `doc.show_entry`. This
change remains for the rest of the game.
For entries which are not normally hidden, this function has no direct
effect.
#### Parameters
* `playername`: Name of the player for whom to reveal the entry
* `category_id`: Category identifier of the category of the entry to reveal
* `entry_id`: Entry identifier of the entry to reveal
### `doc.mark_all_entries_as_revealed(playername)`
Marks all entries as “revealed” to a player. This change remains for the
rest of the game.
#### Parameters
* `playername`: Name of the player for whom to reveal the entries
### `doc.add_entry_alias(category_id, entry_id, alias)`
Adds a single alias for an entry. If an entry has an alias, supplying the
alias to a function which demands an `entry_id` will work as if the original
`entry_id` has been supplied. The scope of an alias is the category in which
it has been created.
When using this function, you must make sure the category already exists.
#### Parameters
* `category_id`: Category identifier of the category of the entry in question
* `entry_id`: The original (!) entry identifier of the entry to create an alias
for
* `alias`: Alias (string) for `entry_id`
### `doc.add_entry_aliases(category_id, entry_id, aliases)`
Adds an arbitrary amount of aliases for an entry at once. Apart from that, this
function has the same effect as `doc.add_entry_alias`.
When using this function, you must make sure the category already exists.
#### Parameters
* `category_id`: Category identifier of the category of the entry in question
* `entry_id`: The original (!) entry identifier of the entry to create aliases
for
* `aliases`: Table/list of aliases (strings) for `entry_id`
### `doc.get_category_count()`
Returns the number of registered categories.
#### Return value
Number of registered categories.
### `doc.get_entry_count(category_id)`
Returns the number of entries in a category.
#### Parameters
* `category_id`: Category identifier of the category in which to count entries
#### Return value
Number of entries in the specified category.
### `doc.get_viewed_count(playername, category_id)`
Returns how many entries have been viewed by a player.
#### Parameters
* `playername`: Name of the player to count the viewed entries for
* `category_id`: Category identifier of the category in which to count the
viewed entries
#### Return value
Amount of entries the player has viewed in the specified category. If the
player does not exist, this function returns `nil`.
### `doc.get_revealed_count(playername, category_id)`
Returns how many entries the player has access to (non-hidden entries)
in this category.
#### Parameters
* `playername`: Name of the player to count the revealed entries for
* `category_id`: Category identifier of the category in which to count the
revealed entries
#### Return value
Amount of entries the player has access to in the specified category. If the
player does not exist, this function returns `nil`.
### `doc.get_hidden_count(playername, category_id)`
Returns how many entries are hidden from the player in this category.
#### Parameters
* `playername`: Name of the player to count the hidden entries for
* `category_id`: Category identifier of the category in which to count the
hidden entries
#### Return value
Amount of entries hidden from the player. If the player does not exist,
this function returns `nil`.
### `doc.get_selection(playername)`
Returns the currently or last viewed entry and/or category of a player.
#### Parameter
* `playername`: Name of the player to query
#### Return value
It returns up to 2 values. The first one is the category ID, the second one
is the entry ID of the entry/category which the player is currently viewing
or is the last entry the player viewed in this session. If the player only
viewed a category so far, the second value is `nil`. If the player has not
viewed a category as well, both returned values are `nil`.
### `doc.widgets.text(data, x, y, width, height)`
This is a convenience function for creating a special formspec widget. It creates
a widget in which you can insert scrollable multi-line text.
As of Minetest 0.4.14, this function is only provided because Minetest lacks
native support for such a widget. When Minetest supports such a widget natively,
this function may become just a simple wrapper.
#### Parameters
* `data`: Text to be written inside the widget
* `x`: Formspec X coordinate (optional)
* `y`: Formspec Y coordinate (optional)
* `width`: Width of the widget in formspec units (optional)
* `height`: Height of the widget in formspec units (optional)
The default values for the optional parameters result in a widget which fills
nearly the entire entry page.
#### Return value
Two values are returned, in this order:
* String: Contains a complete formspec definition building the widget.
* String: Formspec element ID of the created widget
#### Note
If you use this function to build a formspec string, do not use identifiers
beginning with `doc_widget_text` to avoid naming collisions, as this function
makes use of such identifiers internally.
### `doc.widgets.gallery(imagedata, playername, x, y, aspect_ratio, width, rows, align_left, align_top)`
This function creates an image gallery which allows you to display an
arbitrary amount of images aligned horizontally. It is possible to add more
images than the space of an entry would normally held, this is done by adding
“scroll” buttons to the left and right which allows the user to see more images
of the gallery.
This function is useful for adding multiple illustration to your entry without
worrying about space too much. Adding illustrations can help you to create
entry templates which aren't just lengthy walls of text. ;-)
You can define the position, image aspect ratio, total gallery width and the
number of images displayed at once. You can *not* directly define the image
size, nor the resulting height of the overall gallery, those values will
be derived from the parameters.
You can only really use this function efficiently inside a *custom*
`build_formspec` function definition. This is because you need to pass a
`playername`. You can currently also only add up to one gallery per entry;
adding more galleries is not supported and will lead to bugs.
### Parameters
* `imagedata`: List of images to be displayed in the specified order. All images must
have the same aspect ratio. It's a table of tables with this format:
* `image`: Texture name of an image
* `playername`: Name of the player who is viewing the entry in question
* `x`: Formspec X coordinate of the top left corner (optional)
* `y`: Formspec Y coordinate of the top left corner (optional)
* `aspect_ratio`: Aspect ratio of all the images (width/height)
* `width`: Total gallery width in formspec units (optional)
* `rows`: Number of images which can be seen at once (optional)
* `align_left`: If `false`, gallery is aligned to the left instead of the right (optional)
* `align_right`: If `false`, gallery is aligned to the bottom instead of the top (optional)
The default values for the optional parameters result in a gallery with
3 rows which is placed at the top left corner and spans the width of the
entry and assumes an aspect ratio of two thirds.
If the number of images is greater than `rows`, “scroll” buttons will appear
at the left and right side of the images.
#### Return values
Two values are returned, in this order:
* String: Contains a complete formspec definition building the gallery
* Number: The height the gallery occupies in the formspec
## Extending this mod (naming conventions)
If you want to extend this mod with your own functionality, it is recommended
that you put all API functions into `doc.sub.<name>`.
As a naming convention, if you mod *primarily* depends on `doc`, it is recommended
to use a short mod name which starts with “`doc_`”, like `doc_items`,
`doc_minetest_game`, or `doc_identifier`.
One mod which uses this convention is `doc_items` which uses the `doc.sub.items`
table.
|