people/README.md

523 lines
19 KiB
Markdown

# People Mod
NOTE: Not currently compatible with stock minetest. Requires at least
the current git version, plus these:
* https://github.com/CiaranG/minetest/commit/740f057253495633db4cc53c905d4ea4ff1167c8
* https://github.com/CiaranG/minetest/commit/7b7e8bd4b924b74271eb26b30fa681eb8bd780c5
* https://github.com/CiaranG/minetest/commit/8eb489ece109e56c4d0fa01a0b956f7fa9f0ab56
* https://github.com/CiaranG/minetest/commit/8772041b43b78c86bc32e5682391286bca498848
* https://github.com/CiaranG/minetest/commit/f5b73e0baabbfe68bc6a9a52c5221930e4306ed2
* https://github.com/CiaranG/minetest/commit/45dc321b3c48f449bac5f9985db587847490d3e2
* https://github.com/CiaranG/minetest/commit/830f306d0800e1e504174799c410e75a35687f1b
* https://github.com/CiaranG/minetest/commit/294d98c3783c1c1f5abe05e509982ba535f60b46
* https://github.com/CiaranG/minetest/commit/db67b29f925a477a33ebe6d784fccab332214952
* https://github.com/CiaranG/minetest/commit/e0ae57fdb44a5dd4a542677e2513793962ae5b3d
* https://github.com/CiaranG/minetest/commit/638a246de7e7709eb0d5ec5485a4782f53c10fc0
This mod provides 'people' (non player characters) that are programmable
in-game. Each NPC's Lua code runs inside a secure sandbox for that NPC only.
Author: Ciaran Gultnieks
License: LGPL
Includes lua sandbox setup code from mesecons by Jeija (also LGPL), and inspiration
from the npcf mod, and (obviously!) the mesecons lua controller design.
The character model is a modified version of the default player model from
the default minetest game.
## Requirements
Optionally, you might want these mods:
* areas (my fork of it) - https://github.com/CiaranG/areas - for being able to
specify an area as a destination
* footpath - https://gitlab.com/CiaranG/moddebug - for full route finding and
navigation support
* moddebug - https://gitlab.com/CiaranG/moddebug - for debug logging
## Usage
To create a person, issue this command:
/people create Bob
This places a person called "Bob" at your current location.
Then, right-click it at any time to program it. For now, until I think
of a better name, we'll refer to the code you enter here as "the person's
lua code"!
## The Person's Lua Code
This code, as entered in the right-click dialog for a person you own, is
really an event handler. It runs in a sandbox, and when called will always
have a variable called 'event'. This is a table, and the "type" field
determines the type of event that caused the call.
Here is a very simple example:
```lua
if event.type == "program" then
action = {"follow", name=event.programmer}
end
```
To enter this, select "Custom" from the Preset dropdown, and type in the code.
Then, when you hit the Program button, the person will start following
the player who pressed the button and keep doing that until they log off. Because
the code does nothing in response to an "act" event, at that point they will go
into a permanent wait (sleep) state.
### Sandbox
The code runs in a sandboxed Lua environment. Only a limited range of
functionality is available, and in particular things like loops and functions
are prohibited.
A range of standard string, table and math library functions are made
available, as well as the built in minetest vector helpers.
In addition:
* `log(msg)` - logs a v1 debug message
* `mem` - the person's memory - see under Persistence
* `carrying(item)` - returns the number of a particluar item the person is
carrying - e.g. carrying("default:cobble") might return 0, 10, 99 or 198.
### Persistence
The sandboxed Lua environment persists for as long as the person is active.
In addition to saving setup time on each call, this allows 'local' (actually
global to the sandboxed environment) variables persist between calls for
different events.
Information that needs to persist longer than this (i.e. across deactivations
or server restarts) can be stored in the person's "memory". The 'mem' table
(initially empty) can be used to store anything required. It will persist for
the entire lifetime of the person.
### Presets
Several 'presets' are supplied, which serve as both examples and useful
functionality. When editing, select one of the presets from the dropdown and that
preset will be used. If you subsequently select "Custom", the code from the
previously selected preset will be loaded as a base for further editing.
A brief description of these:
####FollowOwner
When programmed, follows the programmer until they log off
####SimpleCommands
Responds to simple commands. Some examples:
* `/tell Bob come here`,
* `/tell Bob go to Sugar Harbour`
* `/tell Bob follow me`
* '/tell Bob drop 23 Stone`
* '/tell Bob drop default:cobble`
Look at the code for more things it can do.
####RouteWalker
Follows a preset route (hard-coded, so you would want to edit it) indefinitely.
## Events
The following event types are received by the person's lua code:
### act
This happens when the person has no current action (see the Actions section).
The handler should select a new action, by setting the 'action' variable. If
it fails to do so, the person will do an automatic wait.
### actfail
This happens when an action fails, unless there is a 'prevaction' set. (To
get a fail, but still have a follow-on action, use 'successaction' instead!)
There is also event.failedaction available, which is the action that actually
failed, and event.failcode which is the failure code that the action returned.
That is normally just false, but some action handlers can return special
values here (anything non-true would be a fail) to indicate particular
things.
### tell
This happens when a player (who must be the owner, current) sends a message
to the person (e.g. via the 'people tell' chat command). It can be used to
respond to commands. The message is in event.message and the name of the
sender is in event.sender, and their position is in event.senderpos.
### step
This happens only when the "step" action is running. It's called every server
step, with event.dtime containing the time since the last step. The handler
should update the speed and yaw variables, or set a new action.
### program
This happens when the lua code has been edited. The name of the player that
did the programming is passed as event.programmer.
### activate
This happens when the entity is activated (either it's brand new, or is in
a block that was unloaded but is now loaded). It is called with event.dtime_s
containing the time since it was last active.
### punched
This happens when a player punches the entity. The name of the offending player
is sent as event.puncher.
## Actions
Actions are the basic building blocks of object behaviour. A person always
has a current action which they are completing, the execution of which is
handled by the mod. The job of the lua programming within the person is to
sit at a higher level of 'conciousness' and select the appropriate actions.
The person's lua code receives an "act" event when it should select an
action - usually when the current action completes. It can also set/replace
the current action in response to any other event. Setting the action is
a simple case of setting the 'action' variable within the lua code.
An action is defined by a table, where the first element [1] is the ID of
the action, and additional named fields contain parameters. For a simple
example, {"go", pos={5,0,5}} is an action to move the person to the given
position.
### Action types
The following actions are currently defined:
#### go
Go (walk) to a location. This generally decomposes into a more complex set
of actions, the ultimate aim of which is to get to the given destination
somehow.
One of the following parameters is needed:
* pos={x,y,z} - specifies an absolute position to go to
* rel={x,y,z} - to go a relative offset from the current position
* name=string - specifies a footpath node or area (see the Navigation
section
Many other parameters are handled by the go action, but these are used
internally only.
#### follow, with name="playername"
Follows the given player indefinitely (or at least until they log off).
#### face, with pos={x,y,z} or yaw=angle
Standing still, face towards the given position, or in the given direction.
#### wait, with time
Do nothing for that many seconds. This may allow the entity to be deactivated
and unloaded, in which case it will be reactivated at the appropriate time.
Short waits may not result in deactivation.
#### drop, with item="name", count=n
Drop the given item. The itemspec is either the full node name (e.g.
"default:stone_brick") or the description as seen in-game, which is
case insensitive (e.g. "stone brick").
Optionally, count can specify the number to drop. Defaults to one if
not specified.
#### dig, with pos={x,y,z}
Dig the node at the given position. Must be within range.
#### rightclicknode, with pos={x,y,z}
Right-click the node at the given position. Must be within range.
#### place
Places an item (node). Must be in the inventory, and in range.
* Required parameter: pos={x,y,z}
* Required parameter: item=itemname
* Optional parameter: param2=value (e.g. for setting facedir)
* Optional parameter: againstdir={x,y,z}
#### stash
* Required parameter: items={item1, ..., itemn"}
* Optional parameter: pos={x,y,z} - position of node to stash in
* Optional parameter: dest="node" - node name to stash in
(e.g. "default:chest")
(You need either pos or dest, or nothing will happen)
Places items into a destination node, which should be something like a chest.
Specifically, it needs to be a node with a "main" inventory list. So for a
normal chest, use "default:chest" for the nodename.
Each item in the list can be:
* Just the item name (e.g. "default:cobble") to put all held in
* Item name and count (e.g. "default:cobble 50") to put that many in
* Table ({"default:cobble", keep=5}) to keep 5 but put the rest in
#### retrieve
Gets items from a source node, which should be something like a chest.
Specifically, it needs to be a node with a "main" inventory list. So for a
normal chest, use "default:chest" for the nodename.
* Required parameter: items={item1, ..., itemn"}
* Optional parameter: pos={x,y,z} - position of node to stash in
* Optional parameter: src="node" - node name to retrieve from
(e.g. "default:chest")
(You need either pos or dest, or nothing will happen)
The items in the list are defined in the same way as for the stash action.
#### sell
* Required parameter: item="itemstring"
Need to be standing within range of a shop (barrel mod) that buys the item
in question.
The entire amount of the item carried will be sold, assuming the shop can
afford to buy it all.
#### buy
* Required parameter: item="itemname"
* Required parameter: num=amount
Need to be standing within range of a shop (barrel mod) that sells the item
in question, and have enough money. If the person doesn't have enough money
to buy the amount specified, a lesser amount may be bought instead.
#### obtain
Meta-action to obtain some of an item by whatever means possible. This could
use crafting, buying, mining, whatever, the only aim is to get it.
The specified amount is the total amount we want to end up having - so if we
already have that many, the action will not do anything. Otherwise, it could
use one or more of the available methods until the total is achieved.
* Required paramter: item="itemname"
* Required parameter: num=amount
#### craft
Craft an item.
* Required paramter: item="itemname"
* Required parameter: num=amount
#### gather
Changes current gathering settings.
All parameters are optional:
* `nodes = {}` - list of nodes to dig
* `topnodes = {}` - list of nodes to dig only if there is a) air above,
and b) the same node below - think of harvesting
cactus/papyrus while still allowing them to grow back!
* `items = {}` - list of items to pick up
* `plant = nil - seed to plant
* animal = nil - species of animal to harvest from
* animal_wield = nil - item to wield when harvesting
So calling with no parameters at all turns off gathering.
Gathering remains in effect until it is switched off, or until the person
is re-programmed. Gathering actually happens during "go" and "wait" actions
only (but this includes any action that uses "go" as a subaction).
Both planting and gathering happen in a square +/- 3m around the person.
This means a good farm arrangement is plots that are 7x7, with a (covered)
water source in the middle, where the person stands to plant and harvest.
#### attackplayer
Attack a player. Parameters:
* `name = "name"` - name of player to attack
The action will cancel when the player is out of range.
#### pickup
Picks up an item. Parameters:
* `pos = {x,y,z}` - position of the item (required)
* `item = "name"` - name of item, e.g. "default:dirt"
#### harvest
Harvest from an animal from the animals mod. Parameters:
* name = "name" - the name of the animal (e.g. "cow 1452")
The correct item should already be wielded. This is normally used in
conjunction with gathering, in which case the wielding is already
handled.
#### tunnel
Tunnel, from the current position. Also builds bridges!
Parameters:
* `dir = {x,y,z}` - direction - either x or z must be 0. and the
other +/-1, while y can be 0 or +/-1.
* 'distance = n` - distance to go for (reduces as the action
proceeds)
* `floor=item` - material to use for floor - optional
* `wall=item` - material to use for wall linings - optional
* `ceiling=item` - material to use for ceiling - optional
* `steps=item` - material to use for steps, on slopes.
* `lighting=item` - material (most likely default:torch) to use for
lighting, which is placed against walls at
4 metre intervals. Optional.
* `support_top=item` - material to use for top supports, which are placed
against the ceiling at 8 metre intervals. Optional.
* `support_ceiling=item` - like support_top, but at ceiling level, not below.
* `support_side=item` - material to use for side supports. Optional.
* `support_side_facein=? - set to true to make the side supports face in
towards the tunnel centre. (Try it with slabs, for
example!)
* `support_wall=item` - like support_side, but at wall level, not within.
#### building
Make a building, from current position.
The current position is designated as the entrance to the building.
Parameters:
* `dir = {x,y,z}` - direction - either x or z must be 0. and the
other +/-1, while y can be 0 or +/-1.
* `width = n` - the width of the building
* `depth = n` - the depth of the building
* `height = n` - the height of the building
* `wall = item` - material to use for walls
* `outside_floor = item` - material to use for the floor outside the walls.
Optional. Does not include the entrance.
This can also be a table, with two entries, in
which case the floor can be either of those, and
if it's not it's replaced with the first. (Example
use case of that is if it's dirt, in which case
it can change to dirt_with_grass, and be left
alone!)
* `door=item` - Door to use. Doorways will be left open if not
specified.
#### step
Allow's the person's lua code to handle on_step itself. It will receive
"step" events (with dtime) and should reset the action when it no longer
needs to do this. It can update 'speed' and 'yaw' and these will be used.
### Nesting
Any action can have a "prevaction" field, which should be a valid action
itself. It will be set when the action has completed. This can be used to nest
actions.
The actions themselves may make use of this functionality. For example, the
follow action is implemented by repeatedly selecting positions near the target
player, and then replacing it self with a "go" action with the original follow
nested as a "prevaction" within it. Thus, when the "go" completes, the follow
resumes once more.
## Chat Commands
People can be managed and controlled via chat commands. Most of these commands
can be issued when a person is inactive - they will be automatically woken
(the unloaded block where they are sleeping will be loaded) and then the
command executed.
The following commands are available:
### /people help
Lists all the available commands.
### /people create `name`
Creates a new person, at your current location.
### /people delete `name`
Deletes a person.
### /people where `name`
Tells you the current location of a person.
### /people summon `name`
Moves the person to your current location.
### /people setowner `name` `playername`
Changes the owner of the person.
### /people tell `name` `message`
The person receives a "tell" event with the given message.
### /tell `name` `message`
Alias for /people tell, for convenience.
### /people status
Lists all people in the word, and their current status (active/inactive).
### /people skin `name` `skin_name|list`
Sets the skin of the person to the named one. (Or use 'list' to get a
list of available skins, which come from the skins mod).
### /people track `name`
Track the given person (location and distance away) on the HUD.
Use without a parameter to switch it off.
## Autonomy and Activation
People are 'autonomous' - i.e. they will continue to act even when no player
is nearby. Indeed, they will continue to act even when no player at all is
logged in to the server.
However, they are designed to be able to not remain active unless necessary.
This is mostly done by use of the "wait" action.
If you set a person to wait for 5 minutes, then assuming no player or other
active entity is nearby, the block the person is in (and surrounding blocks)
will be unloaded, and the person will cease to exist as far as the minetest
engine is concerned. However, after 5 minutes, this mod will reactivate it
by reloading the block.
### Force Loading
This mod uses the 'force loading' API (which is silly and inadequate) to
reactive sleeping entities when it needs to. It does not require the
persistence over server restarts of force-loaded blocks, and while it ought
to clean up any force loading it does almost immediately, that cannot happen
if there is a server crash or other unclean shutdown at the wrong moment.
You could mitigate this by always removing the force loaded blocks file from
the world directory on startup.
Ultimately it won't use this 'feature' at all.
## Footpaths and Navigation
People (in particular via the 'go' action) have an in-built understanding of
footpaths, which are managed via the footpath mod. This provides people with
the ability to do sensible long-range navigation as a player would.
When following a footpath, preference will always be given to the direction
currently being travelled in. The means that, for example, a cobblestone
footpath can cross a larger area 'paved' with cobblestone (or other footpath
materials), so long as the crossing is in a straight line.
If you tell a person to go to a named place (e.g. {"go", name="My House"}) they
will first look for a footpath junction with that name, and then also find the
nearest junction to where they are now. They will then navigate along the path
network from one to the other.
If there is no footpath junction with that name, they'll also look for an area
(areas mod) and head directly for the centre of that area.