🎉 Celebrating 25 Years of GameDev.net! 🎉

Not many can claim 25 years on the Internet! Join us in celebrating this milestone. Learn more about our history, and thank you for being a part of our community!

Getting co-routines to work in Lua 5

Started by
8 comments, last by intransigent-seal 21 years, 1 month ago
I''m using Lua in a chatbot that I''m creating to be put in MUDs. It''s working well so far, but now I want to implement a GetLine function. My app connects to the target MUD, and loads in and executs a script file. Then, every time it receives a line from the MUD, it calls a function in the loaded script. This is fine for most things, but it would be very useful to be able to do it "the other way" as well, so I can have calls to a GetLine function in the script, which halts execution of the script until another line is received, and then resumes execution, and returns the line as the result of GetLine. I''ve tried using lua_yield, and lua_resume, but obviously I''m using them wrong, since it isn''t giving the result that I want.
  
// The C++ GetLine function:

int LF_GetLine(lua_State *L)
{
  Log("Suspending lua execution...");
  mWaitingForLine = true;
  return lua_yield(L, 0);
}

// The line handling function:

void script::HandleGetLine(std::string &line)
{
  if (mWaitingForLine)
  {
    Log("Line received, resuming execution...");
    lua_pushstring(mL, line.c_str());
    if (lua_resume(mL, 1) != 0)
      ErrorLog("Error resuming execution...");
    mWaitingForLine = false;
    return;
  }

  lua_pushstring(mL, "on_get_line");
  lua_rawget(mL, LUA_GLOBALSINDEX);
  lua_pushstring(mL, line.c_str());
  switch (lua_resume(mL, 1))
  {
    case LUA_ERRRUN:
      ErrorLog("Received ERRRUN when calling on_get_line");
      break;
    case 0:
      break;
    default:
      ErrorLog("Received an unknown error while calling on_get_line");
      break;
  }
}

// The Lua cmd_test function:

function cmd_test(user)
   Log("Waiting for line...")
   ln = GetLine()
   Log("Got a line (%s)", ln)
   Send(ln)
end

// What gets logged:

// 22/05/03 19:44:57 : Received: <johnb> @test

// 22/05/03 19:44:57 : Executing command: test called by user johnb

// 22/05/03 19:44:57 : Waiting for line...

// 22/05/03 19:44:57 : Suspending lua execution...

// 22/05/03 19:44:59 : Line received, resuming execution...

// 22/05/03 19:44:59 : Error resuming execution...

  
Any comments would be greatly appreciated, John B
The best thing about the internet is the way people with no experience or qualifications can pretend to be completely superior to other people who have no experience or qualifications.
Advertisement
After resume returns with an error, there should be an error message on the Lua stack. Log that and see what Lua''s error message is, maybe it can help say what is going wrong.
quote: Original post by Anonymous Poster
After resume returns with an error, there should be an error message on the Lua stack. Log that and see what Lua''s error message is, maybe it can help say what is going wrong.

OK, I''ve done that now. The error it returns is:
"cannot resume dead coroutine"

John B
The best thing about the internet is the way people with no experience or qualifications can pretend to be completely superior to other people who have no experience or qualifications.
Maybe Lua expects each coroutine to be created as a new thread. Try creating the coroutine as a new thread with lua_newthread.
Well, I''ve fixed the original problem (kind of - I still don''t know exactly why it wasn''t working, but I''ve replaced it with something that does work). Now I have a new problem though.

At the moment, I''m storing a list of commands in a configuration file. The file has the command name, description, and the name of the function that performs the command. When the driver script detects a command call, it finds the relevant item in the configuration file, and then uses the pcall function to execute the command function. I''m using pcall so that if I mess up one of the command functions, it will catch the error and send back an error message instead of just breaking. This is great, except that it seems that I can''t call a function that yields in code that''s being executed by pcall - which of course means it''s just as bad as it was before. I still can''t call GetLine in one of the command functions. I''ve got around it for now by not using pcall, and just calling the function directly, but if anyone knows a better way, that will let me execute the commands safely without stopping me from yielding the thread, then I''d appreciate it.

John B
The best thing about the internet is the way people with no experience or qualifications can pretend to be completely superior to other people who have no experience or qualifications.
Remember that function calls are different from resuming a coroutine. A coroutine has its own thread, a function call just takes place in the current thread.
quote: Original post by Anonymous Poster
Remember that function calls are different from resuming a coroutine. A coroutine has its own thread, a function call just takes place in the current thread.

I know that, but I don''t see how it affects what I''m doing.

John B
The best thing about the internet is the way people with no experience or qualifications can pretend to be completely superior to other people who have no experience or qualifications.
pcall a function that then calls the other function as a coroutine?
pcall is a protected call. It will catch any errors from the function you''re calling.

John B
The best thing about the internet is the way people with no experience or qualifications can pretend to be completely superior to other people who have no experience or qualifications.
I mean move the pcall higher up in your code, so you pcall a function that then calls the coroutine. When the coroutine yeilds, it returns control to the intermediate function which then returns to the function that called it as a pcall.

This topic is closed to new replies.

Advertisement