LOL!Originally Posted by jdarling
Thanks for the nice comments, and I am just glad to be able to occasionally help other people after myself getting lots of help from the net over the yearsOriginally Posted by jdarling
cheers,
Paul.
LOL!Originally Posted by jdarling
Thanks for the nice comments, and I am just glad to be able to occasionally help other people after myself getting lots of help from the net over the yearsOriginally Posted by jdarling
cheers,
Paul.
Games:
Seafox
Pages:
Syntax Error Software
itch.io page
Online Chess
http://gameknot.com/#paul_nicholls
I was thinking about '__index' as well, but as far as I can figure this would only help with making readable properties, not writable onesOriginally Posted by jdarling
How would using '__newindex' help with emulating properties? This is only called if one is adding a new key + value to a table, not for pre-existing keys...
I would be interested in how you got the '__newindex' working for this sort of thing
Also I have no clue as to if it is even possible to protect the existing 'class methods' created in the table from being accidently overwritten by a lua script using the table and assigning a value to that key...
Any thoughts on that one?
cheers,
Paul.
Games:
Seafox
Pages:
Syntax Error Software
itch.io page
Online Chess
http://gameknot.com/#paul_nicholls
I'm not sure if this will help us guys, but I found this post over on a Lua forum:
http://www.icynorth.com/forums/viewt...404&highlight=
looks interesting :-)
cheers,
Paul
Games:
Seafox
Pages:
Syntax Error Software
itch.io page
Online Chess
http://gameknot.com/#paul_nicholls
Just as soon as I have the code completed and cleaned up I'll post it up for everyone to use. The basic idea is this:Originally Posted by paul_nicholls
Create your "Class" using the methods provided in Luna thus hiding the metatable and object level manager from the Lua script in general. Overide the __index and __newindex (witch fires when an unknown is set) and make sure that ALL properties are removed from the meta table. Any time a person makes a request to the object using dot notation either __index (read) or __newindex (write) will be fired, using RTTI scan the object and find out if the property exists, if so then return/set the value otherwise throw an error or pass it back up to Lua as a new table entitity using lua_settable(L, TableIndex) lua_pushstring(L, [PropName]) lua_pushvalue(L, val). Thus the next time its accessed it won't fire __index or __newindex, since you have caught the ones that do fire these "events" (and I use the term loosly) your code will still execute. Now before you ask what if the person overrides __index or __newindex remember that we hid the MetaTable and ObjectTable from the user, they can still get at it using upval() but thats another topic for another day. You simply have to let your users know not to screw with the __index and __newindex methods attached to your objects
- Jeremy
http://www.eonclash.com/
Ahh! that makes sense, with the starting with no properties! coolOriginally Posted by jdarling
I'll give it a go myself in the meantime to try it
cheers,
Paul.
Games:
Seafox
Pages:
Syntax Error Software
itch.io page
Online Chess
http://gameknot.com/#paul_nicholls
Ok, this is going to be ugly as I haven't posted the TLUA component yet, but I think you can figure it out w/o it as basically all you have to do is replace its reference with a Plua_State
This code is my reference code for my Delphi->Lua application that is comming around:
[pascal]unit TestLuaClass;
interface
uses
Classes, LuaWrapper, Lua, LuaUtils, Lauxlib, LuaLib;
type
TTestClass=class(TPersistent)
private
FBalance: Double;
procedure SetBalance(const Value: Double);
public
class procedure RegisterTo(LuaScript:TLUA);
published
procedure Deposit(Amountouble);
procedure Withdraw(Amountouble);
property Balance : Double read FBalance write SetBalance;
end;
implementation
uses
SysUtils,
TypInfo;
const
LuaClassName = 'TestClass';
function Check(L: Plua_State; Idx : Integer) : TTestClass;
begin
result := nil;
if lua_type(L, Idx) = LUA_TTABLE then
result := LuaGetTableLightUserData(L, Idx, '_Self')
else
luaL_typerror(L, Idx, LuaClassName);
end;
function new_TestClass(L: Plua_State): Integer; cdecl;
var
c : TTestClass;
begin
if lua_type(L, 1) <> LUA_TTABLE then
lua_remove(L, 1);
c := TTestClass.Create;
LuaSetTableLightUserData(L, 1, '_Self', c);
luaL_getmetatable(L, LuaClassName);
lua_setmetatable(L, -2);
result := 1;
end;
function gc_TestClass(L: Plua_State): Integer; cdecl;
var
c : TTestClass;
begin
c := Check(L, 1);
c.Free;
result := 0;
end;
function indexTestClass(L: Plua_State): Integer; cdecl;
var
c : TTestClass;
propName : String;
v : Variant;
begin
c := Check(L, 1);
lua_remove(L, 1);
propName := LuaToString(L, 1);
if IsPublishedProp(c, propName) then
begin
v := GetPropValue(c, propName);
LuaPushVariant(L, v);
end
else
luaL_error(L, PChar('Property "'+propName+'" does not exist'));
result := 1;
end;
function newindexTestClass(LLua_State): Integer; cdecl;
var
c : TTestClass;
propName : String;
v : Variant;
begin
c := Check(L, 1);
lua_remove(L, 1);
propName := LuaToString(L, 1);
v := LuaToVariant(L, 2);
if IsPublishedProp(c, propName) then
SetPropValue(c, propName, v)
else
luaL_error(L, PChar('Property "'+propName+'" does not exist'));
result := 0;
end;
function luaDeposit(L: Plua_State): Integer; cdecl;
var
c : TTestClass;
begin
c := Check(L, 1);
lua_remove(L, 1);
if lua_type(L, 1)<>LUA_TNUMBER then
luaL_error(L, 'Deposit expects one parameter (Amount) that should be an integer.')
else
c.Deposit(lua_tonumber(L, 1));
result := 0;
end;
function luaWithdraw(L: Plua_State): Integer; cdecl;
var
c : TTestClass;
begin
c := Check(L, 1);
lua_remove(L, 1);
if lua_type(L, 1)<>LUA_TNUMBER then
luaL_error(L, 'Withdraw expects one parameter (Amount) that should be an integer.')
else
c.Withdraw(lua_tonumber(L, 1));
result := 0;
end;
{ TTestClass }
procedure TTestClass.Deposit(Amount: Double);
begin
FBalance := FBalance + Amount;
end;
class procedure TTestClass.RegisterTo(LuaScript: TLUA);
var
MetaTable,
MethodTable,
Methods : Integer;
begin
lua_newtable(LuaScript.LuaState);
Methods := lua_gettop(LuaScript.LuaState);
luaL_newmetatable(LuaScript.LuaState, LuaClassName);
MetaTable := lua_gettop(LuaScript.LuaState);
lua_pushstring(LuaScript.LuaState, LuaClassName);
lua_pushvalue(LuaScript.LuaState, Methods);
lua_settable(LuaScript.LuaState, LUA_GLOBALSINDEX);
lua_pushliteral(LuaScript.LuaState, '__metatable');
lua_pushvalue(LuaScript.LuaState, Methods);
lua_settable(LuaScript.LuaState, metatable);
lua_pushliteral(LuaScript.LuaState, '__index');
lua_pushcfunction(LuaScript.LuaState, indexTestClass);
lua_settable(LuaScript.LuaState, MetaTable);
lua_pushliteral(LuaScript.LuaState, '__newindex');
lua_pushcfunction(LuaScript.LuaState, newindexTestClass);
lua_settable(LuaScript.LuaState, MetaTable);
lua_pushliteral(LuaScript.LuaState, '__gc');
lua_pushcfunction(LuaScript.LuaState, gc_TestClass);
lua_settable(LuaScript.LuaState, MetaTable);
lua_newtable(LuaScript.LuaState);
MethodTable := lua_gettop(LuaScript.LuaState);
lua_pushliteral(LuaScript.LuaState, '__call');
lua_pushcfunction(LuaScript.LuaState, new_TestClass);
lua_pushliteral(LuaScript.LuaState, 'new');
lua_pushvalue(LuaScript.LuaState, -2);
lua_settable(LuaScript.LuaState, Methods);
lua_settable(LuaScript.LuaState, MethodTable);
lua_setmetatable(LuaScript.LuaState, Methods);
//Test Method
lua_pushstring(LuaScript.LuaState, 'Deposit');
lua_pushcfunction(LuaScript.LuaState, luaDeposit);
lua_settable(LuaScript.LuaState, Methods);
lua_pushstring(LuaScript.LuaState, 'Withdraw');
lua_pushcfunction(LuaScript.LuaState, luaWithdraw);
lua_settable(LuaScript.LuaState, Methods);
//End of Test Method}
lua_pop(LuaScript.LuaState, 2);
end;
procedure TTestClass.SetBalance(const Value: Double);
begin
FBalance := Value;
end;
procedure TTestClass.Withdraw(Amount: Double);
begin
FBalance := FBalance - Amount;
end;
end.[/pascal]
- Jeremy
http://www.eonclash.com/
Awsome work chief!
That TTestClass.RegisterTo() method is almost scary! hehe
Paul.
Games:
Seafox
Pages:
Syntax Error Software
itch.io page
Online Chess
http://gameknot.com/#paul_nicholls
Actually, I was thinking. Instead of subclassing from TPersistent, you could possible do something like so instead for more flexability with base class types:
Code:{$M+} TTestClass=class private FBalance: Double; procedure SetBalance(const Value: Double); public class procedure RegisterTo(LuaScript:TLUA); published procedure Deposit(Amount:Double); procedure Withdraw(Amount:Double); property Balance : Double read FBalance write SetBalance; end; {$M-}
I believe the ($M+} will also give you RTTI info as well
Paul.
Games:
Seafox
Pages:
Syntax Error Software
itch.io page
Online Chess
http://gameknot.com/#paul_nicholls
Well actually when complete the importer will just be ran on your source and will create a wrapper unit for it. The problem was I needed an object that was quick and easy to test on that exhibited everything I wanted to wrap up. The only one I haven't figured out yet is properties with array indexes. BTW: If you want to use object assignment for properties then you have to do a GetPropType(Instance, PropName) = tkClass (thats off the top of my head so its probiably wrong) and then get the table's reference to _Self. Other then that its pretty straight forward . Hopefully I get everything completed some time soon.Originally Posted by paul_nicholls
- Jeremy
http://www.eonclash.com/
For you info, using jdarling's idea of an empty table + __index and __newindex I have updated my TLuaClass to check/protect methods + properties
example:
class declaration
class bodyCode:TLuaClassCounter = Class(TLuaClass) Private FCount: Integer; Function IncCount(L: lua_State): Integer; Function GetCount(L: lua_State): Integer; Protected Function CallLuaMethod(L: lua_State; MethodIndex: Integer): Integer; Override; Procedure ReadPropertyValue(L: lua_State; PropertyIndex: Integer); Override; Procedure WritePropertyValue(L: lua_State; PropertyIndex: Integer); Override; Public Constructor Create; Override; End;
Behind the scenes, no properties or methods can be overwritten in a Lua script, and read-only properties can't be written to in Lua scriptCode:Constructor TLuaClassCounter.Create; Begin Inherited Create; RegisterLuaMethod ('IncCount',0); RegisterLuaMethod ('GetCount',1); RegisterLuaProperty('Count' ,0,eIntegerProperty,False); RegisterLuaProperty('Count2x' ,1,eIntegerProperty,True); RegisterLuaProperty('Self' ,2,eLuaClassProperty,True); FCount := 0; End; {.......................................................} {.......................................................} Function TLuaClassCounter.IncCount(L: lua_State): Integer; Begin Inc(FCount); Result := 0; End; {.......................................................} {.......................................................} Function TLuaClassCounter.GetCount(L: lua_State): Integer; Begin lua_pushnumber(L,FCount); Result := 1; End; {.......................................................} {.......................................................} Function TLuaClassCounter.CallLuaMethod(L: lua_State; MethodIndex: Integer): Integer; Begin Result := 0; Case MethodIndex Of 0 : Result := IncCount(L); 1 : Result := GetCount(L); Else End; End; {.......................................................} {.......................................................} Procedure TLuaClassCounter.ReadPropertyValue(L: lua_State; PropertyIndex: Integer); Begin Case PropertyIndex Of 0 : lua_pushnumber(L,FCount); 1 : lua_pushnumber(L,FCount * 2); 2 : PushOntoLuaStack(L); Else End; Result := 1; End; {.......................................................} {.......................................................} Procedure TLuaClassCounter.WritePropertyValue(L: lua_State; PropertyIndex: Integer); Var Value: Double; Begin Case PropertyIndex Of 0 : FCount := Trunc(lua_tonumber(L,3)); Else End; End; {.......................................................} {.......................................................}
Also, you can't assign the wrong type to writable properties and it will tell you
BTW, is there anywhere on this site that one can post largeish code/units to share with people?
cheers,
Paul
Games:
Seafox
Pages:
Syntax Error Software
itch.io page
Online Chess
http://gameknot.com/#paul_nicholls
Bookmarks