diff --git a/bootstrap/boot.lua b/bootstrap/boot.lua
index 1eded180291449a68c97cb91917e91ee54ed43dd..e719e5b8e4ee0d6ba3950e0d84365088a15f8c66 100644
--- a/bootstrap/boot.lua
+++ b/bootstrap/boot.lua
@@ -19,19 +19,25 @@ if __SELFEXE then
 	print("SelfExe gave us app directory of:", dir)
 	fs.mount(dir..fs.getPathSeparator().."game"..fs.getPathSeparator().."thirdparty", "/", true)
 	fs.mount(dir..fs.getPathSeparator().."game", "/", true)
-	if fs.exists("/engine.teae") and fs.exists("/thirdparty.teae") then
-		fs.mount(dir..fs.getPathSeparator().."game/engine.teae", "/", true)
-		fs.mount(dir..fs.getPathSeparator().."game/thirdparty.teae", "/", true)
-		print("Using engine.teae")
-	end
 else
 	fs.mount("game"..fs.getPathSeparator().."thirdparty", "/", true)
 	fs.mount("game", "/", true)
-	if fs.exists("/engine.teae") and fs.exists("/thirdparty.teae") then
-		fs.mount(dir..fs.getPathSeparator().."game/engine.teae", "/", true)
-		fs.mount(dir..fs.getPathSeparator().."game/thirdparty.teae", "/", true)
-		print("Using engine.teae")
+end
+
+-- Look for a core
+function get_core(id)
+	for i, file in ipairs(fs.list("/engines/cores/")) do
+		if file:find("%.tec$") then
+			print("Possible engine core", file)
+		end
+	end
+	local core = "/engines/cores/te4core-"..id..".tec"
+	if fs.exists(core) then
+		local rcore = fs.getRealPath(core)
+		print("Using TE4CORE: ", core, rcore)
+		return rcore
 	end
+	return "NO CORE"
 end
 
 -- We need it no more, lets forget about it just it case some malovelant script tried something silly
diff --git a/premake4.lua b/premake4.lua
index e5af86233667018114eb7ff27e1880ca49c851d5..354133d7df0c2bb0ecd46ca274d314a2623d1f0c 100644
--- a/premake4.lua
+++ b/premake4.lua
@@ -91,15 +91,15 @@ project "TEngineRunner"
 	kind "WindowedApp"
 	language "C"
 	targetname "t-engine"
-	files { "src/runner/*.c", "src/getself.c" }
-	links { "physfs", "lua".._OPTIONS.lua }
+	files { "src/runner/*.c", "src/getself.c", "src/physfs.c", "src/auxiliar.c" }
+	links { "physfs", "lua".._OPTIONS.lua, "m" }
 configuration "linux"
 	links { "dl" }
-        defines { 'SELFEXE_LINUX'  }
+        defines { [[TENGINE_HOME_PATH='".t-engine"']], 'SELFEXE_LINUX'  }
 configuration "windows"
-        defines { 'SELFEXE_WINDOWS'  }
+        defines { [[TENGINE_HOME_PATH='"T-Engine"']], 'SELFEXE_WINDOWS'  }
 configuration "macosx"
-        defines { "USE_TENGINE_MAIN", 'SELFEXE_MACOSX'  }
+        defines { [[TENGINE_HOME_PATH='".t-engine"']], "USE_TENGINE_MAIN", 'SELFEXE_MACOSX'  }
 configuration {"Debug"}
 	postbuildcommands { "cp bin/Debug/t-engine t-engine", }
 configuration {"Release"}
@@ -107,6 +107,7 @@ configuration {"Release"}
 
 project "TEngine"
 	targetprefix ""
+	targetextension ".tec"
 	kind "SharedLib"
 	language "C"
 	targetname(corename)
diff --git a/src/core_lua.c b/src/core_lua.c
index 6670df89bad1ecbc54dff0d08e5624f24bf41f59..dba15b726f631baf6bc4caf98147a02d37b309bf 100644
--- a/src/core_lua.c
+++ b/src/core_lua.c
@@ -1975,397 +1975,6 @@ static const struct luaL_reg line_reg[] =
 	{NULL, NULL},
 };
 
