Implemented basis for Lua scripting and registering FSX variables - incomplete and crashes on shutdown

This commit is contained in:
Mark van Renswoude 2017-05-28 23:51:57 +02:00
parent b0613d6f5b
commit 54e7e36ee9
17 changed files with 3836 additions and 84 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
__history
*.local
*.dcu
*.exe
*.identcache

Binary file not shown.

View File

@ -0,0 +1,767 @@
{
Header for Lua 5.2.1 Binaries DLL
http://luabinaries.sourceforge.net/
Delphi conversion by M. van Renswoude, April 2014:
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source
distribution.
}
unit Lua.API;
interface
uses
System.SysUtils;
const
LUA_VERSION_MAJOR = '5';
LUA_VERSION_MINOR = '2';
LUA_VERSION_NUM = 502;
LUA_VERSION_RELEASE = '1';
LUA_VERSION_ = 'Lua ' + LUA_VERSION_MAJOR + '.' + LUA_VERSION_MINOR;
LUA_RELEASE = LUA_VERSION_ + '.' + LUA_VERSION_RELEASE;
LUA_COPYRIGHT = LUA_RELEASE + ' Copyright (C) 1994-2012 Lua.org, PUC-Rio';
LUA_AUTHORS = 'R. Ierusalimschy, L. H. de Figueiredo, W. Celes';
{ mark for precompiled code ('<esc>Lua') }
LUA_SIGNATURE = #33'Lua';
{ option for multiple returns in 'lua_pcall' and 'lua_call' }
LUA_MULTRET = -1;
{ reserve some space for error handling }
LUAI_MAXSTACK = 1000000;
LUAI_FIRSTPSEUDOIDX = (-LUAI_MAXSTACK - 1000);
{ pseudo-indices }
LUA_REGISTRYINDEX = LUAI_FIRSTPSEUDOIDX;
function lua_upvalueindex(idx: Integer): Integer; inline;
const
{ thread status }
LUA_OK = 0;
LUA_YIELD_ = 1;
LUA_ERRRUN = 2;
LUA_ERRSYNTAX = 3;
LUA_ERRMEM = 4;
LUA_ERRGCMM = 5;
LUA_ERRERR = 6;
type
size_t = NativeUint;
psize_t = ^size_t;
lua_State = type Pointer;
lua_CFunction = function(L: lua_State): Integer; cdecl;
{ functions that read/write blocks when loading/dumping Lua chunks }
lua_Reader = function(L: lua_State; ud: Pointer; var sz: size_t): PAnsiChar; cdecl;
lua_Writer = function(L: lua_State; p: Pointer; sz: size_t; ud: Pointer): Integer; cdecl;
{ prototype for memory-allocation functions }
lua_Alloc = function(ud, ptr: Pointer; osize, nsize: size_t): Pointer; cdecl;
const
{ basic types }
LUA_TNONE = (-1);
LUA_TNIL = 0;
LUA_TBOOLEAN = 1;
LUA_TLIGHTUSERDATA = 2;
LUA_TNUMBER = 3;
LUA_TSTRING = 4;
LUA_TTABLE = 5;
LUA_TFUNCTION = 6;
LUA_TUSERDATA = 7;
LUA_TTHREAD = 8;
LUA_NUMTAGS = 9;
{ minimum Lua stack available to a C function }
LUA_MINSTACK = 20;
{ predefined values in the registry }
LUA_RIDX_MAINTHREAD = 1;
LUA_RIDX_GLOBALS = 2;
LUA_RIDX_LAST = LUA_RIDX_GLOBALS;
type
{ type of numbers in Lua }
lua_Number = type Double;
{ type for integer functions }
lua_Integer = type Integer;
{ unsigned integer type }
lua_Unsigned = type Cardinal;
var
{ state manipulation }
lua_newstate: function(f: lua_Alloc; ud: Pointer): lua_State; cdecl;
lua_close: procedure(L: lua_State); cdecl;
lua_newthread: function(L: lua_State): lua_State; cdecl;
lua_atpanic: function(L: lua_State; panicf: lua_CFunction): lua_CFunction; cdecl;
lua_version: function(L: lua_State): lua_Number; cdecl;
{ basic stack manipulation }
lua_absindex: function(L: lua_State; idx: Integer): Integer; cdecl;
lua_gettop: function(L: lua_State): Integer; cdecl;
lua_settop: procedure(L: lua_State; idx: Integer); cdecl;
lua_pushvalue: procedure(L: lua_State; idx: Integer); cdecl;
lua_remove: procedure(L: lua_State; idx: Integer); cdecl;
lua_insert: procedure(L: lua_State; idx: Integer); cdecl;
lua_replace: procedure(L: lua_State; idx: Integer); cdecl;
lua_copy: procedure(L: lua_State; fromidx, toidx: Integer); cdecl;
lua_checkstack: function(L: lua_State; sz: Integer): Integer; cdecl;
lua_xmove: procedure(from: lua_State; _to: lua_State; n: Integer); cdecl;
{ access functions (stack -> C) }
lua_isnumber: function (L: lua_State; idx: Integer): Integer; cdecl;
lua_isstring: function (L: lua_State; idx: Integer): Integer; cdecl;
lua_iscfunction: function (L: lua_State; idx: Integer): Integer; cdecl;
lua_isuserdata: function (L: lua_State; idx: Integer): Integer; cdecl;
lua_type: function (L: lua_State; idx: Integer): Integer; cdecl;
lua_typename: function (L: lua_State; tp: Integer): PAnsiChar; cdecl;
lua_tonumberx: function (L: lua_State; idx: Integer; isnum: PInteger): lua_Number; cdecl;
lua_tointegerx: function (L: lua_State; idx: Integer; isnum: PInteger): lua_Integer; cdecl;
lua_tounsignedx: function (L: lua_State; idx: Integer; isnum: PInteger): lua_Unsigned; cdecl;
lua_toboolean: function (L: lua_State; idx: Integer): Integer; cdecl;
lua_tolstring: function(L: lua_State; idx: Integer; len: psize_t): PAnsiChar; cdecl;
lua_rawlen: function (L: lua_State; idx: Integer): size_t; cdecl;
lua_tocfunction: function (L: lua_State; idx: Integer): lua_CFunction; cdecl;
lua_touserdata: function (L: lua_State; idx: Integer): Pointer; cdecl;
lua_tothread: function (L: lua_State; idx: Integer): lua_State; cdecl;
lua_topointer: function (L: lua_State; idx: Integer): Pointer; cdecl;
const
{ Comparison and arithmetic functions }
LUA_OPADD = 0; { ORDER TM }
LUA_OPSUB = 1;
LUA_OPMUL = 2;
LUA_OPDIV = 3;
LUA_OPMOD = 4;
LUA_OPPOW = 5;
LUA_OPUNM = 6;
var
lua_arith: procedure(L: lua_State; op: Integer); cdecl;
const
LUA_OPEQ = 0;
LUA_OPLT = 1;
LUA_OPLE = 2;
var
lua_rawequal: function(L: lua_State; idx1, idx2: Integer): Integer; cdecl;
lua_compare: function(L: lua_State; idx1, idx2, op: Integer): Integer; cdecl;
{ push functions (C -> stack) }
lua_pushnil: procedure(L: lua_State); cdecl;
lua_pushnumber: procedure(L: lua_State; n: lua_Number); cdecl;
lua_pushinteger: procedure(L: lua_State; n: lua_Integer); cdecl;
lua_pushunsigned: procedure(L: lua_State; n: lua_Unsigned); cdecl;
lua_pushlstring: function (L: lua_State; s: PAnsiChar; l_: size_t): PAnsiChar; cdecl;
lua_pushstring: function (L: lua_State; s: PAnsiChar): PAnsiChar; cdecl;
lua_pushvfstring: function (L: lua_State; fmt: PAnsiChar; argp: Pointer): PAnsiChar; cdecl;
lua_pushfstring: function (L: lua_State; fmt: PAnsiChar; argp: Pointer): PAnsiChar; cdecl;
lua_pushcclosure: procedure(L: lua_State; fn: lua_CFunction; n: Integer); cdecl;
lua_pushboolean: procedure(L: lua_State; b: Integer); cdecl;
lua_pushlightuserdata: procedure(L: lua_State; p: Pointer); cdecl;
lua_pushthread: function (L: lua_State): Integer; cdecl;
{ get functions (Lua -> stack) }
lua_getglobal: procedure(L: lua_State; value: PAnsiChar); cdecl;
lua_gettable: procedure(L: lua_State; idx: Integer); cdecl;
lua_getfield: procedure(L: lua_State; idx: Integer; k: PAnsiChar); cdecl;
lua_rawget: procedure(L: lua_State; idx: Integer); cdecl;
lua_rawgeti: procedure(L: lua_State; idx, n: Integer); cdecl;
lua_rawgetp: procedure(L: lua_State; idx: Integer; p: Pointer); cdecl;
lua_createtable: procedure(L: lua_State; narr: Integer; nrec: Integer); cdecl;
lua_newuserdata: procedure(L: lua_State; sz: size_t); cdecl;
lua_getmetatable: function(L: lua_State; objindex: Integer): Integer; cdecl;
lua_getuservalue: procedure(L: lua_State; idx: Integer); cdecl;
{ set functions (stack -> Lua) }
lua_setglobal: procedure(L: lua_State; value: PAnsiChar); cdecl;
lua_settable: procedure(L: lua_State; idx: Integer); cdecl;
lua_setfield: procedure(L: lua_State; idx: Integer; k: PAnsiChar); cdecl;
lua_rawset: procedure(L: lua_State; idx: Integer); cdecl;
lua_rawseti: procedure(L: lua_State; idx, n: Integer); cdecl;
lua_rawsetp: procedure(L: lua_State; idx: Integer; p: Pointer); cdecl;
lua_setmetatable: function(L: lua_State; objindex: Integer): Integer; cdecl;
lua_setuservalue: procedure(L: lua_State; idx: Integer); cdecl;
{ 'load' and 'call' functions (load and run Lua code) }
lua_callk: procedure(L: lua_State; nargs, nresults, ctx: Integer; k: lua_CFunction); cdecl;
lua_getctx: function(L: lua_State; var ctx: Integer): Integer; cdecl;
lua_pcallk: function(L: lua_State; nargs, nresults, errfunc, ctx: Integer; k: lua_CFunction): Integer; cdecl;
lua_load: function(L: lua_State; reader: lua_Reader; dt: Pointer; chunkname, mode: PAnsiChar): Integer; cdecl;
lua_dump: function(L: lua_State; writer: lua_Writer; data: Pointer): Integer; cdecl;
procedure lua_call(L: lua_State; nargs, nresults: Integer); inline;
function lua_pcall(L: lua_State; nargs, nresults, errfunc: Integer): Integer; inline;
var
{ coroutine functions }
lua_yieldk: function(L: lua_State; nresults, ctx: Integer; k: lua_CFunction): Integer; cdecl;
lua_resume: function(L, from: lua_State; nargs: Integer): Integer; cdecl;
lua_status: function(L: lua_State): Integer; cdecl;
function lua_yield(L: lua_State; nresults: Integer): Integer; inline;
const
{ garbage-collection function and options }
LUA_GCSTOP = 0;
LUA_GCRESTART = 1;
LUA_GCCOLLECT = 2;
LUA_GCCOUNT = 3;
LUA_GCCOUNTB = 4;
LUA_GCSTEP = 5;
LUA_GCSETPAUSE = 6;
LUA_GCSETSTEPMU = 7;
LUA_GCSETMAJORIN = 8;
LUA_GCISRUNNING = 9;
LUA_GCGEN = 0;
LUA_GCINC = 1;
var
lua_gc: function(L: lua_State; what, data: Integer): Integer; cdecl;
var
{ miscellaneous functions }
lua_error: function(L: lua_State): Integer; cdecl;
lua_next: function(L: lua_State; idx: Integer): Integer; cdecl;
lua_concat: procedure(L: lua_State; n: Integer); cdecl;
lua_len: procedure(L: lua_State; idx: Integer); cdecl;
lua_getallocf: function(L: lua_State; ud: Pointer): lua_Alloc; cdecl;
lua_setallocf: procedure(L: lua_State; f: lua_Alloc; ud: Pointer); cdecl;
{ some useful macros }
function lua_tonumber(L: lua_State; idx: Integer): lua_Number; inline;
function lua_tointeger(L: lua_State; idx: Integer): lua_Integer; inline;
function lua_tounsigned(L: lua_State; idx: Integer): lua_Unsigned; inline;
procedure lua_pop(L: lua_State; n: Integer); inline;
procedure lua_newtable(L: lua_State); inline;
procedure lua_register(L: lua_State; name: PAnsiChar; f: lua_CFunction); inline;
procedure lua_pushcfunction(L: lua_State; f: lua_CFunction); inline;
function lua_isfunction(L: lua_State; n: Integer): Boolean; inline;
function lua_istable(L: lua_State; n: Integer): Boolean; inline;
function lua_islightuserdata(L: lua_State; n: Integer): Boolean; inline;
function lua_isnil(L: lua_State; n: Integer): Boolean; inline;
function lua_isboolean(L: lua_State; n: Integer): Boolean; inline;
function lua_isthread(L: lua_State; n: Integer): Boolean; inline;
function lua_isnone(L: lua_State; n: Integer): Boolean; inline;
function lua_isnoneornil(L: lua_State; n: Integer): Boolean; inline;
function lua_pushliteral(L: lua_State; const s: AnsiString): PAnsiChar; inline;
procedure lua_pushglobaltable(L: lua_State); inline;
function lua_tostring(L: lua_State; idx: Integer): PAnsiChar; inline;
const
{======================================================================
Debug API
=======================================================================}
{ Event codes }
LUA_HOOKCALL = 0;
LUA_HOOKRET = 1;
LUA_HOOKLINE = 2;
LUA_HOOKCOUNT = 3;
LUA_HOOKTAILCALL = 4;
{ Event masks }
LUA_MASKCALL = (1 shl LUA_HOOKCALL);
LUA_MASKRET = (1 shl LUA_HOOKRET);
LUA_MASKLINE = (1 shl LUA_HOOKLINE);
LUA_MASKCOUNT = (1 shl LUA_HOOKCOUNT);
const
LUA_IDSIZE = 60;
type
lua_Debug = record
event: Integer;
name: PAnsiChar;
namewhat: PAnsiChar; // 'global', 'local', 'field', 'method'
what: PAnsiChar; // 'Lua', 'C', 'main', 'tail'
source: PAnsiChar;
currentline: Integer;
linedefined: Integer;
lastlinedefined: Integer;
nups: Byte;
nparams: Byte;
isvararg: Byte;
istailcall: Byte;
short_src: array[0..LUA_IDSIZE - 1] of AnsiChar;
//struct CallInfo *i_ci; /* active function */
end;
{ Functions to be called by the debugger in specific events }
lua_Hook = procedure(L: lua_State; var ar: lua_Debug); cdecl;
var
lua_getstack: function(L: lua_State; level: Integer; var ar: lua_Debug): Integer; cdecl;
lua_getinfo: function(L: lua_State; what: PAnsiChar; var ar: lua_Debug): Integer; cdecl;
lua_getlocal: function(L: lua_State; var ar: lua_Debug; n: Integer): PAnsiChar; cdecl;
lua_setlocal: function(L: lua_State; var ar: lua_Debug; n: Integer): PAnsiChar; cdecl;
lua_getupvalue: function(L: lua_State; funcindex, n: Integer): PAnsiChar; cdecl;
lua_setupvalue: function(L: lua_State; funcindex, n: Integer): PAnsiChar; cdecl;
lua_upvalueid: function(L: lua_State; fidx, n: Integer): Pointer; cdecl;
lua_upvaluejoin: procedure(L: lua_State; fidx1, n1, fidx2, n2: Integer);
lua_sethook: function(L: lua_State; func: lua_Hook; mask, count: Integer): Integer; cdecl;
lua_gethook: function(L: lua_State): lua_Hook; cdecl;
lua_gethookmask: function(L: lua_State): Integer; cdecl;
lua_gethookcount: function(L: lua_State): Integer; cdecl;
{====================================================================== }
const
LUA_COLIBNAME = 'coroutine';
LUA_TABLIBNAME = 'table';
LUA_IOLIBNAME = 'io';
LUA_OSLIBNAME = 'os';
LUA_STRLIBNAME = 'string';
LUA_BITLIBNAME = 'bit32';
LUA_MATHLIBNAME = 'math';
LUA_DBLIBNAME = 'debug';
LUA_LOADLIBNAME = 'package';
var
{ lualib }
luaopen_base: function(L: lua_State): Integer; cdecl;
luaopen_coroutine: function(L: lua_State): Integer; cdecl;
luaopen_table: function(L: lua_State): Integer; cdecl;
luaopen_io: function(L: lua_State): Integer; cdecl;
luaopen_os: function(L: lua_State): Integer; cdecl;
luaopen_string: function(L: lua_State): Integer; cdecl;
luaopen_bit32: function(L: lua_State): Integer; cdecl;
luaopen_math: function(L: lua_State): Integer; cdecl;
luaopen_debug: function(L: lua_State): Integer; cdecl;
luaopen_package: function(L: lua_State): Integer; cdecl;
{ open all previous libraries }
luaL_openlibs: procedure(L: lua_State); cdecl;
luaL_requiref: procedure(L: lua_State; modname: PAnsiChar; openf: lua_CFunction; glb: Integer); cdecl;
type
luaL_Reg = record
name: PAnsiChar;
func: lua_CFunction;
end;
PluaL_Reg = ^luaL_Reg;
var
luaL_setfuncs: procedure(L: lua_State; luaL_Reg: PluaL_Reg; nup: Integer); cdecl;
procedure luaL_where(L: lua_State; level: Integer);
function luaL_error(L: lua_State; fmt: PAnsiChar; argp: Pointer): Integer;
const
DefaultLuaLibName = 'lua' + LUA_VERSION_MAJOR + LUA_VERSION_MINOR + '.dll';
procedure LoadLuaLib(const AFileName: string = DefaultLuaLibName);
procedure UnloadLuaLib;
function LuaLibLoaded: Boolean;
function DefaultLuaAlloc(ud, ptr: Pointer; osize, nsize: size_t): Pointer; cdecl;
implementation
uses
System.Generics.Collections,
Winapi.Windows;
var
LuaLibHandle: THandle;
LuaFunctions: TList<PPointer>;
function DefaultLuaAlloc(ud, ptr: Pointer; osize, nsize: size_t): Pointer;
begin
if (nsize = 0) then
begin
FreeMemory(ptr);
Result := nil;
end else
Result := ReallocMemory(ptr, nsize);
end;
procedure LoadLuaLib(const AFileName: string = DefaultLuaLibName);
procedure Load(var AVariable: Pointer; const AName: string);
begin
AVariable := GetProcAddress(LuaLibHandle, PChar(AName));
LuaFunctions.Add(@AVariable);
end;
begin
UnloadLuaLib;
LuaLibHandle := SafeLoadLibrary(AFileName);
if LuaLibHandle = 0 then
RaiseLastOSError;
if not Assigned(LuaFunctions) then
LuaFunctions := TList<PPointer>.Create();
Load(@lua_newstate, 'lua_newstate');
Load(@lua_close, 'lua_close');
Load(@lua_newthread, 'lua_newthread');
Load(@lua_atpanic, 'lua_atpanic');
Load(@lua_version, 'lua_version');
Load(@lua_absindex, 'lua_absindex');
Load(@lua_gettop, 'lua_gettop');
Load(@lua_settop, 'lua_settop');
Load(@lua_pushvalue, 'lua_pushvalue');
Load(@lua_remove, 'lua_remove');
Load(@lua_insert, 'lua_insert');
Load(@lua_replace, 'lua_replace');
Load(@lua_copy, 'lua_copy');
Load(@lua_checkstack, 'lua_checkstack');
Load(@lua_xmove, 'lua_xmove');
Load(@lua_isnumber, 'lua_isnumber');
Load(@lua_isstring, 'lua_isstring');
Load(@lua_iscfunction, 'lua_iscfunction');
Load(@lua_isuserdata, 'lua_isuserdata');
Load(@lua_type, 'lua_type');
Load(@lua_typename, 'lua_typename');
Load(@lua_tonumberx, 'lua_tonumberx');
Load(@lua_tointegerx, 'lua_tointegerx');
Load(@lua_tounsignedx, 'lua_tounsignedx');
Load(@lua_toboolean, 'lua_toboolean');
Load(@lua_tolstring, 'lua_tolstring');
Load(@lua_rawlen, 'lua_rawlen');
Load(@lua_tocfunction, 'lua_tocfunction');
Load(@lua_touserdata, 'lua_touserdata');
Load(@lua_tothread, 'lua_tothread');
Load(@lua_topointer, 'lua_topointer');
Load(@lua_arith, 'lua_arith');
Load(@lua_rawequal, 'lua_rawequal');
Load(@lua_compare, 'lua_compare');
Load(@lua_pushnil, 'lua_pushnil');
Load(@lua_pushnumber, 'lua_pushnumber');
Load(@lua_pushinteger, 'lua_pushinteger');
Load(@lua_pushunsigned, 'lua_pushunsigned');
Load(@lua_pushlstring, 'lua_pushlstring');
Load(@lua_pushstring, 'lua_pushstring');
Load(@lua_pushvfstring, 'lua_pushvfstring');
Load(@lua_pushfstring, 'lua_pushfstring');
Load(@lua_pushcclosure, 'lua_pushcclosure');
Load(@lua_pushboolean, 'lua_pushboolean');
Load(@lua_pushlightuserdata, 'lua_pushlightuserdata');
Load(@lua_pushthread, 'lua_pushthread');
Load(@lua_getglobal, 'lua_getglobal');
Load(@lua_gettable, 'lua_gettable');
Load(@lua_getfield, 'lua_getfield');
Load(@lua_rawget, 'lua_rawget');
Load(@lua_rawgeti, 'lua_rawgeti');
Load(@lua_rawgetp, 'lua_rawgetp');
Load(@lua_newuserdata, 'lua_newuserdata');
Load(@lua_getmetatable, 'lua_getmetatable');
Load(@lua_getuservalue, 'lua_getuservalue');
Load(@lua_createtable, 'lua_createtable');
Load(@lua_setglobal, 'lua_setglobal');
Load(@lua_settable, 'lua_settable');
Load(@lua_setfield, 'lua_setfield');
Load(@lua_rawset, 'lua_rawset');
Load(@lua_rawseti, 'lua_rawseti');
Load(@lua_rawsetp, 'lua_rawsetp');
Load(@lua_setmetatable, 'lua_setmetatable');
Load(@lua_setuservalue, 'lua_setuservalue');
Load(@lua_callk, 'lua_callk');
Load(@lua_getctx, 'lua_getctx');
Load(@lua_pcallk, 'lua_pcallk');
Load(@lua_yieldk, 'lua_yieldk');
Load(@lua_resume, 'lua_resume');
Load(@lua_status, 'lua_status');
Load(@lua_gc, 'lua_gc');
Load(@lua_load, 'lua_load');
Load(@lua_dump, 'lua_dump');
Load(@lua_error, 'lua_error');
Load(@lua_next, 'lua_next');
Load(@lua_concat, 'lua_concat');
Load(@lua_len, 'lua_len');
Load(@lua_getallocf, 'lua_getallocf');
Load(@lua_setallocf, 'lua_setallocf');
Load(@lua_getstack, 'lua_getstack');
Load(@lua_getinfo, 'lua_getinfo');
Load(@lua_getlocal, 'lua_getlocal');
Load(@lua_setlocal, 'lua_setlocal');
Load(@lua_getupvalue, 'lua_getupvalue');
Load(@lua_setupvalue, 'lua_setupvalue');
Load(@lua_upvalueid, 'lua_upvalueid');
Load(@lua_upvaluejoin, 'lua_upvaluejoin');
Load(@lua_sethook, 'lua_sethook');
Load(@lua_gethook, 'lua_gethook');
Load(@lua_gethookmask, 'lua_gethookmask');
Load(@lua_gethookcount, 'lua_gethookcount');
Load(@luaopen_base, 'luaopen_base');
Load(@luaopen_coroutine, 'luaopen_coroutine');
Load(@luaopen_table, 'luaopen_table');
Load(@luaopen_io, 'luaopen_io');
Load(@luaopen_os, 'luaopen_os');
Load(@luaopen_string, 'luaopen_string');
Load(@luaopen_bit32, 'luaopen_bit32');
Load(@luaopen_math, 'luaopen_math');
Load(@luaopen_debug, 'luaopen_debug');
Load(@luaopen_package, 'luaopen_package');
Load(@luaL_openlibs, 'luaL_openlibs');
Load(@luaL_requiref, 'luaL_requiref');
Load(@luaL_setfuncs, 'luaL_setfuncs');
end;
procedure UnloadLuaLib;
var
variable: PPointer;
begin
if Assigned(LuaFunctions) then
begin
for variable in LuaFunctions do
variable^ := nil;
end;
if LuaLibLoaded then
begin
FreeLibrary(LuaLibHandle);
LuaLibHandle := 0;
end;
end;
function LuaLibLoaded: Boolean;
begin
Result := (LuaLibHandle <> 0);
end;
{ Macros }
function lua_upvalueindex(idx: Integer): Integer;
begin
Result := (LUA_REGISTRYINDEX - idx);
end;
procedure lua_call(L: lua_State; nargs, nresults: Integer);
begin
lua_callk(L, nargs, nresults, 0, nil);
end;
function lua_pcall(L: lua_State; nargs, nresults, errfunc: Integer): Integer;
begin
Result := lua_pcallk(L, nargs, nresults, errfunc, 0, nil);
end;
function lua_yield(L: lua_State; nresults: Integer): Integer;
begin
Result := lua_yieldk(L, nresults, 0, nil);
end;
function lua_tonumber(L: lua_State; idx: Integer): lua_Number;
begin
Result := lua_tonumberx(L, idx, nil);
end;
function lua_tointeger(L: lua_State; idx: Integer): lua_Integer;
begin
Result := lua_tointegerx(L, idx, nil);
end;
function lua_tounsigned(L: lua_State; idx: Integer): lua_Unsigned;
begin
Result := lua_tounsignedx(L, idx, nil);
end;
procedure lua_pop(L: lua_State; n: Integer);
begin
lua_settop(L, -(n) - 1);
end;
procedure lua_newtable(L: lua_State); inline;
begin
lua_createtable(L, 0, 0);
end;
procedure lua_register(L: lua_State; name: PAnsiChar; f: lua_CFunction); inline;
begin
lua_pushcfunction(L, f);
lua_setglobal(L, name);
end;
procedure lua_pushcfunction(L: lua_State; f: lua_CFunction);
begin
lua_pushcclosure(L, f, 0);
end;
function lua_isfunction(L: lua_State; n: Integer): Boolean;
begin
Result := lua_type(L, n) = LUA_TFUNCTION;
end;
function lua_istable(L: lua_State; n: Integer): Boolean;
begin
Result := lua_type(L, n) = LUA_TTABLE;
end;
function lua_islightuserdata(L: lua_State; n: Integer): Boolean;
begin
Result := lua_type(L, n) = LUA_TLIGHTUSERDATA;
end;
function lua_isnil(L: lua_State; n: Integer): Boolean;
begin
Result := lua_type(L, n) = LUA_TNIL;
end;
function lua_isboolean(L: lua_State; n: Integer): Boolean;
begin
Result := lua_type(L, n) = LUA_TBOOLEAN;
end;
function lua_isthread(L: lua_State; n: Integer): Boolean;
begin
Result := lua_type(L, n) = LUA_TTHREAD;
end;
function lua_isnone(L: lua_State; n: Integer): Boolean;
begin
Result := lua_type(L, n) = LUA_TNONE;
end;
function lua_isnoneornil(L: lua_State; n: Integer): Boolean;
begin
Result := lua_type(L, n) <= 0;
end;
function lua_pushliteral(L: lua_State; const s: AnsiString): PAnsiChar;
begin
Result := lua_pushlstring(L, PAnsiChar(s), Length(s));
end;
procedure lua_pushglobaltable(L: lua_State);
begin
lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);
end;
function lua_tostring(L: lua_State; idx: Integer): PAnsiChar;
begin
Result := lua_tolstring(L, idx, nil);
end;
procedure luaL_where(L: lua_State; level: Integer);
var
ar: lua_Debug;
msg: AnsiString;
begin
if (lua_getstack(L, level, ar) <> 0) then // check function at level
begin
lua_getinfo(L, 'Sl', ar); // get info about it
if (ar.currentline > 0) then // is there info?
begin
msg := AnsiString(Format('%s:%d: ', [ar.short_src, ar.currentline]));
lua_pushlstring(L, PAnsiChar(msg), Length(msg));
exit
end;
end;
lua_pushliteral(L, ''); // else, no information available...
end;
function luaL_error(L: lua_State; fmt: PAnsiChar; argp: Pointer): Integer;
begin
luaL_where(L, 1);
lua_pushvfstring(L, fmt, argp);
lua_concat(L, 2);
Result := lua_error(L);
end;
initialization
finalization
UnloadLuaLib;
FreeAndNil(LuaFunctions);
end.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1 @@
Source: https://git.x2software.net/delphi/delphilua

