Browse Source

Switch to a custom event system, where SDL pumps into

To do this we needed to take ThreadVariant out of love.thread, and move it to common.
This also changes event names, instead of 1/2-letter abbreviations, full names!
Bart van Strien 13 years ago
parent
commit
083dd11185

+ 173 - 0
src/common/Variant.cpp

@@ -0,0 +1,173 @@
+/**
+* Copyright (c) 2006-2011 LOVE Development Team
+*
+* 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.
+**/
+
+#include "Variant.h"
+#include <common/StringMap.h>
+
+namespace love
+{
+	extern StringMap<Type, TYPE_MAX_ENUM> types;
+
+	love::Type extractudatatype(lua_State * L, int idx)
+	{
+		Type t = INVALID_ID;
+		if (!lua_isuserdata(L, idx))
+			return t;
+		if (luaL_getmetafield (L, idx, "__tostring") == 0)
+			return t;
+		lua_pushvalue(L, idx);
+		int result = lua_pcall(L, 1, 1, 0);
+		if (result == 0)
+			types.find(lua_tostring(L, -1), t);
+		if (result == 0 || result == LUA_ERRRUN)
+			lua_pop(L, 1);
+		return t;
+	}
+
+	Variant::Variant(bool boolean)
+	{
+		type = BOOLEAN;
+		data.boolean = boolean;
+	}
+
+	Variant::Variant(double number)
+	{
+		type = NUMBER;
+		data.number = number;
+	}
+
+	Variant::Variant(const char *string, size_t len)
+	{
+		type = STRING;
+		char *buf = new char[len+1];
+		memset(buf, 0, len+1);
+		memcpy(buf, string, len);
+		data.string.str = buf;
+		data.string.len = len;
+	}
+
+	Variant::Variant(char c)
+	{
+		type = CHARACTER;
+		data.character = c;
+	}
+
+	Variant::Variant(void *userdata)
+	{
+		type = LUSERDATA;
+		data.userdata = userdata;
+	}
+
+	Variant::Variant(love::Type udatatype, void *userdata)
+	{
+		type = FUSERDATA;
+		this->udatatype = udatatype;
+		if (udatatype != INVALID_ID)
+		{
+			Proxy *p = (Proxy *) userdata;
+			flags = p->flags;
+			data.userdata = p->data;
+			((love::Object *) data.userdata)->retain();
+		}
+		else
+			data.userdata = userdata;
+	}
+
+	Variant::~Variant()
+	{
+		switch(type)
+		{
+			case STRING:
+				delete[] data.string.str;
+				break;
+			case FUSERDATA:
+				((love::Object *) data.userdata)->release();
+				break;
+			default:
+				break;
+		}
+	}
+
+	Variant *Variant::fromLua(lua_State *L, int n)
+	{
+		Variant *v = NULL;
+		size_t len;
+		const char *str;
+		switch(lua_type(L, n))
+		{
+			case LUA_TBOOLEAN:
+				v = new Variant(luax_toboolean(L, n));
+				break;
+			case LUA_TNUMBER:
+				v = new Variant(lua_tonumber(L, n));
+				break;
+			case LUA_TSTRING:
+				str = lua_tolstring(L, n, &len);
+				v = new Variant(str, len);
+				break;
+			case LUA_TLIGHTUSERDATA:
+				v = new Variant(lua_touserdata(L, n));
+				break;
+			case LUA_TUSERDATA:
+				v = new Variant(extractudatatype(L, n), lua_touserdata(L, n));
+				break;
+		}
+		return v;
+	}
+
+	void Variant::toLua(lua_State *L)
+	{
+		switch(type)
+		{
+			case BOOLEAN:
+				lua_pushboolean(L, data.boolean);
+				break;
+			case CHARACTER:
+				lua_pushlstring(L, &data.character, 1);
+				break;
+			case NUMBER:
+				lua_pushnumber(L, data.number);
+				break;
+			case STRING:
+				lua_pushlstring(L, data.string.str, data.string.len);
+				break;
+			case LUSERDATA:
+				lua_pushlightuserdata(L, data.userdata);
+				break;
+			case FUSERDATA:
+				if (udatatype != INVALID_ID)
+				{
+					const char *name = NULL;
+					love::types.find(udatatype, name);
+					((love::Object *) data.userdata)->retain();
+					luax_newtype(L, name, flags, data.userdata);
+				}
+				else
+					lua_pushlightuserdata(L, data.userdata);
+				// I know this is not the same
+				// sadly, however, it's the most
+				// I can do (at the moment).
+				break;
+			default:
+				lua_pushnil(L);
+				break;
+		}
+	}
+} // love

+ 73 - 0
src/common/Variant.h

@@ -0,0 +1,73 @@
+/**
+* Copyright (c) 2006-2011 LOVE Development Team
+*
+* 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.
+**/
+
+#ifndef LOVE_VARIANT_H
+#define LOVE_VARIANT_H
+
+#include <common/runtime.h>
+#include <common/Object.h>
+
+#include <cstring>
+
+namespace love
+{
+	class Variant : public love::Object
+	{
+	private:
+		enum Type
+		{
+			UNKNOWN = 0,
+			BOOLEAN,
+			NUMBER,
+			CHARACTER,
+			STRING,
+			LUSERDATA,
+			FUSERDATA
+		} type;
+		union
+		{
+			bool boolean;
+			char character;
+			double number;
+			struct {
+				const char *str;
+				size_t len;
+			} string;
+			void *userdata;
+		} data;
+		love::Type udatatype;
+		bits flags;
+
+	public:
+		
+		Variant(bool boolean);
+		Variant(double number);
+		Variant(const char *string, size_t len);
+		Variant(char c);
+		Variant(void *userdata);
+		Variant(love::Type udatatype, void *userdata);
+		virtual ~Variant();
+
+		static Variant *fromLua(lua_State *L, int n);
+		void toLua(lua_State *L);
+	}; // Variant
+} // love
+
+#endif // LOVE_VARIANT_H

+ 51 - 18
src/modules/event/Event.cpp