-
-/******************************************************************
- ******************************************************************
- *                             FS                                 *
- ******************************************************************
- ******************************************************************/
-
-static int lua_fs_exists(lua_State *L)
-{
-	const char *file = luaL_checkstring(L, 1);
-
-	lua_pushboolean(L, PHYSFS_exists(file));
-
-	return 1;
-}
-
-static int lua_fs_isdir(lua_State *L)
-{
-	const char *file = luaL_checkstring(L, 1);
-
-	lua_pushboolean(L, PHYSFS_isDirectory(file));
-
-	return 1;
-}
-
-static int lua_fs_mkdir(lua_State *L)
-{
-	const char *dir = luaL_checkstring(L, 1);
-
-	PHYSFS_mkdir(dir);
-
-	return 0;
-}
-
-static int lua_fs_delete(lua_State *L)
-{
-	const char *file = luaL_checkstring(L, 1);
-
-	PHYSFS_delete(file);
-
-	return 0;
-}
-
-static int lua_fs_list(lua_State* L)
-{
-	const char *dir = luaL_checkstring(L, 1);
-	bool only_dir = lua_toboolean(L, 2);
-
-	char **rc = PHYSFS_enumerateFiles(dir);
-	char **i;
-	int nb = 1;
-	char buf[2048];
-
-	lua_newtable(L);
-	for (i = rc; *i != NULL; i++)
-	{
-		strcpy(buf, dir);
-		strcat(buf, "/");
-		strcat(buf, *i);
-		if (only_dir && (!PHYSFS_isDirectory(buf)))
-			continue;
-
-		lua_pushnumber(L, nb);
-		lua_pushstring(L, *i);
-		lua_settable(L, -3);
-		nb++;
-	}
-
-	PHYSFS_freeList(rc);
-
-	return 1;
-}
-
-
-static int lua_fs_open(lua_State *L)
-{
-	const char *file = luaL_checkstring(L, 1);
-	const char *mode = luaL_checkstring(L, 2);
-
-	PHYSFS_file **f = (PHYSFS_file **)lua_newuserdata(L, sizeof(PHYSFS_file *));
-	auxiliar_setclass(L, "physfs{file}", -1);
-
-	if (strchr(mode, 'w'))
-		*f = PHYSFS_openWrite(file);
-	else if (strchr(mode, 'a'))
-		*f = PHYSFS_openAppend(file);
-	else
-		*f = PHYSFS_openRead(file);
-	if (!*f)
-	{
-		lua_pop(L, 1);
-		lua_pushnil(L);
-		const char *error = PHYSFS_getLastError();
-		lua_pushstring(L, error);
-		return 2;
-	}
-	return 1;
-}
-
-static int lua_file_read(lua_State *L)
-{
-	PHYSFS_file **f = (PHYSFS_file**)auxiliar_checkclass(L, "physfs{file}", 1);
-	long n = luaL_optlong(L, 2, ~((size_t)0));
-
-	size_t rlen;  /* how much to read */
-	size_t nr;  /* number of chars actually read */
-	luaL_Buffer b;
-	luaL_buffinit(L, &b);
-	rlen = LUAL_BUFFERSIZE;  /* try to read that much each time */
-	do {
-		char *p = luaL_prepbuffer(&b);
-		if (rlen > n) rlen = n;  /* cannot read more than asked */
-		nr = PHYSFS_read(*f, p, sizeof(char), rlen);
-		luaL_addsize(&b, nr);
-		n -= nr;  /* still have to read `n' chars */
-	} while (n > 0 && nr == rlen);  /* until end of count or eof */
-	luaL_pushresult(&b);  /* close buffer */
-	return (n == 0 || lua_objlen(L, -1) > 0);
-	return 1;
-}
-
-// This will return empty lines if you've got DOS-style "\r\n" endlines!
-//  extra credit for handling buffer overflows and EOF more gracefully.
-static int lua_file_readline(lua_State *L)
-{
-	PHYSFS_file **f = (PHYSFS_file**)auxiliar_checkclass(L, "physfs{file}", 1);
-	char buf[1024];
-	char *ptr = buf;
-	int bufsize = 1024;
-	int total = 0;
-
-	if (PHYSFS_eof(*f)) return 0;
-
-	bufsize--;  /* allow for null terminating char */
-	while ((total < bufsize) && (PHYSFS_read(*f, ptr, 1, 1) == 1))
-	{
-		if ((*ptr == '\r') || (*ptr == '\n'))
-			break;
-		ptr++;
-		total++;
-	}
-
-	*ptr = '\0';  // null terminate it.
-	lua_pushstring(L, buf);
-	return 1;
-}
-
-
-static int lua_file_write(lua_State *L)
-{
-	PHYSFS_file **f = (PHYSFS_file**)auxiliar_checkclass(L, "physfs{file}", 1);
-	size_t len;
-	const char *data = lua_tolstring(L, 2, &len);
-
-	PHYSFS_write(*f, data, sizeof(char), len);
-
-	return 0;
-}
-
-static int lua_close_file(lua_State *L)
-{
-	PHYSFS_file **f = (PHYSFS_file**)auxiliar_checkclass(L, "physfs{file}", 1);
-	if (*f)
-	{
-		PHYSFS_close(*f);
-		*f = NULL;
-	}
-	lua_pushnumber(L, 1);
-	return 1;
-}
-
-static int lua_fs_zipopen(lua_State *L)
-{
-	const char *file = luaL_checkstring(L, 1);
-
-	zipFile *zf = (zipFile*)lua_newuserdata(L, sizeof(zipFile*));
-	auxiliar_setclass(L, "physfs{zip}", -1);
-
-	*zf = zipOpen(file, APPEND_STATUS_CREATE);
-	if (!*zf)
-	{
-		lua_pop(L, 1);
-		lua_pushnil(L);
-	}
-	return 1;
-}
-
-static int lua_close_zip(lua_State *L)
-{
-	zipFile *zf = (zipFile*)auxiliar_checkclass(L, "physfs{zip}", 1);
-	if (*zf)
-	{
-		zipClose(*zf, NULL);
-		*zf = NULL;
-	}
-	lua_pushnumber(L, 1);
-	return 1;
-}
-
-static int lua_zip_add(lua_State *L)
-{
-	zipFile *zf = (zipFile*)auxiliar_checkclass(L, "physfs{zip}", 1);
-	const char *filenameinzip = luaL_checkstring(L, 2);
-	size_t datalen;
-	const char *data = lua_tolstring(L, 3, &datalen);
-	int opt_compress_level = luaL_optnumber(L, 4, 4);
-
-	int err=0;
-	zip_fileinfo zi;
-	unsigned long crcFile=0;
-
-	zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour =
-	zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0;
-	zi.dosDate = 0;
-	zi.internal_fa = 0;
-	zi.external_fa = 0;
-
-	err = zipOpenNewFileInZip3(*zf,filenameinzip,&zi,
-		NULL,0,NULL,0,NULL /* comment*/,
-		(opt_compress_level != 0) ? Z_DEFLATED : 0,
-		opt_compress_level,0,
-		/* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */
-		-MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
-		NULL,crcFile);
-
-	if (err != ZIP_OK)
-	{
-		lua_pushnil(L);
-		lua_pushstring(L, "could not add file to zip");
-		return 2;
-	}
-	else
-	{
-		err = zipWriteInFileInZip(*zf, data, datalen);
-	}
-
-	zipCloseFileInZip(*zf);
-
-	lua_pushboolean(L, 1);
-	return 1;
-}
-
-static int lua_fs_mount(lua_State *L)
-{
-	const char *src = luaL_checkstring(L, 1);
-	const char *dest = luaL_checkstring(L, 2);
-	bool append = lua_toboolean(L, 3);
-
-	int err = PHYSFS_mount(src, dest, append);
-	if (err == 0)
-	{
-		lua_pushnil(L);
-		lua_pushstring(L, PHYSFS_getLastError());
-		return 2;
-	}
-	lua_pushboolean(L, TRUE);
-
-	return 1;
-}
-
-static int lua_fs_umount(lua_State *L)
-{
-	const char *src = luaL_checkstring(L, 1);
-
-	int err = PHYSFS_removeFromSearchPath(src);
-	if (err == 0)
-	{
-		lua_pushnil(L);
-		lua_pushstring(L, PHYSFS_getLastError());
-		return 2;
-	}
-	lua_pushboolean(L, TRUE);
-
-	return 1;
-}
-
-static int lua_fs_get_real_path(lua_State *L)
-{
-	const char *src = luaL_checkstring(L, 1);
-	char *path = PHYSFS_getDependentPath(src);
-	lua_pushstring(L, path);
-	free(path);
-	return 1;
-}
-
-static int lua_fs_set_write_dir(lua_State *L)
-{
-	const char *src = luaL_checkstring(L, 1);
-	const int error = PHYSFS_setWriteDir(src);
-	if (error == 0)
-	{
-		lua_pushnil(L);
-		lua_pushstring(L, PHYSFS_getLastError());
-		return 2;
-	}
-	lua_pushboolean(L, TRUE);
-	return 1;
-}
-
-static int lua_fs_rename(lua_State *L)
-{
-	const char *src = luaL_checkstring(L, 1);
-	const char *dst = luaL_checkstring(L, 2);
-	PHYSFS_rename(src, dst);
-	return 0;
-}
-
-static int lua_fs_get_write_dir(lua_State *L)
-{
-	lua_pushstring(L, PHYSFS_getWriteDir());
-	return 1;
-}
-
-static int lua_fs_get_home_path(lua_State *L)
-{
-	lua_pushstring(L, TENGINE_HOME_PATH);
-	return 1;
-}
-
-static int lua_fs_get_user_path(lua_State *L)
-{
-	lua_pushstring(L, PHYSFS_getUserDir());
-	return 1;
-}
-
-static int lua_fs_get_path_separator(lua_State *L)
-{
-	lua_pushstring(L, PHYSFS_getDirSeparator());
-	return 1;
-}
-
-static int lua_fs_get_search_path(lua_State *L)
-{
-	char **rc = PHYSFS_getSearchPath();
-
-	char **i;
-	int nb = 1;
-
-	lua_newtable(L);
-	for (i = rc; *i != NULL; i++)
-	{
-		lua_pushnumber(L, nb);
-		lua_pushstring(L, *i);
-		lua_settable(L, -3);
-		nb++;
-	}
-
-	PHYSFS_freeList(rc);
-	return 1;
-}
-
-static const struct luaL_reg fslib[] =
-{
-	{"open", lua_fs_open},
-	{"zipOpen", lua_fs_zipopen},
-	{"exists", lua_fs_exists},
-	{"rename", lua_fs_rename},
-	{"mkdir", lua_fs_mkdir},
-	{"isdir", lua_fs_isdir},
-	{"delete", lua_fs_delete},
-	{"list", lua_fs_list},
-	{"setWritePath", lua_fs_set_write_dir},
-	{"getWritePath", lua_fs_get_write_dir},
-	{"getPathSeparator", lua_fs_get_path_separator},
-	{"getRealPath", lua_fs_get_real_path},
-	{"getUserPath", lua_fs_get_user_path},
-	{"getHomePath", lua_fs_get_home_path},
-	{"getSearchPath", lua_fs_get_search_path},
-	{"mount", lua_fs_mount},
-	{"umount", lua_fs_umount},
-	{NULL, NULL},
-};
-
-static const struct luaL_reg fsfile_reg[] =
-{
-	{"__gc", lua_close_file},
-	{"close", lua_close_file},
-	{"read", lua_file_read},
-	{"readLine", lua_file_readline},
-	{"write", lua_file_write},
-	{NULL, NULL},
-};
-
-static const struct luaL_reg fszipfile_reg[] =
-{
-	{"__gc", lua_close_zip},
-	{"close", lua_close_zip},
-	{"add", lua_zip_add},
-	{NULL, NULL},
-};
-
 /******************************************************************
  ******************************************************************
  *                            ZLIB                                *
@@ -2442,8 +2051,6 @@ static const struct luaL_reg zliblib[] =
 
 int luaopen_core(lua_State *L)
 {
-	auxiliar_newclass(L, "physfs{file}", fsfile_reg);
-	auxiliar_newclass(L, "physfs{zip}", fszipfile_reg);
 	auxiliar_newclass(L, "line{core}", line_reg);
 	auxiliar_newclass(L, "gl{texture}", sdl_texture_reg);
 	auxiliar_newclass(L, "gl{fbo}", gl_fbo_reg);
@@ -2461,8 +2068,7 @@ int luaopen_core(lua_State *L)
 
 	luaL_openlib(L, "rng", rnglib, 0);
 	luaL_openlib(L, "line", linelib, 0);
-	luaL_openlib(L, "fs", fslib, 0);
 
-	lua_pop(L, 8);
+	lua_settop(L, 0);
 	return 1;
 }
diff --git a/src/main.c b/src/main.c
index 0228c330ec967786c1c3aa25ed2fc9550d2d0c9e..7babeb1e7dadbd103428222963c821be8d48f686 100644
--- a/src/main.c
+++ b/src/main.c
@@ -687,9 +687,8 @@ void boot_lua(int state, bool rebooting, int argc, char *argv[])
 		PHYSFS_init(argv[0]);
 
 		selfexe = get_self_executable(argc, argv);
-		if (selfexe)
+		if (selfexe && PHYSFS_mount(selfexe, "/", 1))
 		{
-			PHYSFS_mount(selfexe, "/", 1);
 		}
 		else
 		{
@@ -700,6 +699,7 @@ void boot_lua(int state, bool rebooting, int argc, char *argv[])
 		/***************** Lua Init *****************/
 		L = lua_open();  /* create state */
 		luaL_openlibs(L);  /* open libraries */