View File

@ -375,6 +375,10 @@ object MainForm: TMainForm
object tsConfiguration: TTabSheet
Caption = ' Configuration '
ImageIndex = 2
ExplicitLeft = 0
ExplicitTop = 0
ExplicitWidth = 0
ExplicitHeight = 0
DesignSize = (
442
452)
@ -529,6 +533,10 @@ object MainForm: TMainForm
object tsAbout: TTabSheet
Caption = 'About'
ImageIndex = 1
ExplicitLeft = 0
ExplicitTop = 0
ExplicitWidth = 0
ExplicitHeight = 0
object lblVersionCaption: TLabel
Left = 16
Top = 67

View File

@ -225,6 +225,7 @@ type
implementation
uses
System.SysUtils,
System.Types,
System.Win.ComObj,
Vcl.Dialogs,
Vcl.Graphics,
@ -241,6 +242,7 @@ uses
ButtonFunctionFrm,
ConfigConversion,
FSXAutoLaunch,
FSXLEDFunctionProvider,
FSXLEDFunctionProviderIntf,
FSXResources,
FSXSimConnectStateMonitor,
@ -248,6 +250,7 @@ uses
LEDColorIntf,
LEDFunctionIntf,
LEDFunctionRegistry,
StaticLEDFunction,
StaticResources;
@ -258,6 +261,9 @@ const
DefaultProfileName = 'Default';
ProfilePostfixModified = ' (modified)';
ScriptsPath = 'Scripts\';
FSXScriptsPath = ScriptsPath + 'FSX\';
UserDataPath = 'G940LEDControl\';
FilenameProfiles = UserDataPath + 'Profiles.xml';
FilenameSettings = UserDataPath + 'Settings.xml';
@ -302,6 +308,7 @@ procedure TMainForm.FormCreate(Sender: TObject);
var
worker: IOmniWorker;
scriptPaths: TStringDynArray;
begin
FLog := TX2GlobalLog.Category('UI');
@ -316,6 +323,16 @@ begin
SetFSXState(TextFSXDisconnected, False);
TLEDFunctionRegistry.Register(TStaticLEDFunctionProvider.Create);
SetLength(scriptPaths, 2);
scriptPaths[0] := App.Path + FSXScriptsPath;
scriptPaths[1] := App.UserPath + UserDataPath + FSXScriptsPath;
TLEDFunctionRegistry.Register(TFSXLEDFunctionProvider.Create(scriptPaths));
FEventMonitor := TOmniEventMonitor.Create(Self);
Log.Info('Starting G940 LED state consumer thread');

