-
Notifications
You must be signed in to change notification settings - Fork 18
Getting Familiar With The Code
This page will walk you through the structure of OpenNefia's source repository.
The game's main code is in the src/
folder. All the files and folders referenced in Source Code below are contained in src/
. src/
is also the "root" of the game files as used by LÖVE, so any time the game is run it must use src/
as the working directory.
lib/
contains extra native libraries, primarily replacements for LÖVE's API when running with stock LuaJIT on Windows.
Note: If you're using a Unix-like OS you'll have to install these libraries with luarocks
and your system's package manager instead, but this shouldn't be too hard. lib/
is mainly provided for Windows users to not have to mess around with compiled dependencies.
api/
is where the base public API that all mods can use. It contains various individual APIs for creating characters, maps, and other things, generating random numbers, drawing to the screen. logging, and more. The following tutorials will describe the usage of some of the more important APIs, but if you're curious you can look in the source code for more information.
ext/
contains modifications to the Lua standard library. For example, ext/table.lua
modifies the table
API.
internal/
contains internal code which is not accessible by mods. Importantly, internal/draw/
and internal/layer/
contain the classes for drawing visual effects like shadows to the screen, so if you're debugging visual issues you might want to check them out. internal/data/
contains the base set of data definitions, like the available event types for use in the event system. Since there's a lack of documentation at the moment you might want to refer to internal/data/events.lua
if you want to see which events are available for use with the event system.
mod/
contains mods. Each folder in mod/
is named after the identifier of the mod, and contains Lua scripts and assets. More information about the structure of mods will be detailed in the section Creating Your First Mod. Three very important mods here are base
, elona_sys
and elona
.
-
base
contains a few definitions for keybindings, shaders, and a large portion of the localized text inside themod/base/locale/
folder. -
elona_sys
is intended to contain reusable features that have no real dependency on content added byelona
like specific types of magic. This includes map loading and dialog windows. -
elona
contains all the definitions for Elona's characters, items, and other things, as well as some APIs with dependencies on these definitions. For example, the dungeon generation algorithm has dependencies on map features added inmod/elona/data/feat.lua
since it can generate breakable pots, so the map generator for dungeons resides inelona
.
Personally I believe the elona_sys
/elona
split might cause more confusion than it's worth. It was partly done to ensure that enough functionality from vanilla Elona could be placed in mods without becoming entangled in base game logic, as a sort of test of the modding system's modularity. However, a large chunk of this base game logic is implemented in the base API and has unwanted dependencies on the elona
mod anyway, so that has to be resolved at some point.
Less important but still useful is the tools
mod. It contains mod/tools/api/Tools.lua
, where various personal functions for debugging are shoved into. It also has a few user interface features for introspecting things. A few of the features this mod provides are detailed in a later section.
Global variables are heavily restricted in OpenNefia's source. If you attempt to define or access an unknown global variable, the game will throw an error. This is to prevent unwanted mutation of global state, a pervasive problem in the original source code of Elona 1.22.
For user convenience, however, there is a limited set of globals accessible throughout most of the source code:
- The standard library of Lua 5.1.
-
inspect
: The library kikito/inspect.lua. -
fun
: A modified version of the library luafun/luafun. -
class
: Interface to an OOP system, which is a heavily modified version of 30log. Details about this system can be found in Object-Oriented Programming in OpenNefia. -
pause()
: A function which pauses the game's execution and starts a REPL, like a debug breakpoint. Details can be found in Engine Features. -
help(thing)
: A function for looking up in-game documentation.
Additionally, there is a separate set of globals available in mod environments only. These are set using env.setup_sandbox
inside internal/env.lua
.
-
_MOD_NAME
: Identifier of the current mod as a string. - A modified version of
loadstring
that uses the mod's environment instead of the global one. - The globals
inspect
,fun
,class
,pause
andhelp
.
Also, mod environments do not have access to dangerous functions/libraries like ffi
or most of debug
. This is done on a whitelist basis. The list of allowed globals in mod environments is defined in internal/env.lua
as SANDBOX_GLOBALS
.
In order for useful features like code hotloading to work, OpenNefia imposes stricter conventions on how Lua scripts are loaded using require
:
- The value that a Lua script returns should be either a single table or
nil
. - The name of the table returned by each script should match the name of the script file. For example, if your script is named
mod/neat_putits/api/NeatPutits.lua
, then the basic code structure insideNeatPutits.lua
should look like this:
-- Declare an API table.
local NeatPutits = {}
function NeatPutits.one_hundred_pounds_of_putits()
-- ...
end
return NeatPutits
You can then use this API by calling local NeatPutits = require("mod.neat_putits.api.NeatPutits")
.
This convention also helps discoverability and keeping things consistent.
Proceed to Creating Your First Mod.
For even more detail about the structure of the code, see Source Structure. This is just a personal memo of the files I end up visiting frequently when changing things. It could be useful for getting to know the important parts of the source code.