Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ draft = false
author = "Slashscreen"
+++

RmlUi is a UI framework that is defined using a HTML/CSS style workflow (using Lua instead of JS) intended to simplify UI development especially for those already familiar with web development. It is designed for interactive applications, and so is reactive by default. You can learn more about it on the [RmlUI website] and [differences in the Recoil version here](#differences-between-upstream-rmlui-and-rmlui-in-recoil).
RmlUi is a UI framework that is defined using a HTML/CSS style workflow (using Lua instead of JS) intended to simplify UI development especially for those already familiar with web development. It is designed for interactive applications, and so is reactive by default. You can learn more about it on the [RmlUi website] and [differences in the Recoil version here](#differences-between-upstream-rmlui-and-rmlui-in-recoil).

## How does RmlUI Work?
## How does RmlUi Work?

To get started, it's important to learn a few key concepts.
- Context: This is a bundle of documents and data models.
Expand Down Expand Up @@ -416,7 +416,7 @@ document = widget.rmlContext:LoadDocument("document.rml", document_table)
- The Beyond All Reason devs prefer to use one shared context for all rmlui widgets.


### Differences between upstream RmlUI and RmlUI in Recoil
### Differences between upstream RmlUi and RmlUi in Recoil

- The SVG element allows either a filepath or raw SVG data in the src attribute, allowing for inline svg to be used (this may change to svg being supported between the opening and closing tag when implemented upstream)
- An additional element ```<texture>``` is available which allows for textures loaded in Recoil to be used, this behaves the same as an ```<img>``` element except the src attribute takes a [texture reference]({{% ref "articles/texture-reference-strings" %}})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Before we get to Widgets and Gadgets we will start with an overview of some key
- Synced mode is the environment that affects game simulation e.g ordering units around. Synced commands are distributed and run by all players in the game to ensure the simulation remains synced.
- Unsynced mode is the players own environment, functionality here could for example enhance controls, display helpful information.

When in Unsynced mode LuaIntro, LuaUi, LuaRules and LuaGaia provide read access to synced but only LuaRules and LuaGaia have full access to simulation information (all players units etc.). In LuaIntro and LuaUi read access to synced is scoped to just what that player can see i.e. observing LoS & radar ranges.
When in Unsynced mode LuaIntro, LuaUI, LuaRules and LuaGaia provide read access to synced but only LuaRules and LuaGaia have full access to simulation information (all players units etc.). In LuaIntro and LuaUI read access to synced is scoped to just what that player can see i.e. observing LoS & radar ranges.

### Key Areas
- LuaRules - Generally home to lower level customisations that affect unit behavior or overall game operation
Expand All @@ -29,7 +29,7 @@ Widgets and Gadgets are concepts that have been adopted by several games using R

Gadgets typically being lower level game logic, unit behaviour functionality that defines your game and should be present for all players, they are typically only found in LuaRules and LuaGaia and are often included using VFS.ZIP_ONLY so as not to be easily overridden by end users (your packaged version takes priority).

Widgets usually involve improving UX or showing helpful UI interfaces, and are often considered things that users can turn on/off in the game to suit their needs, be it through settings or a widget manager UI. They are usually specific to LuaIntro, LuaMenu and LuaUi.
Widgets usually involve improving UX or showing helpful UI interfaces, and are often considered things that users can turn on/off in the game to suit their needs, be it through settings or a widget manager UI. They are usually specific to LuaIntro, LuaMenu and LuaUI.

To manage the invocation of Widgets & Gadgets a "**handler**" is setup in the Lua entrypoint. For environments with synced and unsyned entry points these typically use the same handler which calls the same widgets/gadgets but use a function the he handler like IsSyncedCode to check if they are being run in synced mode or unsynced mode and running the appropriate section of code.

Expand Down Expand Up @@ -85,7 +85,7 @@ end
```

## Handlers
Handlers are the code that runs in the entry point to load in addons/widgets/gadgets and distribute callins to them, and example implementation of a handler is included in the [Recoil base content](https://github.com/beyond-all-reason/RecoilEngine/blob/master/cont/base/springcontent/LuaHandler/handler.lua) for LuaIntro, LuaRules and LuaUi, and will likely do well for a simple game, although many games eventually choose to make their own handlers. This means for LuaIntro and LuaUi you can start creating widgets without worrying about handlers in the luaintro/widgets or luaui/widgets folders, and for creating gadgets for LuaRules in luarules/gadgets folder.
Handlers are the code that runs in the entry point to load in addons/widgets/gadgets and distribute callins to them, and example implementation of a handler is included in the [Recoil base content](https://github.com/beyond-all-reason/RecoilEngine/blob/master/cont/base/springcontent/LuaHandler/handler.lua) for LuaIntro, LuaRules and LuaUI, and will likely do well for a simple game, although many games eventually choose to make their own handlers. This means for LuaIntro and LuaUI you can start creating widgets without worrying about handlers in the luaintro/widgets or luaui/widgets folders, and for creating gadgets for LuaRules in luarules/gadgets folder.

Below is a very simplified pseudocode example of a handler is below to illustrate adding a gadget and forwarding callins to gadgets.
```lua
Expand Down
26 changes: 26 additions & 0 deletions rts/Lua/LuaHandle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
#include "Sim/Units/UnitDef.h"
#include "Sim/Weapons/Weapon.h"
#include "Sim/Weapons/WeaponDef.h"
#include "System/FileSystem/FileHandler.h"
#include "System/FileSystem/VFSModes.h"
#include "System/creg/SerializeLuaState.h"
#include "System/Config/ConfigHandler.h"
#include "System/EventHandler.h"
Expand All @@ -56,6 +58,8 @@

#include "LuaInclude.h"

#include "lib/luasocket/src/luasocket.h"

#include <SDL_keyboard.h>
#include <SDL_keycode.h>
#include <SDL_mouse.h>
Expand Down Expand Up @@ -549,6 +553,28 @@ bool CLuaHandle::LoadCode(lua_State* L, std::string code, const string& debug)
}


void CLuaHandle::InitLuaSocket(lua_State* L)
{
RECOIL_DETAILED_TRACY_ZONE;

const std::string filename = "LuaSocket/socket.lua";
CFileHandler f(filename, SPRING_VFS_BASE);
if (!f.FileExists()) {
LOG_L(L_ERROR, "Error loading %s (file does not exist)", filename.c_str());
return;
}

LUA_OPEN_LIB(L, luaopen_socket_core);

std::string code;
if (f.LoadStringData(code)) {
LoadCode(L, std::move(code), filename);
} else {
LOG_L(L_ERROR, "Error loading %s", filename.c_str());
}
}


int CLuaHandle::LoadStringData(lua_State* L)
{
RECOIL_DETAILED_TRACY_ZONE;
Expand Down
1 change: 1 addition & 0 deletions rts/Lua/LuaHandle.h
Original file line number Diff line number Diff line change
Expand Up @@ -329,6 +329,7 @@ class CLuaHandle : public CEventClient
bool AddBasicCalls(lua_State* L);
bool AddCommonModules(lua_State* L);
bool LoadCode(lua_State* L, std::string code, const std::string& debug);
void InitLuaSocket(lua_State* L);
static bool AddEntriesToTable(lua_State* L, const char* name, bool (*entriesFunc)(lua_State*));

/// returns error code and sets traceback on error
Expand Down
17 changes: 0 additions & 17 deletions rts/Lua/LuaMenu.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
#include "System/FileSystem/FileHandler.h"
#include "System/FileSystem/FileSystem.h"
#include "System/Threading/SpringThreading.h"
#include "lib/luasocket/src/luasocket.h"
#include "LuaUI.h"

#include "System/Misc/TracyDefs.h"
Expand Down Expand Up @@ -134,22 +133,6 @@ string CLuaMenu::LoadFile(const string& name) const
}


void CLuaMenu::InitLuaSocket(lua_State* L) {
RECOIL_DETAILED_TRACY_ZONE;
std::string code;
std::string filename = "socket.lua";
CFileHandler f(filename);

LUA_OPEN_LIB(L, luaopen_socket_core);

if (f.LoadStringData(code)) {
LoadCode(L, std::move(code), filename);
} else {
LOG_L(L_ERROR, "Error loading %s", filename.c_str());
}
}


bool CLuaMenu::RemoveSomeOpenGLFunctions(lua_State* L)
{
// remove some spring opengl functions that don't work preloading
Expand Down
1 change: 0 additions & 1 deletion rts/Lua/LuaMenu.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ class CLuaMenu : public CLuaHandle
static bool LoadUnsyncedReadFunctions(lua_State* L);
static bool RemoveSomeOpenGLFunctions(lua_State* L);
static bool PushGameVersion(lua_State* L);
void InitLuaSocket(lua_State* L);
protected:
QueuedAction queuedAction;
};
Expand Down
20 changes: 0 additions & 20 deletions rts/Lua/LuaUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
#include "System/Config/ConfigHandler.h"
#include "System/StringUtil.h"
#include "System/Threading/SpringThreading.h"
#include "lib/luasocket/src/luasocket.h"

#include <cctype>

Expand Down Expand Up @@ -207,25 +206,6 @@ GetWatchDef(Explosion)
SetWatchDef(Explosion)


void CLuaUI::InitLuaSocket(lua_State* L) {
std::string code;
std::string filename = "LuaSocket/socket.lua";
CFileHandler f(filename, SPRING_VFS_BASE);

if (!f.FileExists()) {
LOG_L(L_ERROR, "Error loading %s (file does not exist)", filename.c_str());
return;
}

LUA_OPEN_LIB(L, luaopen_socket_core);

if (f.LoadStringData(code)) {
LoadCode(L, std::move(code), filename);
} else {
LOG_L(L_ERROR, "Error loading %s", filename.c_str());
}
}

string CLuaUI::LoadFile(const string& name, const std::string& mode) const
{
CFileHandler f(name, mode);
Expand Down
1 change: 0 additions & 1 deletion rts/Lua/LuaUI.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,6 @@ class CLuaUI : public CLuaHandle
string LoadFile(const string& name, const std::string& mode) const;

bool LoadCFunctions(lua_State* L);
void InitLuaSocket(lua_State* L);

bool BuildCmdDescTable(lua_State* L, const vector<SCommandDescription>& cmds);
bool GetLuaIntMap(lua_State* L, int index, spring::unordered_map<int, int>& intList);
Expand Down
Loading