registerTimer() - How to call a class function

Discuss, ask for help, share ideas, give suggestions, read tutorials, and tell us about bugs you have found with MicroMacro in here.

Do not post RoM-Bot stuff here. There is a subforum for that.
Forum rules
This is a sub-forum for things specific to MicroMacro.

This is not the place to ask questions about the RoM bot, which uses MicroMacro. There is a difference.
Post Reply
Message
Author
Sgraffite
Posts: 38
Joined: Wed Jul 09, 2008 12:03 pm

registerTimer() - How to call a class function

#1 Post by Sgraffite » Tue Nov 04, 2008 11:26 pm

I'm trying to use registerTimer() to calll a class function, but I am getting the error:

Code: Select all

function arguments expected near ')'
I've tried calling it like this:

Code: Select all

registerTimer("update", 100, char:update);
registerTimer("update", 100, self:update);
if I just try to pass the function name without self: or char: I get this error:

Code: Select all

Non-function type passed to registerTimer() where afunction is expected
The update function does not require any arguments, am I doing something wrong?

User avatar
Administrator
Site Admin
Posts: 5307
Joined: Sat Jan 05, 2008 4:21 pm

Re: registerTimer() - How to call a class function

#2 Post by Administrator » Wed Nov 05, 2008 12:48 am

The : operator is for calling functions. You should use the . (dot) operator in this case. These kind of specifics are a bit awkward for Lua, but you'll get used to it.

Example:

Code: Select all

SomeClass = { };
SomeClass.__index = SomeClass;

function SomeClass.create(_something)
  local tmp = { };
  setmetatable(tmp, SomeClass);
  tmp._something = _something;

  return tmp;
end

function SomeClass:someFunction()
  printf("This is a test.\n");
end

function main()
  local myClass = SomeClass.create(1);
  registerTimer("test", secondsToTimer(1), myClass.someFunction);

  while(true) do
    yrest(10);
  end
end
startMacro(main);

And, if you're using the class module (which you probably should unless you're writing a module yourself or something):

Code: Select all

SomeClass = class();

function SomeClass:test()
  printf("Hello\n");
end

function main()
  local myClass = class(SomeClass);

  registerTimer("test", secondsToTimer(1), myClass.test);

  while(true) do
    yrest(10);
  end
end
startMacro(main);
Here's a good page on Lua classes: http://lua-users.org/wiki/SimpleLuaClasses

Sgraffite
Posts: 38
Joined: Wed Jul 09, 2008 12:03 pm

Re: registerTimer() - How to call a class function

#3 Post by Sgraffite » Wed Nov 05, 2008 10:06 pm

I should be able to figure this out, I was using that website to base my class structure from. It's got to be something really simple, I'm just not seeing it.

I've fixed the previous error, but I'm getting a different error now:

Code: Select all

attempt to index 'self' a nil value
By my understanding, creating the class and creating an instance of it, it should know what self is. As far as I can tell I did just that, but it does not know what self is.

Here is the code I'm using:
class_character.lua

Code: Select all

Character = class(function(obj,proc)
    obj.proc = proc;
    obj:init();
  end
)

function Character:init()
    character_ptr = 0x081CBEC;
    hp_max_offset = 304;
    mp_max_offset = 312;
    sp_max_offset = 320;
    
    self.hp_max = memoryReadIntPtr(self.proc, character_ptr, hp_max_offset);
    self.mp_max = memoryReadIntPtr(self.proc, character_ptr, mp_max_offset);
    self.sp_max = memoryReadIntPtr(self.proc, character_ptr, sp_max_offset);
end

function Character:update()
    character_ptr = 0x081CBEC;
    hp_offset = 300;
    mp_offset = 308;
    sp_offset = 316;
    
    pos_x = 16;
    pos_y = 20;
    pos_z = 24;
    pos_rot_x = 28;
    pos_rot_y = 36;
    
    targetid_addr = 0x006C7BC4; -- short, 65535 if none selected
    
    self.hp = memoryReadIntPtr(self.proc, character_ptr, hp_offset);
    self.mp = memoryReadIntPtr(self.proc, character_ptr, mp_offset);
    self.sp = memoryReadIntPtr(self.proc, character_ptr, sp_offset);
    
    self.x = memoryReadFloatPtr(self.proc, character_ptr, pos_x);
    self.y = memoryReadFloatPtr(self.proc, character_ptr, pos_y);
    self.z = memoryReadFloatPtr(self.proc, character_ptr, pos_z);
    self.rot_x = memoryReadFloatPtr(self.proc, character_ptr, pos_rot_x);
    self.rot_y = memoryReadFloatPtr(self.proc, character_ptr, pos_rot_y);
    printf("x="..self.rot_x.."\n");
    printf("y="..self.rot_y.."\n");
end
main:

Code: Select all

include( "class_character.lua" );

startKey = key.VK_INSERT;
stopKey = key.VK_DELETE;

function main()
    proc = openProcess(findProcessByExe("game.exe"));
    win = findWindow("Shaiya");
    attach(win);
    setPriority(PRIORITY_HIGH);

    --instantiate new character class
    local myChar = class( Character );
    --registerTimer("update", 100, myChar.update);
    
    while( true ) do
        myChar.update();
        yrest(500);
    end
end

startMacro(main);

User avatar
Administrator
Site Admin
Posts: 5307
Joined: Sat Jan 05, 2008 4:21 pm

Re: registerTimer() - How to call a class function

#4 Post by Administrator » Wed Nov 05, 2008 10:55 pm

If I had to guess, it would be this line:

Code: Select all

myChar.update();
You should replace . with : to call the function as this is a specific instance of that class (and, hence, 'self' would be usable).

