From 8facf2952ab227ae8acafb19af88091d6d629924 Mon Sep 17 00:00:00 2001 From: uramer Date: Sun, 14 Mar 2021 16:39:26 +0100 Subject: [PATCH] Documentation for lua package 'openmw.query' --- .../reference/lua-scripting/overview.rst | 92 ++++++++++++++++++- 1 file changed, 90 insertions(+), 2 deletions(-) diff --git a/docs/source/reference/lua-scripting/overview.rst b/docs/source/reference/lua-scripting/overview.rst index 119d4b14c4..1603529ab5 100644 --- a/docs/source/reference/lua-scripting/overview.rst +++ b/docs/source/reference/lua-scripting/overview.rst @@ -247,7 +247,7 @@ Player scripts are local scripts that are attached to a player. +----------------------+--------------------+---------------------------------------------------------------+ |:ref:`openmw.async` | everywhere | | Timers (implemented) and coroutine utils (not implemented) | +----------------------+--------------------+---------------------------------------------------------------+ -|:ref:`openmw.query` | everywhere | **TODO: write description** | +|:ref:`openmw.query` | everywhere | | Tools for constructing queries: base queries and fields. | +----------------------+--------------------+---------------------------------------------------------------+ |:ref:`openmw.world` | by global scripts | | Read-write access to the game world. | +----------------------+--------------------+---------------------------------------------------------------+ @@ -306,7 +306,95 @@ Timers Queries ======= -**TODO:** describe the concepts of `openmw.query` and `world.selectObjects`/`nearby.selectObjects`. +`openmw.query` contains base queries of each type (e.g. `query.doors`, `query.containers`...), which return all of the objects of given type in no particular order. You can then modify that query to filter the results, sort them, group them, etc. Queries are immutable, so any operations on them return a new copy, leaving the original unchanged. + +`openmw.world.selectObjects` and `openmw.nearby.selectObjects` both accept a query and return objects that match it. However, `nearby.selectObjects` is only available in local scripts, and returns only objects from currently active cells, while `world.selectObjects` is only available in global scripts, and returns objects regardless of them being in active cells. +**TODO:** describe how to filter out inactive objects from world queries + +A minimal example of an object query: + +.. code-block:: Lua + + local query = require('openmw.query') + local nearby = require('openmw.nearby') + local ui = require('openmw.ui') + + local doorQuery = query.doors:orderBy(query.DOOR.destPosition.x) + + local function selectDoors(namePattern) + local query = doorQuery:where(query.DOOR.destCell:like(namePattern)) + return nearby.selectObjects(query) + end + + local function showGuildDoors() + ui.showMessage('Here are all the entrances to guilds!') + for _, door in selectDoors("%Guild%"):ipairs() do + local pos = door.position + local message = string.format("%.0f;%.0f;%.0f", pos.x, pos.y, pos.z) + ui.showMessage(message) + end + end + + return { + engineHandlers = { + onKeyPress = function(code, modifiers) + if code == string.byte('e') then + showGuildDoors() + end + end + } + } + +.. warning:: + The example above uses operation `like` that is not implemented yet. + +**TODO:** add non-object queries, explain how relations work, and define what a field is + +Queries are constructed through the following method calls: (if you've used SQL before, you will find them familiar) + +- `:where(filter)` - filters the results to match the combination of conditions passed as the argument +- `:orderBy(field)` and `:orderByDesc(field)` sort the result by the `field` argument. Sorts in descending order in case of `:orderByDesc`. Multiple calls can be chained, with the first call having priority. (i. e. if the first field is equal, objects are sorted by the second one...) +- `:groupBy(field)` returns only one result for each value of the `field` argument. The choice of the result is arbitrary. Useful for counting only unique objects, or checking if certain objects exist. +- `:limit(number)` will only return `number` of results (or fewer) +- `:offset(number)` skips the first `number` results. Particularly useful in combination with `:limit` + +Filters consist of conditions, which are combined with "and" (operator `*`), "or" (operator `+`), "not" (operator `-`) and braces `()`. + +To make a condition, take a field from the `openmw.query` package and call any of the following methods: + +- `:eq` equal to +- `:neq` not equal to +- `:gt` greater than +- `:gte` greater or equal to +- `:lt` less than +- `:lte` less or equal to +- `:like` matches a pattern. Only applicable to text (strings) + +**TODO:** describe the pattern format + +All the condition methods are type sensitive, and will throw an error if you pass a value of the wrong type into them. + +A few examples of filters: + +.. warning:: + `openmw.query.ACTOR` is not implemented yet + +.. code-block:: Lua + + local query = require('openmw.query') + local ACTOR = query.ACTOR + + local strong_guys_from_capital = (ACTOR.stats.level:gt(10) + ACTOR.stats.strength:gt(70)) + * ACTOR.cell.name:eq("Default city") + + -- could also write like this: + local strong_guys = ACTOR.stats.level:gt(10) + ACTOR.stats.strength:gt(70) + local guys_from_capital = ACTOR.cell.name:eq("Default city") + local strong_guys_from_capital_2 = strong_guys * guys_from_capital + + local DOOR = query.DOOR + + local interestingDoors = -DOOR.name:eq("") * DOOR.isTeleport:eq(true) * Door.destCell:neq("") Using IDE for Lua scripting