+		luaopen_physfs(L);
 		luaopen_core(L);
 		luaopen_fov(L);
 		luaopen_socket_core(L);
diff --git a/src/physfs.c b/src/physfs.c
new file mode 100644
index 0000000000000000000000000000000000000000..8d09b45d66dd30de6ef3c0b68a73927257498bd4
--- /dev/null
+++ b/src/physfs.c
@@ -0,0 +1,429 @@
+/*
+    TE4 - T-Engine 4
+    Copyright (C) 2009, 2010 Nicolas Casalini
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+    Nicolas Casalini "DarkGod"
+    darkgod@te4.org
+*/
+#include <string.h>
+#include "lua.h"
+#include "lauxlib.h"
+#include "lualib.h"
+#include "auxiliar.h"
+#include "physfs.h"
+#include "mzip.h"
+#include "zlib.h"
+#include "types.h"
+
+/******************************************************************
+ ******************************************************************
+ *                             FS                                 *
+ ******************************************************************
+ ******************************************************************/
+
+static int lua_fs_exists(lua_State *L)
+{
+	const char *file = luaL_checkstring(L, 1);
+
+	lua_pushboolean(L, PHYSFS_exists(file));
+
+	return 1;
+}
+
+static int lua_fs_isdir(lua_State *L)
+{
+	const char *file = luaL_checkstring(L, 1);
+
+	lua_pushboolean(L, PHYSFS_isDirectory(file));
+
+	return 1;
+}
+
+static int lua_fs_mkdir(lua_State *L)
+{
+	const char *dir = luaL_checkstring(L, 1);
+
+	PHYSFS_mkdir(dir);
+
+	return 0;
+}
+
+static int lua_fs_delete(lua_State *L)
+{
+	const char *file = luaL_checkstring(L, 1);
+
+	PHYSFS_delete(file);
+
+	return 0;
+}
+
+static int lua_fs_list(lua_State* L)
+{
+	const char *dir = luaL_checkstring(L, 1);
+	bool only_dir = lua_toboolean(L, 2);
+
+	char **rc = PHYSFS_enumerateFiles(dir);
+	char **i;
+	int nb = 1;
+	char buf[2048];
+
+	lua_newtable(L);
+	for (i = rc; *i != NULL; i++)
+	{
+		strcpy(buf, dir);
+		strcat(buf, "/");
+		strcat(buf, *i);
+		if (only_dir && (!PHYSFS_isDirectory(buf)))
+			continue;
+
+		lua_pushnumber(L, nb);
+		lua_pushstring(L, *i);
+		lua_settable(L, -3);
+		nb++;
+	}
+
+	PHYSFS_freeList(rc);
+
+	return 1;
+}
+
+
+static int lua_fs_open(lua_State *L)
+{
+	const char *file = luaL_checkstring(L, 1);
+	const char *mode = luaL_checkstring(L, 2);
+
+	PHYSFS_file **f = (PHYSFS_file **)lua_newuserdata(L, sizeof(PHYSFS_file *));
+	auxiliar_setclass(L, "physfs{file}", -1);
+
+	if (strchr(mode, 'w'))
+		*f = PHYSFS_openWrite(file);
+	else if (strchr(mode, 'a'))
+		*f = PHYSFS_openAppend(file);
+	else
+		*f = PHYSFS_openRead(file);
+	if (!*f)
+	{
+		lua_pop(L, 1);
+		lua_pushnil(L);
+		const char *error = PHYSFS_getLastError();
+		lua_pushstring(L, error);
+		return 2;
+	}
+	return 1;
+}
+
+static int lua_file_read(lua_State *L)
+{
+	PHYSFS_file **f = (PHYSFS_file**)auxiliar_checkclass(L, "physfs{file}", 1);
+	long n = luaL_optlong(L, 2, ~((size_t)0));
+
+	size_t rlen;  /* how much to read */
+	size_t nr;  /* number of chars actually read */
+	luaL_Buffer b;
+	luaL_buffinit(L, &b);
+	rlen = LUAL_BUFFERSIZE;  /* try to read that much each time */
+	do {
+		char *p = luaL_prepbuffer(&b);
+		if (rlen > n) rlen = n;  /* cannot read more than asked */
+		nr = PHYSFS_read(*f, p, sizeof(char), rlen);
+		luaL_addsize(&b, nr);
+		n -= nr;  /* still have to read `n' chars */
+	} while (n > 0 && nr == rlen);  /* until end of count or eof */
+	luaL_pushresult(&b);  /* close buffer */
+	return (n == 0 || lua_objlen(L, -1) > 0);
+	return 1;
+}
+
+// This will return empty lines if you've got DOS-style "\r\n" endlines!
+//  extra credit for handling buffer overflows and EOF more gracefully.
+static int lua_file_readline(lua_State *L)
+{
+	PHYSFS_file **f = (PHYSFS_file**)auxiliar_checkclass(L, "physfs{file}", 1);
+	char buf[1024];
+	char *ptr = buf;
+	int bufsize = 1024;
+	int total = 0;
+
+	if (PHYSFS_eof(*f)) return 0;
+
+	bufsize--;  /* allow for null terminating char */
+	while ((total < bufsize) && (PHYSFS_read(*f, ptr, 1, 1) == 1))
+	{
+		if ((*ptr == '\r') || (*ptr == '\n'))
+			break;
+		ptr++;
+		total++;
+	}
+
+	*ptr = '\0';  // null terminate it.
+	lua_pushstring(L, buf);
+	return 1;
+}
+
+
+static int lua_file_write(lua_State *L)
+{
+	PHYSFS_file **f = (PHYSFS_file**)auxiliar_checkclass(L, "physfs{file}", 1);
+	size_t len;
+	const char *data = lua_tolstring(L, 2, &len);
+
+	PHYSFS_write(*f, data, sizeof(char), len);
+
+	return 0;
+}
+
+static int lua_close_file(lua_State *L)
+{
+	PHYSFS_file **f = (PHYSFS_file**)auxiliar_checkclass(L, "physfs{file}", 1);
+	if (*f)
+	{
+		PHYSFS_close(*f);
+		*f = NULL;
+	}
+	lua_pushnumber(L, 1);
+	return 1;
+}
+
+static int lua_fs_zipopen(lua_State *L)
+{
+	const char *file = luaL_checkstring(L, 1);
+
+	zipFile *zf = (zipFile*)lua_newuserdata(L, sizeof(zipFile*));
+	auxiliar_setclass(L, "physfs{zip}", -1);
+
+	*zf = zipOpen(file, APPEND_STATUS_CREATE);
+	if (!*zf)
+	{
+		lua_pop(L, 1);
+		lua_pushnil(L);
+	}
+	return 1;
+}
+
+static int lua_close_zip(lua_State *L)
+{
+	zipFile *zf = (zipFile*)auxiliar_checkclass(L, "physfs{zip}", 1);
+	if (*zf)
+	{
+		zipClose(*zf, NULL);
+		*zf = NULL;
+	}
+	lua_pushnumber(L, 1);
+	return 1;
+}
+
+static int lua_zip_add(lua_State *L)
+{
+	zipFile *zf = (zipFile*)auxiliar_checkclass(L, "physfs{zip}", 1);
+	const char *filenameinzip = luaL_checkstring(L, 2);
+	size_t datalen;
+	const char *data = lua_tolstring(L, 3, &datalen);
+	int opt_compress_level = luaL_optnumber(L, 4, 4);
+
+	int err=0;
+	zip_fileinfo zi;
+	unsigned long crcFile=0;
+
+	zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour =
+	zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0;
+	zi.dosDate = 0;
+	zi.internal_fa = 0;
+	zi.external_fa = 0;
+
+	err = zipOpenNewFileInZip3(*zf,filenameinzip,&zi,
+		NULL,0,NULL,0,NULL /* comment*/,
+		(opt_compress_level != 0) ? Z_DEFLATED : 0,
+		opt_compress_level,0,
+		/* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */
+		-MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
+		NULL,crcFile);
+
+	if (err != ZIP_OK)
+	{
+		lua_pushnil(L);
+		lua_pushstring(L, "could not add file to zip");
+		return 2;
+	}
+	else
+	{
+		err = zipWriteInFileInZip(*zf, data, datalen);
+	}
+
+	zipCloseFileInZip(*zf);
+
+	lua_pushboolean(L, 1);
+	return 1;
+}
+
+static int lua_fs_mount(lua_State *L)
+{
+	const char *src = luaL_checkstring(L, 1);
+	const char *dest = luaL_checkstring(L, 2);
+	bool append = lua_toboolean(L, 3);
+
+	int err = PHYSFS_mount(src, dest, append);
+	if (err == 0)
+	{
+		lua_pushnil(L);
+		lua_pushstring(L, PHYSFS_getLastError());
+		return 2;
+	}
+	lua_pushboolean(L, TRUE);
+
+	return 1;
+}
+
+static int lua_fs_umount(lua_State *L)
+{
+	const char *src = luaL_checkstring(L, 1);
+
+	int err = PHYSFS_removeFromSearchPath(src);
+	if (err == 0)
+	{
+		lua_pushnil(L);
+		lua_pushstring(L, PHYSFS_getLastError());
+		return 2;
+	}
+	lua_pushboolean(L, TRUE);
+
+	return 1;
+}
+
+static int lua_fs_get_real_path(lua_State *L)
+{
+	const char *src = luaL_checkstring(L, 1);
+	char *path = PHYSFS_getDependentPath(src);
+	lua_pushstring(L, path);
+	free(path);
+	return 1;
+}
+
+static int lua_fs_set_write_dir(lua_State *L)
+{
+	const char *src = luaL_checkstring(L, 1);
+	const int error = PHYSFS_setWriteDir(src);
+	if (error == 0)
+	{
+		lua_pushnil(L);
+		lua_pushstring(L, PHYSFS_getLastError());
+		return 2;
+	}
+	lua_pushboolean(L, TRUE);
+	return 1;
+}
+
+static int lua_fs_rename(lua_State *L)
+{
+	const char *src = luaL_checkstring(L, 1);
+	const char *dst = luaL_checkstring(L, 2);
+	PHYSFS_rename(src, dst);
+	return 0;
+}
+
+static int lua_fs_get_write_dir(lua_State *L)
+{
+	lua_pushstring(L, PHYSFS_getWriteDir());
+	return 1;
+}
+
+static int lua_fs_get_home_path(lua_State *L)
+{
+	lua_pushstring(L, TENGINE_HOME_PATH);
+	return 1;
+}
+
+static int lua_fs_get_user_path(lua_State *L)
+{
+	lua_pushstring(L, PHYSFS_getUserDir());
+	return 1;
+}
+
+static int lua_fs_get_path_separator(lua_State *L)
+{
+	lua_pushstring(L, PHYSFS_getDirSeparator());
+	return 1;
+}
+
+static int lua_fs_get_search_path(lua_State *L)
+{
+	char **rc = PHYSFS_getSearchPath();
+
+	char **i;
+	int nb = 1;
+
+	lua_newtable(L);
+	for (i = rc; *i != NULL; i++)
+	{
+		lua_pushnumber(L, nb);
+		lua_pushstring(L, *i);
+		lua_settable(L, -3);
+		nb++;
+	}
+
+	PHYSFS_freeList(rc);
+	return 1;
+}
+
+static const struct luaL_reg fslib[] =
+{
+	{"open", lua_fs_open},
+	{"zipOpen", lua_fs_zipopen},
+	{"exists", lua_fs_exists},
+	{"rename", lua_fs_rename},
+	{"mkdir", lua_fs_mkdir},
+	{"isdir", lua_fs_isdir},
+	{"delete", lua_fs_delete},
+	{"list", lua_fs_list},
+	{"setWritePath", lua_fs_set_write_dir},
+	{"getWritePath", lua_fs_get_write_dir},
+	{"getPathSeparator", lua_fs_get_path_separator},
+	{"getRealPath", lua_fs_get_real_path},
+	{"getUserPath", lua_fs_get_user_path},
+	{"getHomePath", lua_fs_get_home_path},
+	{"getSearchPath", lua_fs_get_search_path},
+	{"mount", lua_fs_mount},
+	{"umount", lua_fs_umount},
+	{NULL, NULL},
+};
+
+static const struct luaL_reg fsfile_reg[] =
+{
+	{"__gc", lua_close_file},
+	{"close", lua_close_file},
+	{"read", lua_file_read},
+	{"readLine", lua_file_readline},
+	{"write", lua_file_write},
+	{NULL, NULL},
+};
+
+static const struct luaL_reg fszipfile_reg[] =
+{
+	{"__gc", lua_close_zip},
+	{"close", lua_close_zip},
+	{"add", lua_zip_add},
+	{NULL, NULL},
+};
+
+int luaopen_physfs(lua_State *L)
+{
+	auxiliar_newclass(L, "physfs{file}", fsfile_reg);
+	auxiliar_newclass(L, "physfs{zip}", fszipfile_reg);
+	luaL_openlib(L, "fs", fslib, 0);
+
+	lua_settop(L, 0);
+	return 1;
+}
diff --git a/src/runner/main.c b/src/runner/main.c
index f19ba5ccffc57b9f2f406ac88505253afbbf8895..b4b0d7d0eb1be119c5a05e6bc6154b27aabc1b41 100644
--- a/src/runner/main.c
+++ b/src/runner/main.c
@@ -28,6 +28,9 @@
 #include <dlfcn.h>
 #endif
 