Sgraffite
Posts: 38
Joined: Wed Jul 09, 2008 12:03 pm

Re: registerTimer() - How to call a class function

#5 Post by Sgraffite » Wed Nov 05, 2008 11:35 pm

Thanks a bunch, can't believe I didn't see that, was throwing me off for a while :(

zer0
Posts: 213
Joined: Sat Feb 16, 2008 11:55 pm

Re: registerTimer() - How to call a class function

#6 Post by zer0 » Thu Nov 06, 2008 6:17 am

Yeah I often accidentally use "." instead of ":". :) And the error that it generates doesn't isolate the issue down easily. ;)

Sgraffite
Posts: 38
Joined: Wed Jul 09, 2008 12:03 pm

Re: registerTimer() - How to call a class function

#7 Post by Sgraffite » Thu Nov 06, 2008 11:22 pm

I was messing around with your example some more, because I can't for the life of me get registerTimer to call a function that accesses anything involving "self", and have said function be able to access self.

Using this code:

Code: Select all

startKey = key.VK_INSERT;
stopKey = key.VK_DELETE;

SomeClass = class();

function SomeClass:test()
  self.name = 'Cow';
  printf("Hello I am "..self.name.."\n");
end

function main()
  local myClass = class(SomeClass);
  --myClass:test();
  registerTimer("test", secondsToTimer(1), myClass.test);

  while(true) do
    yrest(10);
  end
end
startMacro(main);

With the registerTimer line uncommented, it will throw an error about self being nil. Commenting out the registerTimer line, and uncommenting the line above it works just fine. Logically I don't understand why this would happen as they are both calling the same function.


Also I am using MicroMacro v0.98 and have noticed that after running versions of the same script many times (like making one change every time, and running the script afterwards), eventually it will seemingly cache that script at a certain point. When this happens you can run other scripts and it will still run the original one at the point that it was cached. Also changing the original script, after it seemed to cache it, will no longer have any effect. You can delete the entire contents of the script, save it, and it will still run in MicroMacro at the point it was cached. I'm using Ctrl + L to stop the scripts if that matters.

zer0
Posts: 213
Joined: Sat Feb 16, 2008 11:55 pm

Re: registerTimer() - How to call a class function

#8 Post by zer0 » Fri Nov 07, 2008 12:58 am

Ahh I get what ur saying now. I had some code which produced the same effect so I had to have the timer call a function, that in turn calls the class function.

I think this is because using self:some_function(), is actually just syntactic sugar for my_class.some_function(self), and the registerTimer function does not allow the passing of arguments. Elverion can u comfirm if this is correct?? ;)
Is there a way to pass arguments to the function being timed in registerTimer()?

User avatar
Administrator
Site Admin
Posts: 5307
Joined: Sat Jan 05, 2008 4:21 pm

Re: registerTimer() - How to call a class function

#9 Post by Administrator » Fri Nov 07, 2008 2:05 am

Ok, I looked into it. It seems the problem is because the function is not being called from the class itself. The 'best' way to go about resolving your problem here would be to do as follows:

Code: Select all

  registerTimer("test", secondsToTimer(1), function () myClass:func() end);
It simply creates a wrapping function to call instead of calling the class's function directly.

I'll look into rewriting the timer code (again) to see if I can get a simpler system that would allow for passing of arguments to the timed function.

Sgraffite
Posts: 38
Joined: Wed Jul 09, 2008 12:03 pm

Re: registerTimer() - How to call a class function

#10 Post by Sgraffite » Fri Nov 07, 2008 2:32 am

Awesome, that works great, thanks!

User avatar
Administrator
Site Admin
Posts: 5307
Joined: Sat Jan 05, 2008 4:21 pm

Re: registerTimer() - How to call a class function

#11 Post by Administrator » Fri Nov 07, 2008 3:12 am

I think this is because using self:some_function(), is actually just syntactic sugar for my_class.some_function(self), and the registerTimer function does not allow the passing of arguments. Elverion can u comfirm if this is correct?? ;)
Forgot to respond to this before. This is correct. Better than I could have stated, myself. As a work-around, you can pass 'self' into the function by yourself with the updated lib.lua. For example:

Code: Select all

Character = class();
function Character:init()
  self.HP = 100; -- initialize HP
end

function main()
  local myCharacter = class(Character);
  registerTimer("testing", secondsToTimer(1), myCharacter.init, myCharacter);
end
It's a silly example (why would you init more than once?), but you get the point. 'myCharacter' will be passed in as the hidden parameter 'self'. You can now pass unlimited* number of arguments to registerTimer, and they will all be sent to the resulting function call**.

Here's a better example:

Code: Select all

Character = class();
function Character:setName(name)
  self.name = name;
end

function Character:func(text)
  printf("Hello %s, my name is %s\n", text, self.name);
end


function main()
  local myClass = class(Character);
  myClass:setName("Bob");

  registerTimer("test", secondsToTimer(1), myClass.func, myClass, "Sally");

  while(true) do
    yrest(10);
  end
end
startMacro(main);


*Unlimited: at least until you reach a stack-limit. Nothing you need to worry about, though.
**Be aware that these values cannot be modified without re-calling registerTimer. For example:

Code: Select all

function timed(a)
  printf("A: %d\n", a);
end

function main()
  local num = 12;
  registerTimer("timed", secondsToTimer(1), timed, num);

  while(1) do
    yrest(100);
    num = num + 1;
  end
end
startMacro(main);
This will continue to print "A: 12" even though 'num' is constantly changing.
Attachments
lib.lua
Updated lib.lua
(14.28 KiB) Downloaded 133 times

Post Reply

Who is online

Users browsing this forum: No registered users and 12 guests