View File

@ -38,7 +38,10 @@ uses
FSXLEDFunctionProviderIntf in 'Units\FSXLEDFunctionProviderIntf.pas',
SimBaseDocumentXMLBinding in 'Units\SimBaseDocumentXMLBinding.pas',
FSXAutoLaunch in 'Units\FSXAutoLaunch.pas',
ControlIntf in 'Units\ControlIntf.pas';
ControlIntf in 'Units\ControlIntf.pas',
Lua.API in 'DelphiLua\Lua.API.pas',
Lua in 'DelphiLua\Lua.pas',
LuaLEDFunctionProvider in 'Units\LuaLEDFunctionProvider.pas';
{$R *.res}
@ -65,7 +68,6 @@ begin
Application.ShowMainForm := not isRestarting;
Application.Title := 'G940 LED Control';
Application.CreateForm(TMainForm, MainForm);
if isRestarting then
MainForm.Visible := True;

View File

@ -8,7 +8,7 @@
<FrameworkType>VCL</FrameworkType>
<ProjectVersion>13.4</ProjectVersion>
<Base>True</Base>
<Config Condition="'$(Config)'==''">Release</Config>
<Config Condition="'$(Config)'==''">Debug</Config>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<TargetedPlatforms>1</TargetedPlatforms>
<AppType>Application</AppType>
@ -142,6 +142,9 @@
<DCCReference Include="Units\SimBaseDocumentXMLBinding.pas"/>
<DCCReference Include="Units\FSXAutoLaunch.pas"/>
<DCCReference Include="Units\ControlIntf.pas"/>
<DCCReference Include="DelphiLua\Lua.API.pas"/>
<DCCReference Include="DelphiLua\Lua.pas"/>
<DCCReference Include="Units\LuaLEDFunctionProvider.pas"/>
<BuildConfiguration Include="Debug">
<Key>Cfg_2</Key>
<CfgParent>Base</CfgParent>