+#include "lua.h"
+#include "lauxlib.h"
+#include "lualib.h"
 #include "physfs.h"
 
 // Load the shared lib containing the core and calls te4main inside it, passing control to that core
@@ -35,20 +38,70 @@ int run_core(int corenum, int argc, char **argv)
 {
 	int (*te4main)(int, char**);
 
+	/******************************************************************
+	 ** Find a core file
+	 ******************************************************************/
+	PHYSFS_init(argv[0]);
+
+	const char *selfexe = get_self_executable(argc, argv);
+	if (selfexe && PHYSFS_mount(selfexe, "/", 1)) {} else
+	{
+		printf("NO SELFEXE: bootstrapping from CWD\n");
+		PHYSFS_mount("bootstrap", "/bootstrap", 1);
+	}
+
+	lua_State *L = lua_open();
+	luaL_openlibs(L);
+	luaopen_physfs(L);
+
+	// Tell the boostrapping code the selfexe path
+	if (selfexe) lua_pushstring(L, selfexe);
+	else lua_pushnil(L);
+	lua_setglobal(L, "__SELFEXE");
+
+	// Will be useful
+#ifdef __APPLE__
+	lua_pushboolean(L, TRUE);
+	lua_setglobal(L, "__APPLE__");
+#endif
+
+	// Run bootstrapping
+	if (!luaL_loadfile(L, "/bootstrap/boot.lua")) { lua_call(L, 0, 0); }
+	// Could not load bootstrap! Try to mount the engine from working directory as last resort
+	else
+	{
+		printf("Could not find bootstrapping code! Aborting!\n");
+		exit(1);
+	}
+
+	// Get the core
+	lua_getglobal(L, "get_core");
+	lua_pushnumber(L, corenum);
+	lua_call(L, 1, 1);
+	char *core = lua_tostring(L, -1);
+
+	lua_close(L);
+	PHYSFS_deinit();
+
+	if (!core) {
+		printf("No core found!");
+		exit(1);
+	}
+
 	/***********************************************************************
 	 ** Windows DLL loading code
 	 ***********************************************************************/
 #ifdef SELFEXE_WINDOWS
 
-	HINSTANCE handle = LoadLibrary("game/engines/cores/te4core-12.dll");
+	HINSTANCE handle = LoadLibrary(core);
 	if (!handle) {
-		fprintf(stderr, "Error loading core %d: %d\n", corenum, GetLastError());
+		fprintf(stderr, "Error loading core %d (%s): %d\n", corenum, core, GetLastError());
 		exit(EXIT_FAILURE);
 	}
 
 	te4main = GetProcAddress(handle, "te4main");
 	if (te4main == NULL)  {
-		fprintf(stderr, "Error binding to core %d: %d\n", corenum, GetLastError());
+		fprintf(stderr, "Error binding to core %d (%s): %d\n", corenum, core, GetLastError());
 		exit(EXIT_FAILURE);
 	}
 
@@ -63,9 +116,9 @@ int run_core(int corenum, int argc, char **argv)
 #else
 	char *error;
 
-	void *handle = dlopen("game/engines/cores/te4core-12.so", RTLD_LAZY);
+	void *handle = dlopen(core, RTLD_LAZY);
 	if (!handle) {
-		fprintf(stderr, "Error loading core %d: %s\n", corenum, dlerror());
+		fprintf(stderr, "Error loading core %d (%s): %s\n", corenum, core, dlerror());
 		exit(EXIT_FAILURE);
 	}
 
@@ -81,7 +134,7 @@ int run_core(int corenum, int argc, char **argv)
 	*(void **) (&te4main) = dlsym(handle, "te4main");
 
 	if ((error = dlerror()) != NULL)  {
-		fprintf(stderr, "Error binding to core %d: %s\n", corenum, error);
+		fprintf(stderr, "Error binding to core %d (%s): %s\n", corenum, core, error);
 		exit(EXIT_FAILURE);
 	}
 
@@ -91,6 +144,8 @@ int run_core(int corenum, int argc, char **argv)
 	dlclose(handle);
 #endif
 
+	free(core);
+
 	return corenum;
 }
 
@@ -106,22 +161,6 @@ int main(int argc, char **argv)
 {
 	int core = 12;
 
-	/***************** Physfs Init *****************/
-	PHYSFS_init(argv[0]);
-
-	const char *selfexe = get_self_executable(argc, argv);
-	if (selfexe)
-	{
-		PHYSFS_mount(selfexe, "/", 1);
-	}
-	else
-	{
-		printf("NO SELFEXE: bootstrapping from CWD\n");
-		PHYSFS_mount("bootstrap", "/bootstrap", 1);
-	}
-
-	PHYSFS_deinit();
-
 	// Run the requested cores until we want no more
 	while (core) core = run_core(core, argc, argv);