@@ -24,18 +24,65 @@ namespace love
 {
 namespace event
 {
+	Message::Message(std::string name, int nargs, ...)
+		: name(name), nargs(nargs)
+	{
+		args = new Variant*[nargs];
+		va_list arg;
+		va_start(arg, nargs);
+		for (int i = 0; i < nargs; i++)
+		{
+			args[i] = va_arg(arg, Variant*);
+			args[i]->retain();
+		}
+		va_end(arg);
+	}
+
+	Message::~Message()
+	{
+		for (int i = 0; i < nargs; i++)
+			args[i]->release();
+	}
+
+	int Message::toLua(lua_State *L)
+	{
+		lua_pushstring(L, name.c_str());
+		for (int i = 0; i < nargs; i++)
+			args[i]->toLua(L);
+		return nargs+1;
+	}
+
+	Message *Message::fromLua(lua_State *L, int n)
+	{
+		std::string name = luaL_checkstring(L, n);
+		Message *m = new Message(name, 0);
+		int nargs = lua_gettop(L)-n;
+		delete[] m->args;
+		m->args = new Variant*[nargs];
+		for (int i = 0; i < nargs; i++)
+		{
+			m->args[i] = Variant::fromLua(L, n+i);
+		}
+		return m;
+	}
+
 	Event::~Event()
 	{
 	}
 
-	bool Event::getConstant(const char * in, Event::Type & out)
+	void Event::push(Message *msg)
 	{
-		return types.find(in, out);
+		msg->retain();
+		queue.push(msg);
 	}
 
-	bool Event::getConstant(Event::Type in, const char *& out)
+	bool Event::poll(Message *&msg)
 	{
-		return types.find(in, out);
+		if (queue.empty())
+			return false;
+		msg = queue.front();
+		queue.pop();
+		return true;
 	}
 
 	bool Event::getConstant(const char * in, love::mouse::Mouse::Button & out)
@@ -58,20 +105,6 @@ namespace event
 		return keys.find(in, out);
 	}
 
-	StringMap<Event::Type, Event::TYPE_MAX_ENUM>::Entry Event::typeEntries[] =
-	{
-		{"kp", Event::TYPE_KEY_PRESSED},
-		{"kr", Event::TYPE_KEY_RELEASED},
-		{"mp", Event::TYPE_MOUSE_PRESSED},
-		{"mr", Event::TYPE_MOUSE_RELEASED},
-		{"jp", Event::TYPE_JOYSTICK_PRESSED},
-		{"jr", Event::TYPE_JOYSTICK_RELEASED},
-		{"f", Event::TYPE_FOCUS},
-		{"q", Event::TYPE_QUIT},
-	};
-
-	StringMap<Event::Type, Event::TYPE_MAX_ENUM> Event::types(Event::typeEntries, sizeof(Event::typeEntries));
-
 	StringMap<love::mouse::Mouse::Button, love::mouse::Mouse::BUTTON_MAX_ENUM>::Entry Event::buttonEntries[] =
 	{
 		{"l", love::mouse::Mouse::BUTTON_LEFT},

+ 24 - 52
src/modules/event/Event.h

@@ -24,77 +24,49 @@
 // LOVE
 #include <common/Module.h>
 #include <common/StringMap.h>
+#include <common/Variant.h>
 #include <keyboard/Keyboard.h>
 #include <mouse/Mouse.h>
 
+// STL
+#include <queue>
+
 namespace love
 {
 namespace event
 {
-	class Event : public Module
+	class Message : public Object
 	{
-	public:
-
-		enum Type
-		{
-		   TYPE_INVALID,
-		   TYPE_KEY_PRESSED,
-		   TYPE_KEY_RELEASED,
-		   TYPE_MOUSE_PRESSED,
-		   TYPE_MOUSE_RELEASED,
-		   TYPE_JOYSTICK_RELEASED,
-		   TYPE_JOYSTICK_PRESSED,
-		   TYPE_FOCUS,
-		   TYPE_QUIT,
-		   TYPE_MAX_ENUM = 32
-		};
-
-		union Message
-		{
-			Type type;
+	private:
+		std::string name;
+		Variant **args;
+		int nargs;
 
-			struct
-			{
-				Type type;
-				love::mouse::Mouse::Button b;
-				unsigned x;
-				unsigned y;
-			} mouse;
+	public:
+		Message(std::string name, int nargs, ...);
+		~Message();
 
-			struct
-			{
-				Type type;
-				unsigned index;
-				unsigned button;
-			} joystick;
+		int toLua(lua_State *L);
+		static Message *fromLua(lua_State *L, int n);
+	};
 
-			struct
-			{
-				Type type;
-				love::keyboard::Keyboard::Key k;
-				unsigned short u;
-			} keyboard;
+	class Event : public Module
+	{
+	public:
+		virtual ~Event();
 
-			struct
-			{
-				Type type;
-				bool f;
-			} focus;
-		};
+		void push(Message *msg);
+		bool poll(Message *&msg);
 
-		virtual ~Event();
+		virtual void pump() = 0;
 
-		static bool getConstant(const char * in, Type & out);
-		static bool getConstant(Type in, const char *& out);
 		static bool getConstant(const char * in, love::mouse::Mouse::Button & out);
 		static bool getConstant(love::mouse::Mouse::Button in, const char *& out);
 		static bool getConstant(const char * in, love::keyboard::Keyboard::Key & out);
 		static bool getConstant(love::keyboard::Keyboard::Key in, const char *& out);
 
-	private:
-
-		static StringMap<Type, TYPE_MAX_ENUM>::Entry typeEntries[];
-		static StringMap<Type, TYPE_MAX_ENUM> types;
+	protected:
+		std::queue<Message*> queue;
 		static StringMap<love::mouse::Mouse::Button, love::mouse::Mouse::BUTTON_MAX_ENUM>::Entry buttonEntries[];
 		static StringMap<love::mouse::Mouse::Button, love::mouse::Mouse::BUTTON_MAX_ENUM> buttons;
 		static StringMap<love::keyboard::Keyboard::Key, love::keyboard::Keyboard::KEY_MAX_ENUM>::Entry keyEntries[];

+ 68 - 78
src/modules/event/sdl/Event.cpp

@@ -42,35 +42,30 @@ namespace sdl
 	void Event::pump()
 	{
 		SDL_PumpEvents();
-	}
 
-	bool Event::poll(Message & message)
-	{
 		static SDL_Event e;
-
 		SDL_EnableUNICODE(1);
 
+		Message *msg;
+
 		while (SDL_PollEvent(&e))
 		{
-			if (convert(e, message))
-				return true;
+			msg = convert(e);
+			if (msg)
+			{
+				push(msg);
+				msg->release();
+			}
 		}
-
-		return false;
 	}
 
-	bool Event::wait(Message & message)
+	Message *Event::wait()
 	{
 		static SDL_Event e;
 		bool ok = (SDL_WaitEvent(&e) == 1);
-		return ok && convert(e, message);
-	}
-
-	bool Event::push(Message & message)
-	{
-		static SDL_Event e;
-		bool ok = convert(message, e);
-		return ok && (SDL_PushEvent(&e) == 0);
+		if (!ok)
+			return NULL;
+		return convert(e);
 	}
 
 	void Event::clear()
@@ -81,83 +76,78 @@ namespace sdl
 		{
 			// Do nothing with 'e' ...
 		}
+
+		while (!queue.empty())
+		{
+			queue.back()->release();
+			queue.pop();
+		}
 	}
 
-	bool Event::convert(SDL_Event & e, Message & m)
+	Message *Event::convert(SDL_Event & e)
 	{
+		Message *msg = NULL;
+		love::keyboard::Keyboard::Key key;
+		love::mouse::Mouse::Button button;
+		Variant *arg1, *arg2, *arg3;
+		const char *txt;
 		switch(e.type)
 		{
 		case SDL_KEYDOWN:
-			m.type = Event::TYPE_KEY_PRESSED;
-			m.keyboard.u = e.key.keysym.unicode;
-			return keys.find(e.key.keysym.sym, m.keyboard.k);
+			if (keys.find(e.key.keysym.sym, key) && love::event::Event::keys.find(key, txt))
+			{
+				arg1 = new Variant(txt, strlen(txt));
+				arg2 = new Variant((double) e.key.keysym.unicode);
+				msg = new Message("keypressed", 2, arg1, arg2);
+				arg1->release();
+				arg2->release();
+			}
+			break;
 		case SDL_KEYUP:
-			m.type = Event::TYPE_KEY_RELEASED;
-			return keys.find(e.key.keysym.sym, m.keyboard.k);
+			if (keys.find(e.key.keysym.sym, key) && love::event::Event::keys.find(key, txt))
+			{
+				arg1 = new Variant(txt, strlen(txt));
+				msg = new Message("keyreleased", 1, arg1);
+				arg1->release();
+			}
+			break;
 		case SDL_MOUSEBUTTONDOWN:
 		case SDL_MOUSEBUTTONUP:
-			m.type = (e.type == SDL_MOUSEBUTTONDOWN) ? Event::TYPE_MOUSE_PRESSED : Event::TYPE_MOUSE_RELEASED;
-			m.mouse.x = e.button.x;
-			m.mouse.y = e.button.y;
-			return buttons.find(e.button.button, m.mouse.b);
+			if (buttons.find(e.button.button, button) && love::event::Event::buttons.find(button, txt))
+			{
+				arg1 = new Variant((double) e.button.x);
+				arg2 = new Variant((double) e.button.y);
+				arg3 = new Variant(txt, strlen(txt));
+				msg = new Message((e.type == SDL_MOUSEBUTTONDOWN) ?
+						"mousepressed" : "mousereleased", 3,
+						arg1, arg2, arg3);
+				arg1->release();
+				arg2->release();
+				arg3->release();
+			}
+			break;
 		case SDL_JOYBUTTONDOWN:
 		case SDL_JOYBUTTONUP:
-			m.type = (e.type == SDL_JOYBUTTONDOWN) ? Event::TYPE_JOYSTICK_PRESSED : Event::TYPE_JOYSTICK_RELEASED;
-			m.joystick.button = e.jbutton.button;
-			m.joystick.index = e.jbutton.which;
-			return true;
+			arg1 = new Variant((double) (e.jbutton.which+1));
+			arg2 = new Variant((double) (e.jbutton.button+1));
+			msg = new Message((e.type == SDL_JOYBUTTONDOWN) ?
+					"joystickpressed" : "joystickreleased", 2,
+					arg1, arg2);
+			arg1->release();
+			arg2->release();
+			break;
 		case SDL_ACTIVEEVENT:
+			arg1 = new Variant(e.active.gain != 0);
 			if (e.active.state & SDL_APPINPUTFOCUS)
-			{
-				m.type = Event::TYPE_FOCUS;
-				m.focus.f = (e.active.gain != 0);
-				return true;
-			}
-			else
-				break;
+				msg = new Message("focus", 1, arg1);
+			arg1->release();
+			break;
 		case SDL_QUIT:
-			m.type = Event::TYPE_QUIT;
-			return true;
-		}
-
-		return false;
-	}
-
-	bool Event::convert(Message & m, SDL_Event & e)
-	{
-		switch(m.type)
-		{
-		case Event::TYPE_KEY_PRESSED:
-			e.type = SDL_KEYDOWN;
-			e.key.keysym.unicode = (Uint16)m.keyboard.u;
-			return keys.find(m.keyboard.k, e.key.keysym.sym);
-		case Event::TYPE_KEY_RELEASED:
-			e.type = SDL_KEYUP;
-			return keys.find(m.keyboard.k, e.key.keysym.sym);
-		case Event::TYPE_MOUSE_PRESSED:
-		case Event::TYPE_MOUSE_RELEASED:
-			e.type = (m.type == Event::TYPE_MOUSE_PRESSED) ? SDL_MOUSEBUTTONDOWN : SDL_MOUSEBUTTONUP;
-			e.button.x = m.mouse.x;
-			e.button.y = m.mouse.y;
-			return buttons.find(m.mouse.b, e.button.button);
-		case Event::TYPE_JOYSTICK_PRESSED:
-		case Event::TYPE_JOYSTICK_RELEASED:
-			e.type = (m.type == Event::TYPE_JOYSTICK_PRESSED) ? SDL_JOYBUTTONDOWN : SDL_JOYBUTTONUP;
-			e.jbutton.which = m.joystick.index;
-			e.jbutton.button = m.joystick.button;
-			return true;
-		case Event::TYPE_FOCUS:
-			e.type = SDL_ACTIVEEVENT;
-			e.active.state = SDL_APPINPUTFOCUS;
-			e.active.gain = m.focus.f;
-		case Event::TYPE_QUIT:
-			e.type = SDL_QUIT;
-			return true;
-		default:
-			return true;
+			msg = new Message("quit", 0);
+			break;
 		}
 
-		return true;
+		return msg;
 	}
 
 	EnumMap<love::keyboard::Keyboard::Key, SDLKey, love::keyboard::Keyboard::KEY_MAX_ENUM>::Entry Event::keyEntries[] =

+ 2 - 19
src/modules/event/sdl/Event.h

@@ -51,28 +51,12 @@ namespace sdl
 		**/
 		void pump();
 
-		/**
-		* Checks if there are messages in the queue.
-		*
-		* @param message The next message in the queue, if the return value is true.
-		* @return True if there a message was found, false otherwise.
-		**/
-		bool poll(Message & message);
-
 		/**
 		* Waits for the next event (indefinitely). Useful for creating games where
 		* the screen and game state only needs updating when the user interacts with
 		* the window.
 		**/
-		bool wait(Message & message);
-
-		/**
-		* Push a message onto the event queue.
-		*
-		* @param message The message to push onto the queue.
-		* @return True on success, false if the queue was full.
-		**/
-		bool push(Message & message);
+		Message *wait();
 
 		/**
 		 * Clears the event queue.
@@ -81,8 +65,7 @@ namespace sdl
 
 	private:
 
-		bool convert(SDL_Event & e, Message & m);
-		bool convert(Message & m, SDL_Event & e);
+		Message *convert(SDL_Event & e);
 
 		static EnumMap<love::keyboard::Keyboard::Key, SDLKey, love::keyboard::Keyboard::KEY_MAX_ENUM>::Entry keyEntries[];
 		static EnumMap<love::keyboard::Keyboard::Key, SDLKey, love::keyboard::Keyboard::KEY_MAX_ENUM> keys;

+ 16 - 103
src/modules/event/sdl/wrap_Event.cpp

@@ -34,104 +34,15 @@ namespace sdl
 {
 	static Event * instance = 0;
 
-	static bool to_message(lua_State * L, Event::Message & msg)
-	{
-		const char * str = luaL_checkstring(L, 1);
-
-		if (!Event::getConstant(str, msg.type))
-			return false;
-
-		switch(msg.type)
-		{
-		case Event::TYPE_KEY_PRESSED:
-			if (!Event::getConstant(luaL_checkstring(L, 2), msg.keyboard.k))
-				return false;
-			msg.keyboard.u = (unsigned short)luaL_optint(L, 3, 0);
-			return true;
-		case Event::TYPE_KEY_RELEASED:
-			if (!Event::getConstant(luaL_checkstring(L, 2), msg.keyboard.k))
-				return false;
-			return true;
-		case Event::TYPE_MOUSE_PRESSED:
-		case Event::TYPE_MOUSE_RELEASED:
-			if (!Event::getConstant(luaL_checkstring(L, 2), msg.mouse.b))
-				return false;
-			msg.mouse.x = luaL_checkint(L, 3);
-			msg.mouse.y = luaL_checkint(L, 4);
-			return true;
-		case Event::TYPE_JOYSTICK_PRESSED:
-		case Event::TYPE_JOYSTICK_RELEASED:
-			msg.joystick.index = luaL_checkint(L, 2);
-			msg.joystick.button = luaL_checkint(L, 3);
-			return true;
-		case Event::TYPE_FOCUS:
-			msg.focus.f = luax_toboolean(L, 2);
-			return true;
-		case Event::TYPE_QUIT:
-			return true;
-		default:
-			return false;
-		}
-
-		return false;
-	}
-
-	static int push_message(lua_State * L, const Event::Message & msg)
-	{
-		const char * str = 0;
-
-		if (!Event::getConstant(msg.type, str))
-			return 0;
-
-		lua_pushstring(L, str);
-
-		switch(msg.type)
-		{
-		case Event::TYPE_KEY_PRESSED:
-			if (!Event::getConstant(msg.keyboard.k, str))
-				return 0;
-			lua_pushstring(L, str);
-			lua_pushinteger(L, msg.keyboard.u);
-			return 3;
-		case Event::TYPE_KEY_RELEASED:
-			if (!Event::getConstant(msg.keyboard.k, str))
-				return 0;
-			lua_pushstring(L, str);
-			return 2;
-		case Event::TYPE_MOUSE_PRESSED:
-		case Event::TYPE_MOUSE_RELEASED:
-			if (!Event::getConstant(msg.mouse.b, str))
-				return 0;
-			lua_pushinteger(L, msg.mouse.x);
-			lua_pushinteger(L, msg.mouse.y);
-			lua_pushstring(L, str);
-			return 4;
-		case Event::TYPE_JOYSTICK_PRESSED:
-		case Event::TYPE_JOYSTICK_RELEASED:
-			lua_pushinteger(L, msg.joystick.index+1);
-			lua_pushinteger(L, msg.joystick.button+1);
-			return 3;
-		case Event::TYPE_FOCUS:
-			lua_pushboolean(L, msg.focus.f);
-			return 2;
-		case Event::TYPE_QUIT:
-			return 1;
-		default:
-			return 0;
-		}
-
-		return 0;
-	}
-
 	static int poll_i(lua_State * L)
 	{
-		static Event::Message m;
+		Message *m;
 
 		while (instance->poll(m))
 		{
-			int args = push_message(L, m);
-			if (args > 0)
-				return args;
+			int args = m->toLua(L);
+			m->release();
+			return args;
 		}
 
 		// No pending events.
@@ -152,11 +63,13 @@ namespace sdl
 
 	int w_wait(lua_State * L)
 	{
-		static Event::Message m;
+		static Message *m;
 
-		if (instance->wait(m))
+		if ((m = instance->wait()))
 		{
-			return push_message(L, m);
+			int args = m->toLua(L);
+			m->release();
+			return args;
 		}
 
 		return 0;
@@ -164,17 +77,18 @@ namespace sdl
 
 	int w_push(lua_State * L)
 	{
-		static Event::Message m;
+		static Message *m;
 
-		if (!to_message(L, m))
+		if (!(m = Message::fromLua(L, 1)))
 		{
 			luax_pushboolean(L, false);
 			return 1;
 		}
 
-		luax_pushboolean(L, instance->push(m));
+		instance->push(m);
+		m->release();
 
-		return 1;
+		return 0;
 	}
 
 	int w_clear(lua_State *)
@@ -185,9 +99,8 @@ namespace sdl
 
 	int w_quit(lua_State * L)
 	{
-		static Event::Message m;
-		m.type = Event::TYPE_QUIT;
-		luax_pushboolean(L, instance->push(m));
+		Message *m = new Message("quit", 0);
+		instance->push(m);
 		return 1;
 	}
 

+ 9 - 68
src/modules/thread/Thread.cpp

@@ -59,7 +59,7 @@ namespace thread
 		{
 			{
 				Lock lock((Mutex*) comm->mutex);
-				ThreadVariant *v = new ThreadVariant(lua_tostring(L, -1), lua_strlen(L, -1));
+				Variant *v = new Variant(lua_tostring(L, -1), lua_strlen(L, -1));
 				comm->setValue("error", v);
 				v->release();
 			}
@@ -68,65 +68,6 @@ namespace thread
 		lua_close(L);
 	}
 
-
-	ThreadVariant::ThreadVariant(bool boolean)
-	{
-		type = BOOLEAN;
-		data.boolean = boolean;
-	}
-
-	ThreadVariant::ThreadVariant(double number)
-	{
-		type = NUMBER;
-		data.number = number;
-	}
-
-	ThreadVariant::ThreadVariant(const char *string, size_t len)
-	{
-		type = STRING;
-		char *buf = new char[len+1];
-		memset(buf, 0, len+1);
-		memcpy(buf, string, len);
-		data.string.str = buf;
-		data.string.len = len;
-	}
-
-	ThreadVariant::ThreadVariant(void *userdata)
-	{
-		type = LUSERDATA;
-		data.userdata = userdata;
-	}
-
-	ThreadVariant::ThreadVariant(Type udatatype, void *userdata)
-	{
-		type = FUSERDATA;
-		this->udatatype = udatatype;
-		if (udatatype != INVALID_ID)
-		{
-			Proxy *p = (Proxy *) userdata;
-			flags = p->flags;
-			data.userdata = p->data;
-			((love::Object *) data.userdata)->retain();
-		}
-		else
-			data.userdata = userdata;
-	}
-
-	ThreadVariant::~ThreadVariant()
-	{
-		switch(type)
-		{
-			case STRING:
-				delete[] data.string.str;
-				break;
-			case FUSERDATA:
-				((love::Object *) data.userdata)->release();
-				break;
-			default:
-				break;
-		}
-	}
-
 	ThreadData::ThreadData(const char *name, size_t len, const char *code, void *mutex, void *cond)
 		: len(len), mutex(mutex), cond(cond)
 	{
@@ -162,7 +103,7 @@ namespace thread
 		return name;
 	}
 
-	ThreadVariant* ThreadData::getValue(const std::string & name)
+	Variant* ThreadData::getValue(const std::string & name)
 	{
 		if (shared.count(name) == 0)
 			return 0;
@@ -177,7 +118,7 @@ namespace thread
 		shared.erase(name);
 	}
 
-	void ThreadData::setValue(const std::string & name, ThreadVariant *v)
+	void ThreadData::setValue(const std::string & name, Variant *v)
 	{
 		if (shared.count(name) != 0)
 			shared[name]->release();
@@ -188,7 +129,7 @@ namespace thread
 	std::vector<std::string> ThreadData::getKeys()
 	{
 		std::vector<std::string> keys;
-		for (std::map<std::string, ThreadVariant*>::iterator it = shared.begin(); it != shared.end(); it++)
+		for (std::map<std::string, Variant*>::iterator it = shared.begin(); it != shared.end(); it++)
 		{
 			keys.push_back(it->first);
 		}
@@ -273,9 +214,9 @@ namespace thread
 		return name;
 	}
 
-	ThreadVariant *Thread::get(const std::string & name)
+	Variant *Thread::get(const std::string & name)
 	{
-		ThreadVariant *v = comm->getValue(name);
+		Variant *v = comm->getValue(name);
 		if (v)
 			v->retain();
 		return v;
@@ -286,9 +227,9 @@ namespace thread
 		return comm->getKeys();
 	}
 
-	ThreadVariant *Thread::demand(const std::string & name)
+	Variant *Thread::demand(const std::string & name)
 	{
-		ThreadVariant *v = comm->getValue(name);
+		Variant *v = comm->getValue(name);
 		while (!v)
 		{
 			if (comm->getValue("error"))
@@ -305,7 +246,7 @@ namespace thread
 		comm->clearValue(name);
 	}
 
-	void Thread::set(const std::string & name, ThreadVariant *v)
+	void Thread::set(const std::string & name, Variant *v)
 	{
 		lock(); //this function explicitly locks
 		comm->setValue(name, v); //because we need

+ 7 - 41
src/modules/thread/Thread.h

@@ -31,9 +31,9 @@
 #include <filesystem/File.h>
 #include <common/runtime.h>
 #include <common/Module.h>
+#include <common/Variant.h>
 #include <thread/threads.h>
 
-
 namespace love
 {
 namespace thread
@@ -41,46 +41,12 @@ namespace thread
 
 	class ThreadModule;
 
-	enum ThreadVariantType
-	{
-		UNKNOWN = 0,
-		BOOLEAN,
-		NUMBER,
-		STRING,
-		LUSERDATA,
-		FUSERDATA
-	};
-
-	class ThreadVariant : public love::Object
-	{
-	public:
-		ThreadVariant(bool boolean);
-		ThreadVariant(double number);
-		ThreadVariant(const char *string, size_t len);
-		ThreadVariant(void *userdata);
-		ThreadVariant(Type udatatype, void *userdata);
-		virtual ~ThreadVariant();
-		ThreadVariantType type;
-		union
-		{
-			bool boolean;
-			double number;
-			struct {
-				const char *str;
-				size_t len;
-			} string;
-			void *userdata;
-		} data;
-		Type udatatype;
-		bits flags;
-	};
-
 	class ThreadData
 	{
 	private:
 		char *code;
 		char *name;
-		std::map<std::string, ThreadVariant*> shared;
+		std::map<std::string, Variant*> shared;
 		size_t len;
 
 	public:
@@ -88,9 +54,9 @@ namespace thread
 		~ThreadData();
 		const char *getCode();
 		const char *getName(size_t *len = 0);
-		ThreadVariant* getValue(const std::string & name);
+		Variant* getValue(const std::string & name);
 		void clearValue(const std::string & name);
-		void setValue(const std::string & name, ThreadVariant *v);
+		void setValue(const std::string & name, Variant *v);
 		std::vector<std::string> getKeys();
 
 		void *mutex;
@@ -130,11 +96,11 @@ namespace thread
 		void kill();
 		void wait();
 		std::string getName();
-		ThreadVariant *get(const std::string & name);
+		Variant *get(const std::string & name);
 		std::vector<std::string> getKeys();
-		ThreadVariant *demand(const std::string & name);
+		Variant *demand(const std::string & name);
 		void clear(const std::string & name);
-		void set(const std::string & name, ThreadVariant *v);
+		void set(const std::string & name, Variant *v);
 		void lock();
 		void unlock();
 	}; // Thread

+ 21 - 86
src/modules/thread/wrap_Thread.cpp

@@ -58,58 +58,21 @@ namespace thread
 		return 1;
 	}
 
-	bool __pushThreadVariant(lua_State *L, ThreadVariant *v)
-	{
-		if (!v)
-		{
-			lua_pushnil(L);
-			return false;
-		}
-		switch(v->type)
-		{
-			case BOOLEAN:
-				lua_pushboolean(L, v->data.boolean);
-				break;
-			case NUMBER:
-				lua_pushnumber(L, v->data.number);
-				break;
-			case STRING:
-				lua_pushlstring(L, v->data.string.str, v->data.string.len);
-				break;
-			case LUSERDATA:
-				lua_pushlightuserdata(L, v->data.userdata);
-				break;
-			case FUSERDATA:
-				if (v->udatatype != INVALID_ID)
-				{
-					const char *name = NULL;
-					love::types.find(v->udatatype, name);
-					((love::Object *) v->data.userdata)->retain();
-					luax_newtype(L, name, v->flags, v->data.userdata);
-				}
-				else
-					lua_pushlightuserdata(L, v->data.userdata);
-				// I know this is not the same
-				// sadly, however, it's the most
-				// I can do (at the moment).
-				break;
-			default:
-				lua_pushnil(L);
-				break;
-		}
-		return true;
-	}
 
 	int w_Thread_get(lua_State *L)
 	{
 		Thread *t = luax_checkthread(L, 1);
 		std::string name = luax_checkstring(L, 2);
 		t->lock();
-		ThreadVariant *v = t->get(name);
+		Variant *v = t->get(name);
 		t->clear(name);
 		t->unlock();
-		if (!__pushThreadVariant(L, v))
+		if (!v)
+		{
+			lua_pushnil(L);
 			return 1;
+		}
+		v->toLua(L);
 		t->lock();
 		v->release();
 		t->unlock();
@@ -138,11 +101,15 @@ namespace thread
 		Thread *t = luax_checkthread(L, 1);
 		std::string name = luax_checkstring(L, 2);
 		t->lock();
-		ThreadVariant *v = t->demand(name);
+		Variant *v = t->demand(name);
 		t->clear(name);
 		t->unlock();
-		if (!__pushThreadVariant(L, v))
+		if (!v)
+		{
+			lua_pushnil(L);
 			return 1;
+		}
+		v->toLua(L);
 		t->lock();
 		v->release();
 		t->unlock();
@@ -154,60 +121,28 @@ namespace thread
 		Thread *t = luax_checkthread(L, 1);
 		std::string name = luax_checkstring(L, 2);
 		t->lock();
-		ThreadVariant *v = t->get(name);
+		Variant *v = t->get(name);
 		t->unlock();
-		if (!__pushThreadVariant(L, v))
+		if (!v)
+		{
+			lua_pushnil(L);
 			return 1;
+		}
+		v->toLua(L);
 		t->lock();
 		v->release();
 		t->unlock();
 		return 1;
 	}
 
-	Type extractudatatype(lua_State * L, int idx)
-        {
-                Type t = INVALID_ID;
-                if (!lua_isuserdata(L, idx))
-                        return t;
-                if (luaL_getmetafield (L, idx, "__tostring") == 0)
-                        return t;
-                lua_pushvalue(L, idx);
-                int result = lua_pcall(L, 1, 1, 0);
-                if (result == 0)
-                        types.find(lua_tostring(L, -1), t);
-                if (result == 0 || result == LUA_ERRRUN)
-                        lua_pop(L, 1);
-                return t;
-        }
 
 	int w_Thread_set(lua_State *L)
 	{
 		Thread *t = luax_checkthread(L, 1);
 		std::string name = luax_checkstring(L, 2);
-		ThreadVariant *v;
-		size_t len;
-		const char *str;
-		switch(lua_type(L, 3))
-		{
-			case LUA_TBOOLEAN:
-				v = new ThreadVariant(luax_toboolean(L, 3));
-				break;
-			case LUA_TNUMBER:
-				v = new ThreadVariant(lua_tonumber(L, 3));
-				break;
-			case LUA_TSTRING:
-				str = lua_tolstring(L, 3, &len);
-				v = new ThreadVariant(str, len);
-				break;
-			case LUA_TLIGHTUSERDATA:
-				v = new ThreadVariant(lua_touserdata(L, 3));
-				break;
-			case LUA_TUSERDATA:
-				v = new ThreadVariant(extractudatatype(L, 3), lua_touserdata(L, 3));
-				break;
-			default:
-				return luaL_error(L, "Expected boolean, number, string or userdata");
-		}
+		Variant *v = Variant::fromLua(L, 3);
+		if (!v)
+			return luaL_error(L, "Expected boolean, number, string or userdata");
 		t->set(name, v);
 		t->lock();
 		v->release();

+ 0 - 1
src/modules/thread/wrap_Thread.h

@@ -27,7 +27,6 @@
 
 namespace love
 {
-	extern StringMap<Type, TYPE_MAX_ENUM> types;
 namespace thread
 {
 	Thread *luax_checkthread(lua_State *L, int idx);

+ 21 - 16
src/scripts/boot.lua

@@ -153,32 +153,36 @@ end
 function love.createhandlers()
 
 	-- Standard callback handlers.
-	love.handlers = {
-		kp = function (b, u)
+	love.handlers = setmetatable({
+		keypressed = function (b, u)
 			if love.keypressed then love.keypressed(b, u) end
 		end,
-		kr = function (b)
+		keyreleased = function (b)
 			if love.keyreleased then love.keyreleased(b) end
 		end,
-		mp = function (x,y,b)
+		mousepressed = function (x,y,b)
 			if love.mousepressed then love.mousepressed(x,y,b) end
 		end,
-		mr = function (x,y,b)
+		mousereleased = function (x,y,b)
 			if love.mousereleased then love.mousereleased(x,y,b) end
 		end,
-		jp = function (j,b)
+		joypressed = function (j,b)
 			if love.joystickpressed then love.joystickpressed(j,b) end
 		end,
-		jr = function (j,b)
+		joyrreleased = function (j,b)
 			if love.joystickreleased then love.joystickreleased(j,b) end
 		end,
-		f = function (f)
+		focus = function (f)
 			if love.focus then love.focus(f) end
 		end,
-		q = function ()
+		quit = function ()
 			return
 		end,
-	}
+	}, {
+		__index = function(self, name)
+			error("Unknown event: " .. name)
+		end,
+	})
 
 end
 
@@ -375,8 +379,9 @@ function love.run()
 	while true do
 		-- Process events.
 		if love.event then
+			love.event.pump()
 			for e,a,b,c in love.event.poll() do
-				if e == "q" then
+				if e == "quit" then
 					if not love.quit or not love.quit() then
 						if love.audio then
 							love.audio.stop()
@@ -647,7 +652,7 @@ function love.nogame()
 	
 	function love.keyreleased(key)
 		if key == "escape" then
-			love.event.push("q")
+			love.event.quit()
 		end
 	end
 
@@ -721,10 +726,10 @@ function love.errhand(msg)
 	while true do
 		e, a, b, c = love.event.wait()
 
-		if e == "q" then
+		if e == "quit" then
 			return
 		end
-		if e == "kp" and a == "escape" then
+		if e == "keypressed" and a == "escape" then
 			return
 		end
 
@@ -771,10 +776,10 @@ function love.releaseerrhand(msg)
 	while true do
 		e, a, b, c = love.event.wait()
 
-		if e == "q" then
+		if e == "quit" then
 			return
 		end
-		if e == "kp" and a == "escape" then
+		if e == "keypressed" and a == "escape" then
 			return
 		end
 

+ 41 - 28
src/scripts/boot.lua.h

@@ -256,56 +256,65 @@ const unsigned char boot_lua[] =
 	0x74, 0x65, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x73, 0x28, 0x29, 0x0a,0x0a,
 	0x09, 0x2d, 0x2d, 0x20, 0x53, 0x74, 0x61, 0x6e, 0x64, 0x61, 0x72, 0x64, 0x20, 0x63, 0x61, 0x6c, 0x6c, 0x62, 
 	0x61, 0x63, 0x6b, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x73, 0x2e, 0x0a,
-	0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x0a,
-	0x09, 0x09, 0x6b, 0x70, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x62, 
-	0x2c, 0x20, 0x75, 0x29, 0x0a,
+	0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x73, 0x20, 0x3d, 0x20, 0x73, 
+	0x65, 0x74, 0x6d, 0x65, 0x74, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x28, 0x7b, 0x0a,
+	0x09, 0x09, 0x6b, 0x65, 0x79, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 
+	0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x62, 0x2c, 0x20, 0x75, 0x29, 0x0a,
 	0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x70, 0x72, 0x65, 0x73, 
 	0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x70, 
 	0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x28, 0x62, 0x2c, 0x20, 0x75, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
 	0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a,
-	0x09, 0x09, 0x6b, 0x72, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x62, 
-	0x29, 0x0a,
+	0x09, 0x09, 0x6b, 0x65, 0x79, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x75, 
+	0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x62, 0x29, 0x0a,
 	0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6b, 0x65, 0x79, 0x72, 0x65, 0x6c, 0x65, 
 	0x61, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6b, 0x65, 0x79, 
 	0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x28, 0x62, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
 	0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a,
-	0x09, 0x09, 0x6d, 0x70, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 
-	0x2c, 0x79, 0x2c, 0x62, 0x29, 0x0a,
+	0x09, 0x09, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 
+	0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x62, 0x29, 0x0a,
 	0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x70, 0x72, 
 	0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6d, 0x6f, 
 	0x75, 0x73, 0x65, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x62, 0x29, 0x20, 
 	0x65, 0x6e, 0x64, 0x0a,
 	0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a,
-	0x09, 0x09, 0x6d, 0x72, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 
-	0x2c, 0x79, 0x2c, 0x62, 0x29, 0x0a,
+	0x09, 0x09, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 
+	0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x62, 0x29, 0x0a,
 	0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6d, 0x6f, 0x75, 0x73, 0x65, 0x72, 0x65, 
 	0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6d, 
 	0x6f, 0x75, 0x73, 0x65, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x28, 0x78, 0x2c, 0x79, 0x2c, 0x62, 
 	0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
 	0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a,
-	0x09, 0x09, 0x6a, 0x70, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x6a, 
-	0x2c, 0x62, 0x29, 0x0a,
+	0x09, 0x09, 0x6a, 0x6f, 0x79, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 
+	0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x6a, 0x2c, 0x62, 0x29, 0x0a,
 	0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 
 	0x6b, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 
 	0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x70, 0x72, 0x65, 0x73, 0x73, 0x65, 0x64, 0x28, 0x6a, 
 	0x2c, 0x62, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
 	0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a,
-	0x09, 0x09, 0x6a, 0x72, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x6a, 
-	0x2c, 0x62, 0x29, 0x0a,
+	0x09, 0x09, 0x6a, 0x6f, 0x79, 0x72, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x3d, 0x20, 0x66, 
+	0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x6a, 0x2c, 0x62, 0x29, 0x0a,
 	0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 
 	0x6b, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 
 	0x65, 0x2e, 0x6a, 0x6f, 0x79, 0x73, 0x74, 0x69, 0x63, 0x6b, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 
 	0x28, 0x6a, 0x2c, 0x62, 0x29, 0x20, 0x65, 0x6e, 0x64, 0x0a,
 	0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a,
-	0x09, 0x09, 0x66, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x66, 0x29, 0x0a,
+	0x09, 0x09, 0x66, 0x6f, 0x63, 0x75, 0x73, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 
+	0x20, 0x28, 0x66, 0x29, 0x0a,
 	0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x6f, 0x63, 0x75, 0x73, 0x20, 0x74, 
 	0x68, 0x65, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x66, 0x6f, 0x63, 0x75, 0x73, 0x28, 0x66, 0x29, 0x20, 
 	0x65, 0x6e, 0x64, 0x0a,
 	0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a,
-	0x09, 0x09, 0x71, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x28, 0x29, 0x0a,
+	0x09, 0x09, 0x71, 0x75, 0x69, 0x74, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 
+	0x28, 0x29, 0x0a,
 	0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x0a,
 	0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a,
-	0x09, 0x7d, 0x0a,0x0a,
+	0x09, 0x7d, 0x2c, 0x20, 0x7b, 0x0a,
+	0x09, 0x09, 0x5f, 0x5f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x20, 0x3d, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 
+	0x6f, 0x6e, 0x28, 0x73, 0x65, 0x6c, 0x66, 0x2c, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a,
+	0x09, 0x09, 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x28, 0x22, 0x55, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x20, 
+	0x65, 0x76, 0x65, 0x6e, 0x74, 0x3a, 0x20, 0x22, 0x20, 0x2e, 0x2e, 0x20, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x0a,
+	0x09, 0x09, 0x65, 0x6e, 0x64, 0x2c, 0x0a,
+	0x09, 0x7d, 0x29, 0x0a,0x0a,
 	0x65, 0x6e, 0x64, 0x0a,0x0a,
 	0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x69, 0x73, 0x5f, 0x66, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x67, 0x61, 0x6d, 
 	0x65, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x0a,0x0a,
@@ -641,11 +650,13 @@ const unsigned char boot_lua[] =
 	0x73, 0x2e, 0x0a,
 	0x09, 0x09, 0x69, 0x66, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x74, 0x68, 
 	0x65, 0x6e, 0x0a,
+	0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x75, 0x6d, 0x70, 
+	0x28, 0x29, 0x0a,
 	0x09, 0x09, 0x09, 0x66, 0x6f, 0x72, 0x20, 0x65, 0x2c, 0x61, 0x2c, 0x62, 0x2c, 0x63, 0x20, 0x69, 0x6e, 0x20, 
 	0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x6f, 0x6c, 0x6c, 0x28, 0x29, 0x20, 
 	0x64, 0x6f, 0x0a,
-	0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x71, 0x22, 0x20, 0x74, 0x68, 
-	0x65, 0x6e, 0x0a,
+	0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x71, 0x75, 0x69, 0x74, 0x22, 
+	0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
 	0x09, 0x09, 0x09, 0x09, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x71, 
 	0x75, 0x69, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x71, 0x75, 
 	0x69, 0x74, 0x28, 0x29, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
@@ -1605,8 +1616,8 @@ const unsigned char boot_lua[] =
 	0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x64, 0x28, 0x6b, 0x65, 0x79, 0x29, 0x0a,
 	0x09, 0x09, 0x69, 0x66, 0x20, 0x6b, 0x65, 0x79, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x65, 0x73, 0x63, 0x61, 0x70, 
 	0x65, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
-	0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x75, 0x73, 0x68, 
-	0x28, 0x22, 0x71, 0x22, 0x29, 0x0a,
+	0x09, 0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x71, 0x75, 0x69, 0x74, 
+	0x28, 0x29, 0x0a,
 	0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
 	0x09, 0x65, 0x6e, 0x64, 0x0a,0x0a,
 	0x09, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x63, 0x6f, 0x6e, 
@@ -1723,12 +1734,13 @@ const unsigned char boot_lua[] =
 	0x09, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x74, 0x72, 0x75, 0x65, 0x20, 0x64, 0x6f, 0x0a,
 	0x09, 0x09, 0x65, 0x2c, 0x20, 0x61, 0x2c, 0x20, 0x62, 0x2c, 0x20, 0x63, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 
 	0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x77, 0x61, 0x69, 0x74, 0x28, 0x29, 0x0a,0x0a,
-	0x09, 0x09, 0x69, 0x66, 0x20, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x71, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
+	0x09, 0x09, 0x69, 0x66, 0x20, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x71, 0x75, 0x69, 0x74, 0x22, 0x20, 0x74, 
+	0x68, 0x65, 0x6e, 0x0a,
 	0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x0a,
 	0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
-	0x09, 0x09, 0x69, 0x66, 0x20, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x6b, 0x70, 0x22, 0x20, 0x61, 0x6e, 0x64, 
-	0x20, 0x61, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x22, 0x20, 0x74, 0x68, 0x65, 
-	0x6e, 0x0a,
+	0x09, 0x09, 0x69, 0x66, 0x20, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x6b, 0x65, 0x79, 0x70, 0x72, 0x65, 0x73, 
+	0x73, 0x65, 0x64, 0x22, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x65, 0x73, 0x63, 
+	0x61, 0x70, 0x65, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
 	0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x0a,
 	0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,0x0a,
 	0x09, 0x09, 0x64, 0x72, 0x61, 0x77, 0x28, 0x29, 0x0a,0x0a,
@@ -1800,12 +1812,13 @@ const unsigned char boot_lua[] =
 	0x09, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x74, 0x72, 0x75, 0x65, 0x20, 0x64, 0x6f, 0x0a,
 	0x09, 0x09, 0x65, 0x2c, 0x20, 0x61, 0x2c, 0x20, 0x62, 0x2c, 0x20, 0x63, 0x20, 0x3d, 0x20, 0x6c, 0x6f, 0x76, 
 	0x65, 0x2e, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x2e, 0x77, 0x61, 0x69, 0x74, 0x28, 0x29, 0x0a,0x0a,
-	0x09, 0x09, 0x69, 0x66, 0x20, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x71, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
+	0x09, 0x09, 0x69, 0x66, 0x20, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x71, 0x75, 0x69, 0x74, 0x22, 0x20, 0x74, 
+	0x68, 0x65, 0x6e, 0x0a,
 	0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x0a,
 	0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,
-	0x09, 0x09, 0x69, 0x66, 0x20, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x6b, 0x70, 0x22, 0x20, 0x61, 0x6e, 0x64, 
-	0x20, 0x61, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x65, 0x73, 0x63, 0x61, 0x70, 0x65, 0x22, 0x20, 0x74, 0x68, 0x65, 
-	0x6e, 0x0a,
+	0x09, 0x09, 0x69, 0x66, 0x20, 0x65, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x6b, 0x65, 0x79, 0x70, 0x72, 0x65, 0x73, 
+	0x73, 0x65, 0x64, 0x22, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x61, 0x20, 0x3d, 0x3d, 0x20, 0x22, 0x65, 0x73, 0x63, 
+	0x61, 0x70, 0x65, 0x22, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x0a,
 	0x09, 0x09, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x0a,
 	0x09, 0x09, 0x65, 0x6e, 0x64, 0x0a,0x0a,
 	0x09, 0x09, 0x64, 0x72, 0x61, 0x77, 0x28, 0x29, 0x0a,0x0a,