Binary file not shown.

View File

@ -1,6 +1,7 @@
unit FSXLEDFunction;
interface
(*
uses
FSXLEDFunctionProvider,
LEDFunction,
@ -337,9 +338,11 @@ type
function GetWorkerClass: TCustomLEDMultiStateFunctionWorkerClass; override;
end;
*)
implementation
(*
uses
FSXLEDFunctionWorker,
FSXResources,
@ -1086,6 +1089,6 @@ end;
function TFSXATCVisibilityFunction.GetWorkerClass: TCustomLEDMultiStateFunctionWorkerClass;
begin
Result := TFSXATCVisibilityFunctionWorker;
end;
end;*)
end.

View File

@ -4,79 +4,74 @@ interface
uses
Generics.Collections,
System.SyncObjs,
System.Types,
X2Log.Intf,
Lua,
FSXLEDFunctionProviderIntf,
FSXSimConnectIntf,
LEDFunction,
LEDFunctionIntf,
LEDStateIntf;
LEDStateIntf,
LuaLEDFunctionProvider;
type
TCustomFSXFunction = class;
TCustomFSXFunctionList = TObjectList<TCustomFSXFunction>;
TFSXLEDFunctionWorker = class;
TFSXLEDFunctionProvider = class(TCustomLEDFunctionProvider, IFSXLEDFunctionProvider, IFSXSimConnectObserver)
TFSXLEDFunctionProvider = class(TCustomLuaLEDFunctionProvider, IFSXLEDFunctionProvider, IFSXSimConnectObserver)
private
FSimConnect: TInterfacedObject;
FSimConnectLock: TCriticalSection;
FProfileMenuSimConnect: IFSXSimConnectProfileMenu;
FScriptSimConnect: TObject;
protected
procedure RegisterFunctions; override;
function GetUID: string; override;
protected
function CreateLuaLEDFunction(AInfo: ILuaTable; AOnSetup: ILuaFunction): TCustomLuaLEDFunction; override;
procedure InitInterpreter; override;
procedure SetupWorker(AWorker: TFSXLEDFunctionWorker; AOnSetup: ILuaFunction);
{ IFSXSimConnectObserver }
procedure ObserveDestroy(Sender: IFSXSimConnect);
{ IFSXLEDFunctionProvider }
procedure SetProfileMenu(AEnabled: Boolean; ACascaded: Boolean);
public
constructor Create;
constructor Create(const AScriptFolders: TStringDynArray);
destructor Destroy; override;
function GetSimConnect: IFSXSimConnect;
end;
TCustomFSXFunction = class(TCustomMultiStateLEDFunction)
TFSXLEDFunction = class(TCustomLuaLEDFunction)
private
FProvider: TFSXLEDFunctionProvider;
FDisplayName: string;
FUID: string;
protected
function GetDefaultCategoryName: string; override;
function GetWorkerClass: TCustomLEDMultiStateFunctionWorkerClass; override;
procedure InitializeWorker(AWorker: TCustomLEDMultiStateFunctionWorker); override;
property Provider: TFSXLEDFunctionProvider read FProvider;
protected
function GetCategoryName: string; override;
function GetDisplayName: string; override;
function GetUID: string; override;
public
constructor Create(AProvider: TFSXLEDFunctionProvider; const ADisplayName, AUID: string);
constructor Create(AProvider: TFSXLEDFunctionProvider; AInfo: ILuaTable; AOnSetup: ILuaFunction);
end;
TCustomFSXFunctionClass = class of TCustomFSXFunction;
TCustomFSXFunctionWorker = class(TCustomLEDMultiStateFunctionWorker)
TFSXLEDFunctionWorker = class(TCustomLuaLEDFunctionWorker)
private
FDataHandler: IFSXSimConnectDataHandler;
FDefinitionID: Cardinal;
FSimConnect: IFSXSimConnect;
FDefinitionID: TList<Cardinal>;
protected
procedure RegisterVariables(ADefinition: IFSXSimConnectDefinition); virtual; abstract;
procedure SetSimConnect(const Value: IFSXSimConnect); virtual;
property DataHandler: IFSXSimConnectDataHandler read FDataHandler;
property DefinitionID: Cardinal read FDefinitionID;
property SimConnect: IFSXSimConnect read FSimConnect write SetSimConnect;
property DefinitionID: TList<Cardinal> read FDefinitionID;
protected
procedure AddDefinition(ADefinition: IFSXSimConnectDefinition);
procedure HandleData(AData: Pointer); virtual; abstract;
public
constructor Create(const AProviderUID, AFunctionUID: string; AStates: ILEDMultiStateFunction; ASettings: ILEDFunctionWorkerSettings; const APreviousState: string = ''); override;
@ -86,6 +81,7 @@ type
implementation
uses
System.Classes,
System.SysUtils,
X2Log.Global,
@ -100,37 +96,88 @@ uses
type
TCustomFSXFunctionWorkerDataHandler = class(TInterfacedObject, IFSXSimConnectDataHandler)
private
FWorker: TCustomFSXFunctionWorker;
FWorker: TFSXLEDFunctionWorker;
protected
{ IFSXSimConnectDataHandler }
procedure HandleData(AData: Pointer);
property Worker: TCustomFSXFunctionWorker read FWorker;
property Worker: TFSXLEDFunctionWorker read FWorker;
public
constructor Create(AWorker: TCustomFSXFunctionWorker);
constructor Create(AWorker: TFSXLEDFunctionWorker);
end;
TLuaSimConnect = class(TPersistent)
private
FProvider: TFSXLEDFunctionProvider;
protected
property Provider: TFSXLEDFunctionProvider read FProvider;
public
constructor Create(AProvider: TFSXLEDFunctionProvider);
published
procedure Monitor(Context: ILuaContext);
end;
type
TLuaSimConnectType = record
TypeName: string;
Units: string;
DataType: SIMCONNECT_DATAType;
end;
const
LuaSimConnectTypes: array[0..4] of TLuaSimConnectType =
(
( TypeName: 'Bool'; Units: FSX_UNIT_BOOL; DataType: SIMCONNECT_DATAType_INT32 ),
( TypeName: 'Percent'; Units: FSX_UNIT_PERCENT; DataType: SIMCONNECT_DATAType_FLOAT64 ),
( TypeName: 'Integer'; Units: FSX_UNIT_NUMBER; DataType: SIMCONNECT_DATAType_INT32 ),
( TypeName: 'Float'; Units: FSX_UNIT_NUMBER; DataType: SIMCONNECT_DATAType_FLOAT64 ),
( TypeName: 'Mask'; Units: FSX_UNIT_MASK; DataType: SIMCONNECT_DATATYPE_INT32 )
);
function GetUnits(const AType: string; out AUnits: string; out ADataType: SIMCONNECT_DATAType): Boolean;
var
typeIndex: Integer;
begin
for typeIndex := Low(LuaSimConnectTypes) to High(LuaSimConnectTypes) do
if SameText(AType, LuaSimConnectTypes[typeIndex].TypeName) then
begin
AUnits := LuaSimConnectTypes[typeIndex].Units;
ADataType := LuaSimConnectTypes[typeIndex].DataType;
Exit(True);
end;
Result := False;
end;
{ TFSXLEDFunctionProvider }
constructor TFSXLEDFunctionProvider.Create;
constructor TFSXLEDFunctionProvider.Create(const AScriptFolders: TStringDynArray);
begin
inherited Create;
FSimConnectLock := TCriticalSection.Create;
FScriptSimConnect := TLuaSimConnect.Create(Self);
inherited Create(AScriptFolders);
end;
destructor TFSXLEDFunctionProvider.Destroy;
begin
FreeAndNil(FScriptSimConnect);
FreeAndNil(FSimConnectLock);
inherited Destroy;
end;
(*
procedure TFSXLEDFunctionProvider.RegisterFunctions;
begin
inherited RegisterFunctions;
{ Systems }
RegisterFunction(TFSXBatteryMasterFunction.Create( Self, FSXFunctionDisplayNameBatteryMaster, FSXFunctionUIDBatteryMaster));
RegisterFunction(TFSXDeIceFunction.Create( Self, FSXFunctionDisplayNameDeIce, FSXFunctionUIDDeIce));
@ -193,6 +240,36 @@ begin
{ ATC }
RegisterFunction(TFSXATCVisibilityFunction.Create(FSXProviderUID));
end;
*)
function TFSXLEDFunctionProvider.CreateLuaLEDFunction(AInfo: ILuaTable; AOnSetup: ILuaFunction): TCustomLuaLEDFunction;
begin
Result := TFSXLEDFunction.Create(Self, AInfo, AOnSetup);
end;
procedure TFSXLEDFunctionProvider.InitInterpreter;
var
simConnectType: ILuaTable;
typeIndex: Integer;
begin
inherited InitInterpreter;
Interpreter.RegisterFunctions(FScriptSimConnect, 'SimConnect');
simConnectType := TLuaTable.Create;
for typeIndex := Low(LuaSimConnectTypes) to High(LuaSimConnectTypes) do
simConnectType.SetValue(LuaSimConnectTypes[typeIndex].TypeName, LuaSimConnectTypes[typeIndex].TypeName);
Interpreter.SetGlobalVariable('SimConnectType', simConnectType);
end;
procedure TFSXLEDFunctionProvider.SetupWorker(AWorker: TFSXLEDFunctionWorker; AOnSetup: ILuaFunction);
begin
AOnSetup.Call([AWorker.UID]);
end;
function TFSXLEDFunctionProvider.GetUID: string;
@ -245,81 +322,80 @@ end;
{ TCustomFSXFunction }
constructor TCustomFSXFunction.Create(AProvider: TFSXLEDFunctionProvider; const ADisplayName, AUID: string);
{ TFSXLEDFunction }
constructor TFSXLEDFunction.Create(AProvider: TFSXLEDFunctionProvider; AInfo: ILuaTable; AOnSetup: ILuaFunction);
begin
inherited Create(AProvider.GetUID);
inherited Create(AProvider, AInfo, AOnSetup);
FProvider := AProvider;
FDisplayName := ADisplayName;
FUID := AUID;
end;
procedure TCustomFSXFunction.InitializeWorker(AWorker: TCustomLEDMultiStateFunctionWorker);
begin
(AWorker as TCustomFSXFunctionWorker).SimConnect := Provider.GetSimConnect;
end;
function TCustomFSXFunction.GetCategoryName: string;
function TFSXLEDFunction.GetDefaultCategoryName: string;
begin
Result := FSXCategory;
end;
function TCustomFSXFunction.GetDisplayName: string;
function TFSXLEDFunction.GetWorkerClass: TCustomLEDMultiStateFunctionWorkerClass;
begin
Result := FDisplayName;
Result := TFSXLEDFunctionWorker;
end;
function TCustomFSXFunction.GetUID: string;
procedure TFSXLEDFunction.InitializeWorker(AWorker: TCustomLEDMultiStateFunctionWorker);
var
worker: TFSXLEDFunctionWorker;
begin
Result := FUID;
worker := (AWorker as TFSXLEDFunctionWorker);
worker.Provider := Provider;
Provider.SetupWorker(worker, Setup);
end;
{ TCustomFSXFunctionWorker }
constructor TCustomFSXFunctionWorker.Create(const AProviderUID, AFunctionUID: string; AStates: ILEDMultiStateFunction; ASettings: ILEDFunctionWorkerSettings; const APreviousState: string);
{ TFSXLEDFunctionWorker }
constructor TFSXLEDFunctionWorker.Create(const AProviderUID, AFunctionUID: string; AStates: ILEDMultiStateFunction; ASettings: ILEDFunctionWorkerSettings; const APreviousState: string);
begin
{ We can't pass ourselves as the Data Handler, as it would keep a reference to
this worker from the SimConnect interface. That'd mean the worker never
gets destroyed, and SimConnect never shuts down. Hence this proxy class. }
FDataHandler := TCustomFSXFunctionWorkerDataHandler.Create(Self);
FDefinitionID := TList<Cardinal>.Create;
inherited Create(AProviderUID, AFunctionUID, AStates, ASettings, APreviousState);
end;
destructor TCustomFSXFunctionWorker.Destroy;
destructor TFSXLEDFunctionWorker.Destroy;
var
simConnect: IFSXSimConnect;
id: Cardinal;
begin
if DefinitionID <> 0 then
SimConnect.RemoveDefinition(DefinitionID, DataHandler);
if Assigned(Provider) and (DefinitionID.Count > 0) then
begin
simConnect := (Provider as TFSXLEDFunctionProvider).GetSimConnect;
for id in DefinitionID do
simConnect.RemoveDefinition(id, DataHandler);
end;
FreeAndNil(FDefinitionID);
inherited Destroy;
end;
procedure TCustomFSXFunctionWorker.SetSimConnect(const Value: IFSXSimConnect);
var
definition: IFSXSimConnectDefinition;
procedure TFSXLEDFunctionWorker.AddDefinition(ADefinition: IFSXSimConnectDefinition);
begin
FSimConnect := Value;
if Assigned(SimConnect) then
begin
definition := SimConnect.CreateDefinition;
RegisterVariables(definition);
FDefinitionID := SimConnect.AddDefinition(definition, DataHandler);
end;
DefinitionID.Add((Provider as TFSXLEDFunctionProvider).GetSimConnect.AddDefinition(ADefinition, DataHandler));
end;
{ TCustomFSXFunctionWorkerDataHandler }
constructor TCustomFSXFunctionWorkerDataHandler.Create(AWorker: TCustomFSXFunctionWorker);
constructor TCustomFSXFunctionWorkerDataHandler.Create(AWorker: TFSXLEDFunctionWorker);
begin
inherited Create;
@ -333,7 +409,65 @@ begin
end;
initialization
TLEDFunctionRegistry.Register(TFSXLEDFunctionProvider.Create);
{ TLuaSimConnect }
constructor TLuaSimConnect.Create(AProvider: TFSXLEDFunctionProvider);
begin
inherited Create;
FProvider := AProvider;
end;
procedure TLuaSimConnect.Monitor(Context: ILuaContext);
var
workerID: string;
variables: ILuaTable;
onData: ILuaFunction;
worker: TCustomLuaLEDFunctionWorker;
definition: IFSXSimConnectDefinition;
variable: TLuaKeyValuePair;
info: ILuaTable;
units: string;
dataType: SIMCONNECT_DATAType;
begin
if Context.Parameters.Count < 3 then
raise ELuaScriptError.Create('Not enough parameters for SimConnect.Monitor');
if Context.Parameters[0].VariableType <> VariableString then
raise ELuaScriptError.Create('Context expected for SimConnect.Monitor parameter 1');
if Context.Parameters[1].VariableType <> VariableTable then
raise ELuaScriptError.Create('Table expected for SimConnect.Monitor parameter 2');
if Context.Parameters[2].VariableType <> VariableFunction then
raise ELuaScriptError.Create('Function expected for SimConnect.Monitor parameter 3');
workerID := Context.Parameters[0].AsString;
variables := Context.Parameters[1].AsTable;
onData := Context.Parameters[2].AsFunction;
worker := Provider.FindWorker(workerID);
if not Assigned(worker) then
raise ELuaScriptError.Create('Context expected for SimConnect.Monitor parameter 1');
definition := Provider.GetSimConnect.CreateDefinition;
for variable in variables do
begin
if variable.Value.VariableType = VariableTable then
begin
info := variable.Value.AsTable;
if info.HasValue('variable') and
info.HasValue('type') and
GetUnits(info.GetValue('type').AsString, units, dataType) then
begin
definition.AddVariable(info.GetValue('variable').AsString, units, dataType);
end;
end;
end;
(worker as TFSXLEDFunctionWorker).AddDefinition(definition);
end;
end.

