lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


> >From: Falko Poiker <fpoiker@relic.com>

> >The other reason I don't want to use tolua, and this seems to be a
problem
> >with lua in general, is that it creates wrapper functions for every
variable
> >and object/structure element accessed by lua.
> No really. You only need to create wrapper functions for each *type*.
> Variables are exported to Lua as userdata, and variables of the same type
> have the same tag, so that they can share the get/setglobal tag methods.
> This is exactly what tolua does.
Hmmm... That doesn't seem to be what I'm experiencing.  I have a large
number of variables in my tolua.pkg file, and tolua creates a
toluaI_set_<varname> and a toluaI_get_<varname> function for every one,
whether the variable is a float, int or a user defined type (in the example
below, the vector4 class).

> If you need concrete examples of how to do all this, post some
> declarations of your variables and I'll send you some sample code.
Okay, in my tolua.pkg file I have (among other things) the following:

class vector4 {
    float x;
	float y;
	float z;
	float w;
	
	vector4() {}
    vector4(float _x, float _y, float _z, float _w) { x = _x; y = _y; z =
_z; w = _w; }

    void set(float _x, float _y, float _z, float _w) { x = _x; y = _y; z =
_z; w = _w; }

	// some other methods
}

/*==========================================================================
===
    Pieplate tweakables:
============================================================================
=*/
extern int twkPiePieces;
extern int twkHorizonPieces;
extern real32 twkPieClosestDistance;
extern real32 twkMaxMovementDist;
extern real32 twkHorizontalHashMarkLength;
extern real32 twkVerticalHashMarkLength;
extern real32 twkHeightSnap;
extern real32 twkShipCloseToPlaneDistance;
extern real32 twkPieCircleSizeMax;       
extern real32 twkPieCircleSizeMin;       
extern real32 twkHeightFactor;

extern vector4 test;
extern vector4 twkInnerPieColour;
extern vector4 twkRangePieColour;
extern vector4 twkOuterPieColour;
extern vector4 twkMoveToDiscColour;
extern vector4 twkMoveToPlanarDiscColour;
extern vector4 twkShipOnPlaneColour;
extern vector4 twkClosestShipOnPlaneColour;



This package file creates 2 functions for every variable (registered
internally to tolua using the functions calls "tolua_tablevar" and
"tolua_globalvar").  For example, for the "test" variable, the
tolua_XXX_open function has the line

 tolua_globalvar("test",toluaI_get_test,toluaI_set_test);

and the functions

/* get function: test */
static void toluaI_get_test(void)
{
  tolua_pushusertype((void*)&test,tolua_tag_vector4);
}

/* set function: test */
static void toluaI_set_test(void)
{
  if (!tolua_istype(1,tolua_tag_vector4,0))
   tolua_error("#vinvalid type in variable assignment.");
  test = *((vector4*)  tolua_getusertype(1,0));
}


> >Homeworld (our last game) had
> >over 10,000 tweakables, so exposing this number of variables to lua would
> >result in over 1 megabyte of memory usage simply for the function
wrappers.
> Do you really have 10,000 different *types*?
No, 10,000 different variables.  Very few types - most are real, int, char
or vector.

> >So I've been considering another option - modifying the lua code so that
it
> >modifies the game variables directly.
> You could do this of course, although I don't see you can avoid having
several
> types in the Value union.
> >1. there is no need to pre-register any of the game's variables with Lua
-
> >the variables are accessed on a "need to know" basis.
> Again, I don't see you can avoid this.
Well, I've been poking around a bit, and here's a code snippet of what it
would look like:


// From lvm.c  of version 3.2

void luaV_setglobal (TaggedString *ts) {
  // Falko's modification
  //was: TObject *oldvalue = &ts->u.s.globalval;
  TObject *oldvalue = getGameGlobal(ts->str, &ts->u.s.globalval);

  TObject *im = luaT_getimbyObj(oldvalue, IM_SETGLOBAL);
  if (ttype(im) == LUA_T_NIL)  /* is there a tag method? */
  {
      // added by Falko
      setGameGlobal(ts->str, L->stack.top->value.n);
    luaS_rawsetglobal(ts, --L->stack.top);
  }
  else {
    /* WARNING: caller must assure stack space */
    struct Stack *S = &L->stack;
    TObject newvalue;
    newvalue = *(S->top-1);
    ttype(S->top-1) = LUA_T_STRING;
    tsvalue(S->top-1) = ts;
    *S->top++ = *oldvalue;
    *S->top++ = newvalue;
    luaD_callTM(im, 3, 0);
  }
}


getGameGlobal compares "ts->str" with its internal list of variable names -
if it finds a game variable of the same name, it creates a "TObject" with
the correct value and returns it, if not, it returns 
"&ts->u.s.globalval".
setGameGlobal does the same, but sets the game variable and returns nothing.

Note that the number parameter of setGameGlobal (L->stack.top->value.n) is
only temporary.  I imagine that "setGameGlobal" would accept the value enum
directly and extract what it needs in C.

Later iterations of getGameGlobal and setGameGlobal would somehow get around
doing a string compare every time by creating a pointer to any variable
accessed to create a shortcut to that variable (possibly by defining a "game
variable" type in the Value union or something like that).

By the way, I'm only suggesting doing this because I thought I could
eliminate a bunch of work on my part.  If Lua provides a mechanism to do
this easily without modifying the lua code, I would be very pleased to know
how.

Thanks for your help!!
Falko