View File

@ -1,6 +1,7 @@
unit FSXLEDFunctionWorker;
interface
(*
uses
OtlTaskControl,
@ -268,9 +269,10 @@ type
constructor Create(const AProviderUID: string; const AFunctionUID: string; AStates: ILEDMultiStateFunction; ASettings: ILEDFunctionWorkerSettings; const APreviousState: string = ''); override;
destructor Destroy; override;
end;
*)
implementation
(*
uses
System.Math,
System.StrUtils,
@ -1181,6 +1183,6 @@ begin
FVisible := visible;
FOnStateChanged(visible);
end;
end;
end;*)
end.

View File

@ -0,0 +1,332 @@
unit LuaLEDFunctionProvider;
interface
uses
System.Generics.Collections,
System.SysUtils,
System.Types,
LEDFunction,
LEDFunctionIntf,
LEDStateIntf,
Lua;
type
ELuaScriptError = class(Exception);
TCustomLuaLEDFunctionWorker = class;
TCustomLuaLEDFunction = class(TCustomMultiStateLEDFunction)
private
FCategoryName: string;
FDisplayName: string;
FUID: string;
FScriptStates: ILuaTable;
FSetup: ILuaFunction;
protected
procedure RegisterStates; override;
function GetDefaultCategoryName: string; virtual;
{ ILEDFunction }
function GetCategoryName: string; override;
function GetDisplayName: string; override;
function GetUID: string; override;
property ScriptStates: ILuaTable read FScriptStates;
property Setup: ILuaFunction read FSetup;
public
constructor Create(AProvider: ILEDFunctionProvider; AInfo: ILuaTable; ASetup: ILuaFunction);
end;
TCustomLuaLEDFunctionProvider = class(TCustomLEDFunctionProvider)
private
FInterpreter: TLua;
FScriptFolders: TStringDynArray;
FWorkers: TDictionary<string, TCustomLuaLEDFunctionWorker>;
protected
function CreateLuaLEDFunction(AInfo: ILuaTable; ASetup: ILuaFunction): TCustomLuaLEDFunction; virtual; abstract;
procedure InitInterpreter; virtual;
procedure RegisterFunctions; override;
procedure RegisterWorker(AWorker: TCustomLuaLEDFunctionWorker);
procedure UnregisterWorker(AWorker: TCustomLuaLEDFunctionWorker);
function FindWorker(const AUID: string): TCustomLuaLEDFunctionWorker;
property Interpreter: TLua read FInterpreter;
property ScriptFolders: TStringDynArray read FScriptFolders;
property Workers: TDictionary<string, TCustomLuaLEDFunctionWorker> read FWorkers;
public
constructor Create(const AScriptFolders: TStringDynArray);
destructor Destroy; override;
end;
TCustomLuaLEDFunctionWorker = class(TCustomLEDMultiStateFunctionWorker)
private
FProvider: TCustomLuaLEDFunctionProvider;
FUID: string;
procedure SetProvider(const Value: TCustomLuaLEDFunctionProvider);
protected
property Provider: TCustomLuaLEDFunctionProvider read FProvider write SetProvider;
public
constructor Create(const AProviderUID, AFunctionUID: string; AStates: ILEDMultiStateFunction; ASettings: ILEDFunctionWorkerSettings; const APreviousState: string = ''); override;
destructor Destroy; override;
property UID: string read FUID;
end;
implementation
uses
System.IOUtils,
LEDColorIntf,
LEDState;
const
LuaLEDColors: array[TLEDColor] of string =
(
'Off', 'Green', 'Amber', 'Red',
'FlashingGreenFast', 'FlashingGreenNormal',
'FlashingAmberFast', 'FlashingAmberNormal',
'FlashingRedFast', 'FlashingRedNormal'
);
function GetLEDColor(const AValue: string; ADefault: TLEDColor = lcOff): TLEDColor;
var
color: TLEDColor;
begin
for color := Low(TLEDColor) to High(TLEDColor) do
if SameText(AValue, LuaLEDColors[color]) then
exit(color);
Result := ADefault;
end;
{ TCustomLuaLEDFunctionProvider }
constructor TCustomLuaLEDFunctionProvider.Create(const AScriptFolders: TStringDynArray);
begin
FWorkers := TDictionary<string, TCustomLuaLEDFunctionWorker>.Create;
FInterpreter := TLua.Create;
FScriptFolders := AScriptFolders;
InitInterpreter;
inherited Create;
end;
destructor TCustomLuaLEDFunctionProvider.Destroy;
begin
FreeAndNil(FInterpreter);
FreeAndNil(FWorkers);
inherited Destroy;
end;
procedure TCustomLuaLEDFunctionProvider.InitInterpreter;
var
table: ILuaTable;
color: TLEDColor;
begin
Interpreter.RegisterFunction('RegisterFunction',
procedure(Context: ILuaContext)
var
info: ILuaTable;
setup: ILuaFunction;
begin
if Context.Parameters.Count < 2 then
raise ELuaScriptError.Create('Not enough parameters for RegisterFunction');
if Context.Parameters[0].VariableType <> VariableTable then
raise ELuaScriptError.Create('Table expected for RegisterFunction parameter 1');
if Context.Parameters[1].VariableType <> VariableFunction then
raise ELuaScriptError.Create('Function expected for RegisterFunction parameter 2');
info := Context.Parameters[0].AsTable;
setup := Context.Parameters[1].AsFunction;
if not info.HasValue('uid') then
raise ELuaScriptError.Create('"uid" value is required for RegisterFunction parameter 1');
RegisterFunction(CreateLuaLEDFunction(info, setup));
end);
table := TLuaTable.Create;
for color := Low(TLEDColor) to High(TLEDColor) do
table.SetValue(LuaLEDColors[color], LuaLEDColors[color]);
Interpreter.SetGlobalVariable('LEDColor', table);
// #ToDo1 -oMvR: 28-5-2017: SetState
end;
procedure TCustomLuaLEDFunctionProvider.RegisterFunctions;
var
scriptFolder: string;
scriptFile: string;
begin
for scriptFolder in ScriptFolders do
if TDirectory.Exists(scriptFolder) then
for scriptFile in TDirectory.GetFiles(ScriptFolder, '*.lua') do
try
Interpreter.LoadFromFile(scriptFile);
except
on E:Exception do
Exception.RaiseOuterException(ELuaScriptError.CreateFmt('Error while loading script %s: %s', [scriptFile, E.Message]));
end;
end;
procedure TCustomLuaLEDFunctionProvider.RegisterWorker(AWorker: TCustomLuaLEDFunctionWorker);
begin
Workers.Add(AWorker.UID, AWorker);
end;
procedure TCustomLuaLEDFunctionProvider.UnregisterWorker(AWorker: TCustomLuaLEDFunctionWorker);
begin
Workers.Remove(AWorker.UID);
end;
function TCustomLuaLEDFunctionProvider.FindWorker(const AUID: string): TCustomLuaLEDFunctionWorker;
begin
if not Workers.TryGetValue(AUID, Result) then
Result := nil;
end;
{ TCustomLuaLEDFunction }
constructor TCustomLuaLEDFunction.Create(AProvider: ILEDFunctionProvider; AInfo: ILuaTable; ASetup: ILuaFunction);
begin
FCategoryName := GetDefaultCategoryName;
FDisplayName := 'Unknown function';
FSetup := ASetup;
FUID := AInfo.GetValue('uid').AsString;
if AInfo.HasValue('category') then
FCategoryName := AInfo.GetValue('category').AsString;
if AInfo.HasValue('displayName') then
FDisplayName := AInfo.GetValue('displayName').AsString;
FScriptStates := nil;
if AInfo.HasValue('states') then
FScriptStates := AInfo.GetValue('states').AsTable;
// #ToDo1 -oMvR: 28-5-2017: application filter?
inherited Create(AProvider.GetUID);
end;
function TCustomLuaLEDFunction.GetCategoryName: string;
begin
Result := FCategoryName;
end;
function TCustomLuaLEDFunction.GetDisplayName: string;
begin
Result := FDisplayName;
end;
function TCustomLuaLEDFunction.GetUID: string;
begin
Result := FUID;
end;
procedure TCustomLuaLEDFunction.RegisterStates;
var
state: TLuaKeyValuePair;
displayName: string;
defaultColor: TLEDColor;
info: ILuaTable;
begin
if not Assigned(ScriptStates) then
exit;
for state in ScriptStates do
begin
displayName := state.Key.AsString;
defaultColor := lcOff;
if state.Value.VariableType = VariableTable then
begin
info := state.Value.AsTable;
if info.HasValue('displayName') then
displayName := info.GetValue('displayName').AsString;
if info.HasValue('default') then
defaultColor := GetLEDColor(info.GetValue('default').AsString);
end;
RegisterState(TLEDState.Create(state.Key.AsString, displayName, defaultColor));
end;
end;
function TCustomLuaLEDFunction.GetDefaultCategoryName: string;
begin
Result := 'Other';
end;
{ TCustomLuaLEDFunctionWorker }
constructor TCustomLuaLEDFunctionWorker.Create(const AProviderUID, AFunctionUID: string; AStates: ILEDMultiStateFunction; ASettings: ILEDFunctionWorkerSettings; const APreviousState: string);
var
workerGUID: TGUID;
begin
if CreateGUID(workerGUID) <> 0 then
RaiseLastOSError;
FUID := GUIDToString(workerGUID);
inherited Create(AProviderUID, AFunctionUID, AStates, ASettings, APreviousState);
end;
destructor TCustomLuaLEDFunctionWorker.Destroy;
begin
SetProvider(nil);
inherited Destroy;
end;
procedure TCustomLuaLEDFunctionWorker.SetProvider(const Value: TCustomLuaLEDFunctionProvider);
begin
if Value <> FProvider then
begin
if Assigned(FProvider) then
FProvider.UnregisterWorker(Self);
FProvider := Value;
if Assigned(FProvider) then
FProvider.RegisterWorker(Self);
end;
end;
end.

View File

@ -114,8 +114,4 @@ begin
Result := FState;
end;
initialization
TLEDFunctionRegistry.Register(TStaticLEDFunctionProvider.Create);
end.

View File

@ -1,2 +1,2 @@
<?xml version="1.0"?>
<DataBindingSettings xmlns="http://www.x2software.net/xsd/databinding/DataBindingSettings.xsd"><Output><OutputType>Single</OutputType><OutputSingle><FileName>F:\Development\G940\G940LEDControl\Units\SimBaseDocumentXMLBinding.pas</FileName></OutputSingle></Output></DataBindingSettings>
<DataBindingSettings xmlns="http://www.x2software.net/xsd/databinding/DataBindingSettings.xsd"><Output><OutputType>Single</OutputType><OutputSingle><FileName>..\Units\SimBaseDocumentXMLBinding.pas</FileName></OutputSingle></Output></DataBindingSettings>

View File

@ -1,6 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- edited with XMLSpy v2015 rel. 3 (x64) (http://www.altova.com) by Mark van Renswoude (UnameIT we build IT B.V.) -->
<!-- W3C Schema generated by XMLSpy v2015 rel. 3 (x64) (http://www.altova.com) -->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="SimBase.Document">
<xs:complexType>