/* This file is part of Iceball. Iceball 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. Iceball 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 Iceball. If not, see . */ #include "common.h" struct icelua_entry { int (*fn) (lua_State *L); char *name; }; lua_State *lstate_client = NULL; lua_State *lstate_server = NULL; struct icelua_whitelist { char *addr; int port; }; struct icelua_whitelist *raw_whitelist = NULL; int raw_whitelist_len = 0; int bin_storage_allowed = 0; int whitelist_validate(const char *name, int port) { if(name == NULL || port == 0 || port == -1) return 0; int i; for(i = 0; i < raw_whitelist_len; i++) if(!strcmp(raw_whitelist[i].addr, name) && (raw_whitelist[i].port == -1 || port == raw_whitelist[i].port)) return 1; return 0; } // helper functions int icelua_assert_stack(lua_State *L, int smin, int smax) { int top = lua_gettop(L); if(smin != -1 && top < smin) return luaL_error(L, "expected at least %d arguments, got %d", smin, top); if(smax != -1 && top > smax) return luaL_error(L, "expected at most %d arguments, got %d", smax, top); return top; } int icelua_force_get_integer(lua_State *L, int table, char *name) { lua_getfield(L, table, name); if(!lua_isnumber(L, -1)) return luaL_error(L, "expected integer for \"%s\", got something else", name); int ret = lua_tointeger(L, -1); lua_pop(L, 1); return ret; } // To be moved. Maybe. int icelua_fn_common_mk_compat_disable(lua_State *L) { mk_compat_mode = 0; return 0; } #ifndef DEDI int icelua_fn_client_mk_sys_execv(lua_State *L) { if((boot_mode & 3) != 3 || net_port != 0) return luaL_error(L, "mk_sys_execv called when not in -s 0 mode"); int top = lua_gettop(L); char **arglist = malloc(sizeof(char *) * (top+2)); int i; for(i = 1; i <= top; i++) arglist[i] = strdup(lua_tostring(L, i)); arglist[0] = strdup(main_argv0); arglist[top+1] = NULL; SDL_Quit(); #ifdef WIN32 const char *follow = main_argv0; while(*follow != '\x00') { if(*follow == '\\' || *follow == '/') main_argv0 = follow+1; follow++; } //if(main_oldcwd != NULL) _chdir(main_oldcwd); #endif printf("argv0: [%s]\n", main_argv0); fflush(stdout); execv(main_argv[0], arglist); printf("WORK YOU FUCKASS: %s\n", strerror(errno)); fflush(stdout); // DOES NOT RETURN. fprintf(stderr, "ABORT: sys_execv must not return!\n"); fflush(stderr); abort(); return 0; } extern char mk_app_title[]; int icelua_fn_client_mk_set_title(lua_State *L) { int top = icelua_assert_stack(L, 1, 1); const char *title = lua_tostring(L, 1); strncpy(mk_app_title, title, 128); mk_app_title[127] = '\x00'; return 0; } #endif #include "lua_fetch.h" #include "lua_base.h" #include "lua_bin.h" #include "lua_camera.h" #include "lua_image.h" #include "lua_input.h" #include "lua_json.h" #include "lua_map.h" #include "lua_mus.h" #include "lua_model.h" #include "lua_net.h" #include "lua_tcp.h" #include "lua_udp.h" #include "lua_util.h" #include "lua_wav.h" #include "lua_va.h" // common functions // client functions // server functions #ifndef DEDI struct icelua_entry icelua_client[] = { {icelua_fn_client_mk_set_title, "mk_set_title"}, {icelua_fn_client_mk_sys_execv, "mk_sys_execv"}, {icelua_fn_client_mouse_lock_set, "mouse_lock_set"}, {icelua_fn_client_mouse_visible_set, "mouse_visible_set"}, {icelua_fn_client_mouse_visible_set, "mouse_visible_set"}, {icelua_fn_client_mouse_warp, "mouse_warp"}, {icelua_fn_client_map_fog_get, "map_fog_get"}, {icelua_fn_client_map_fog_set, "map_fog_set"}, {icelua_fn_client_camera_point, "camera_point"}, {icelua_fn_client_camera_point_sky, "camera_point_sky"}, {icelua_fn_client_camera_move_local, "camera_move_local"}, {icelua_fn_client_camera_move_global, "camera_move_global"}, {icelua_fn_client_camera_move_to, "camera_move_to"}, {icelua_fn_client_camera_get_pos, "camera_get_pos"}, {icelua_fn_client_camera_get_forward, "camera_get_forward"}, {icelua_fn_client_camera_shading_set, "camera_shading_set"}, {icelua_fn_client_screen_get_dims, "screen_get_dims"}, {icelua_fn_client_model_render_bone_global, "model_render_bone_global"}, {icelua_fn_client_model_render_bone_local, "model_render_bone_local"}, {icelua_fn_client_img_blit, "img_blit"}, {icelua_fn_client_img_blit_to, "img_blit_to"}, {icelua_fn_client_wav_cube_size, "wav_cube_size"}, {icelua_fn_client_wav_play_global, "wav_play_global"}, {icelua_fn_client_wav_play_local, "wav_play_local"}, {icelua_fn_client_wav_chn_exists, "wav_chn_exists"}, {icelua_fn_client_wav_chn_update, "wav_chn_update"}, {icelua_fn_client_va_render_global, "va_render_global"}, {icelua_fn_client_va_render_local, "va_render_local"}, {icelua_fn_client_wav_kill, "wav_kill"}, {icelua_fn_client_mus_play, "mus_play"}, {icelua_fn_client_mus_stop, "mus_stop"}, {icelua_fn_client_mus_vol_set, "mus_vol_set"}, {NULL, NULL} }; #endif struct icelua_entry icelua_server[] = { {NULL, NULL} }; struct icelua_entry icelua_common[] = { {icelua_fn_common_mk_compat_disable, "mk_compat_disable"}, {icelua_fn_common_fetch_start, "fetch_start"}, {icelua_fn_common_fetch_poll, "fetch_poll"}, {icelua_fn_common_fetch_block, "fetch_block"}, {icelua_fn_common_map_load, "map_load"}, {icelua_fn_common_map_new, "map_new"}, {icelua_fn_common_map_free, "map_free"}, {icelua_fn_common_map_get, "map_get"}, {icelua_fn_common_map_set, "map_set"}, {icelua_fn_common_map_save, "map_save"}, {icelua_fn_common_map_get_dims, "map_get_dims"}, {icelua_fn_common_map_pillar_get, "map_pillar_get"}, {icelua_fn_common_map_pillar_set, "map_pillar_set"}, {icelua_fn_common_model_new, "model_new"}, {icelua_fn_common_model_load_pmf, "model_load_pmf"}, {icelua_fn_common_model_save_pmf, "model_save_pmf"}, {icelua_fn_common_model_free, "model_free"}, {icelua_fn_common_model_len, "model_len"}, {icelua_fn_common_model_bone_new, "model_bone_new"}, {icelua_fn_common_model_bone_free, "model_bone_free"}, {icelua_fn_common_model_bone_get, "model_bone_get"}, {icelua_fn_common_model_bone_set, "model_bone_set"}, {icelua_fn_common_model_bone_find, "model_bone_find"}, {icelua_fn_common_img_load, "img_load"}, {icelua_fn_common_img_new, "img_new"}, {icelua_fn_common_img_pixel_set, "img_pixel_set"}, {icelua_fn_common_img_fill, "img_fill"}, {icelua_fn_common_img_free, "img_free"}, {icelua_fn_common_img_get_dims, "img_get_dims"}, {icelua_fn_common_json_parse, "json_parse"}, {icelua_fn_common_json_load, "json_load"}, {icelua_fn_common_json_write, "json_write"}, {icelua_fn_common_net_pack, "net_pack"}, {icelua_fn_common_net_unpack, "net_unpack"}, {icelua_fn_common_net_send, "net_send"}, {icelua_fn_common_net_recv, "net_recv"}, {icelua_fn_common_tcp_connect, "tcp_connect"}, {icelua_fn_common_tcp_send, "tcp_send"}, {icelua_fn_common_tcp_recv, "tcp_recv"}, {icelua_fn_common_tcp_close, "tcp_close"}, {icelua_fn_common_udp_open, "udp_open"}, {icelua_fn_common_udp_sendto, "udp_sendto"}, {icelua_fn_common_udp_recvfrom, "udp_recvfrom"}, {icelua_fn_common_udp_close, "udp_close"}, {icelua_fn_common_wav_load, "wav_load"}, {icelua_fn_common_wav_free, "wav_free"}, {icelua_fn_common_mus_load_it, "mus_load_it"}, {icelua_fn_common_mus_free, "mus_free"}, {icelua_fn_common_bin_load, "bin_load"}, {icelua_fn_common_bin_save, "bin_save"}, {icelua_fn_common_argb_split_to_merged, "argb_split_to_merged"}, {icelua_fn_common_argb_merged_to_split, "argb_merged_to_split"}, {icelua_fn_common_time, "time"}, {icelua_fn_common_va_make, "va_make"}, {NULL, NULL} }; #ifndef DEDI struct icelua_entry icelua_common_client[] = { {NULL, NULL} }; #endif struct icelua_entry icelua_common_server[] = { {icelua_fn_server_net_kick, "net_kick"}, {NULL, NULL} }; void icelua_loadfuncs(lua_State *L, char *table, struct icelua_entry *fnlist) { if(L == NULL) return; lua_getglobal(L, table); while(fnlist->fn != NULL) { lua_pushcfunction(L, fnlist->fn); lua_setfield (L, -2, fnlist->name); fnlist++; } lua_pop(L, 1); } void icelua_loadbasefuncs(lua_State *L) { if(L == NULL) return; // load base library // TODO: whitelist the functions by spawning a new environment. // this is harder than it sounds. lua_pushcfunction(L, luaopen_base); lua_call(L, 0, 0); // here's the other three lua_pushcfunction(L, luaopen_string); lua_call(L, 0, 0); lua_pushcfunction(L, luaopen_math); lua_call(L, 0, 0); lua_pushcfunction(L, luaopen_table); lua_call(L, 0, 0); // overwrite dofile/loadfile. lua_pushcfunction(L, icelua_fn_base_loadfile); lua_setglobal(L, "loadfile"); lua_pushcfunction(L, icelua_fn_base_dofile); lua_setglobal(L, "dofile"); } int icelua_initfetch(void) { int i; char xpath[128+1]; int argct = (main_largstart == -1 || (main_largstart >= main_argc) ? 0 : main_argc - main_largstart); if(to_client_local.sockfd == -1) to_client_local.sockfd = SOCKFD_LOCAL; lua_getglobal(lstate_client, "client"); lua_pushstring(lstate_client, mod_basedir+4); lua_setfield(lstate_client, -2, "base_dir"); lua_pop(lstate_client, 1); lua_getglobal(lstate_client, "common"); lua_pushstring(lstate_client, mod_basedir+4); lua_setfield(lstate_client, -2, "base_dir"); lua_pop(lstate_client, 1); lua_getglobal(lstate_client, "client"); lua_pushstring(lstate_client, "gl"); // Only one renderer now. -mk<3 lua_setfield(lstate_client, -2, "renderer"); lua_pop(lstate_client, 1); snprintf(xpath, 128, "%s/main_client.lua", mod_basedir); lua_pushcfunction(lstate_client, icelua_fn_common_fetch_block); lua_pushstring(lstate_client, "lua"); lua_pushstring(lstate_client, xpath); printf("Now loading client; please wait! [%s]\n", xpath); if(lua_pcall(lstate_client, 2, 1, 0) != 0) { printf("ERROR fetching client Lua: %s\n", lua_tostring(lstate_client, -1)); lua_pop(lstate_client, 1); return 1; } printf("Client loaded! Initialising...\n"); for(i = 0; i < argct; i++) lua_pushstring(lstate_client, main_argv[i+main_largstart]); if((boot_mode & 1) && net_addr_xbuf[1] != '\x00') { lua_pushstring(lstate_client, net_addr_xbuf); argct++; } if(lua_pcall(lstate_client, argct, 0, 0) != 0) { printf("ERROR running client Lua: %s\n", lua_tostring(lstate_client, -1)); lua_pop(lstate_client, 1); return 1; } printf("Done!\n"); boot_mode |= 4; return 0; } void icelua_pushversion(lua_State *L, const char *tabname) { char vbuf[32]; snprintf(vbuf, 31, "%i.%i", VERSION_W, VERSION_X); if(VERSION_Y != 0) snprintf(vbuf+strlen(vbuf), 31-strlen(vbuf), ".%i", VERSION_Y); if(VERSION_A != 0) snprintf(vbuf+strlen(vbuf), 31-strlen(vbuf), "%c", VERSION_A+96); if(VERSION_Z != 0) snprintf(vbuf+strlen(vbuf), 31-strlen(vbuf), "-%i", VERSION_Z); lua_getglobal(L, tabname); lua_newtable(L); lua_pushstring(L, vbuf); lua_setfield(L, -2, "str"); lua_pushinteger(L, (((((((VERSION_W<<5) + VERSION_X )<<7) + VERSION_Y )<<5) + VERSION_A )<<10) + VERSION_Z); lua_setfield(L, -2, "num"); lua_newtable(L); lua_pushinteger(L, 1); lua_pushinteger(L, VERSION_W); lua_settable(L, -3); lua_pushinteger(L, 2); lua_pushinteger(L, VERSION_X); lua_settable(L, -3); lua_pushinteger(L, 3); lua_pushinteger(L, VERSION_Y); lua_settable(L, -3); lua_pushinteger(L, 4); lua_pushinteger(L, VERSION_A); lua_settable(L, -3); lua_pushinteger(L, 5); lua_pushinteger(L, VERSION_Z); lua_settable(L, -3); lua_setfield(L, -2, "cmp"); lua_setfield(L, -2, "version"); // -mk<3 lua_newtable(L); lua_pushinteger(L, MK_REVISION); lua_setfield(L, -2, "num"); lua_setfield(L, -2, "fork_marikiri_ver"); lua_pop(L, 1); } int icelua_init(void) { int i, argct; // create states if(boot_mode & 1) { // create temp state for loading config lua_State *Lc = luaL_newstate(); int v; float f; // load config #ifndef DEDI if(!json_load(Lc, "clsave/config.json")) { // set video stuff lua_getfield(Lc, -1, "video"); lua_getfield(Lc, -1, "width"); v = lua_tointeger(Lc, -1); if(v >= 0) screen_width = v; lua_pop(Lc, 1); lua_getfield(Lc, -1, "height"); v = lua_tointeger(Lc, -1); if(v >= 0) screen_height = v; lua_pop(Lc, 1); lua_getfield(Lc, -1, "cubeshift"); v = lua_tointeger(Lc, -1); if(v != 0) screen_cubeshift = -v; lua_pop(Lc, 1); lua_getfield(Lc, -1, "antialiasinglevel"); v = lua_tointeger(Lc, -1); if(v >= 0) screen_antialiasing_level = v; lua_pop(Lc, 1); lua_getfield(Lc, -1, "smoothlighting"); v = lua_toboolean(Lc, -1); if(!lua_isnil(Lc, -1)) screen_smooth_lighting = v; lua_pop(Lc, 1); lua_getfield(Lc, -1, "gl_vsync"); v = lua_toboolean(Lc, -1); if(v >= 0) gl_vsync = v; lua_pop(Lc, 1); lua_getfield(Lc, -1, "gl_quality"); v = lua_tointeger(Lc, -1); if(v >= 0) gl_quality = v; lua_pop(Lc, 1); // backwards compatibility lua_getfield(Lc, -1, "vbo"); v = lua_toboolean(Lc, -1); if(!lua_isnil(Lc, -1)) { gl_use_vbo = v; printf("WARNING: clsave/config.json: \"vbo\" is deprecated - use \"gl_vbo\" instead\n"); } lua_pop(Lc, 1); lua_getfield(Lc, -1, "gl_vbo"); v = lua_toboolean(Lc, -1); if(!lua_isnil(Lc, -1)) gl_use_vbo = v; lua_pop(Lc, 1); lua_getfield(Lc, -1, "gl_flip_quads"); v = lua_toboolean(Lc, -1); if(!lua_isnil(Lc, -1)) gl_flip_quads = v; lua_pop(Lc, 1); lua_getfield(Lc, -1, "gl_frustum_cull"); v = lua_toboolean(Lc, -1); if(!lua_isnil(Lc, -1)) gl_frustum_cull = v; lua_pop(Lc, 1); lua_getfield(Lc, -1, "gl_occlusion_cull"); v = lua_tointeger(Lc, -1); if(!lua_isnil(Lc, -1)) gl_occlusion_cull = v; lua_pop(Lc, 1); lua_getfield(Lc, -1, "gl_expand_textures"); v = lua_toboolean(Lc, -1); if(!lua_isnil(Lc, -1)) gl_expand_textures = v; lua_pop(Lc, 1); lua_getfield(Lc, -1, "gl_chunk_size"); v = lua_tointeger(Lc, -1); if(v > 0) gl_chunk_size = v; lua_pop(Lc, 1); lua_getfield(Lc, -1, "gl_visible_chunks"); v = lua_tointeger(Lc, -1); if(v > 0) gl_visible_chunks = v; lua_pop(Lc, 1); lua_getfield(Lc, -1, "gl_chunks_tesselated_per_frame"); v = lua_tointeger(Lc, -1); if(v > 0) gl_chunks_tesselated_per_frame = v; lua_pop(Lc, 1); lua_getfield(Lc, -1, "fullscreen"); v = lua_toboolean(Lc, -1); if(!lua_isnil(Lc, -1)) screen_fullscreen = v; lua_pop(Lc, 1); // drop table lua_pop(Lc, 1); // set audio stuff lua_getfield(Lc, -1, "audio"); lua_getfield(Lc, -1, "freq"); v = lua_tointeger(Lc, -1); if(v >= 0) wav_mfreq = v; lua_pop(Lc, 1); lua_getfield(Lc, -1, "bufsize"); v = lua_tointeger(Lc, -1); if(v >= 0) wav_bufsize = v; lua_pop(Lc, 1); lua_getfield(Lc, -1, "volume"); f = lua_tonumber(Lc, -1); if(!lua_isnil(Lc, -1)) wav_gvol = f; lua_pop(Lc, 1); // drop table lua_pop(Lc, 1); // set security stuff lua_getfield(Lc, -1, "security"); lua_getfield(Lc, -1, "bin_storage_allowed"); v = lua_toboolean(Lc, -1); if(!lua_isnil(Lc, -1)) bin_storage_allowed = v; lua_pop(Lc, 1); { if(lua_istable(Lc, -1)) lua_getfield(Lc, -1, "raw_whitelist"); else lua_newtable(Lc); // allocate whitelist raw_whitelist_len = lua_objlen(Lc, -1); raw_whitelist = malloc(sizeof(struct icelua_whitelist)*raw_whitelist_len); // read each entry for(i = 0; i < raw_whitelist_len; i++) { printf("entry %i/%i\n", i+1, raw_whitelist_len); // get entry lua_pushinteger(Lc, i+1); lua_gettable(Lc, -2); if(lua_istable(Lc, -1)) { // check entries lua_pushinteger(Lc, 1); lua_gettable(Lc, -2); lua_pushinteger(Lc, 2); lua_gettable(Lc, -3); // check entries if(lua_isstring(Lc, -2) && lua_isnumber(Lc, -1)) { raw_whitelist[i].addr = strdup(lua_tostring(Lc, -2)); raw_whitelist[i].port = lua_tointeger(Lc, -1); printf("Whitelist entry %i/%i: \"%s\" port %i \n", i+1, raw_whitelist_len, raw_whitelist[i].addr, raw_whitelist[i].port); } else { // mark as invalid fprintf(stderr, "invalid entry %i/%i in whitelist!\n", i+1, raw_whitelist_len); raw_whitelist[i].addr = NULL; } // pop entries lua_pop(Lc, 2); } else { // mark as invalid fprintf(stderr, "invalid entry %i/%i in whitelist!\n", i+1, raw_whitelist_len); raw_whitelist[i].addr = NULL; } // pop entry lua_pop(Lc, 1); } // drop table lua_pop(Lc, 1); } // drop table lua_pop(Lc, 1); } #endif } lstate_client = (boot_mode & 1 ? luaL_newstate() : NULL); lstate_server = (boot_mode & 2 ? luaL_newstate() : NULL); // create tables if(lstate_client != NULL) { lua_newtable(lstate_client); lua_setglobal(lstate_client, "client"); lua_newtable(lstate_client); lua_setglobal(lstate_client, "common"); lua_pushvalue(lstate_client, LUA_GLOBALSINDEX); lua_setglobal(lstate_client, "_G"); } if(lstate_server != NULL) { lua_newtable(lstate_server); lua_setglobal(lstate_server, "server"); lua_newtable(lstate_server); lua_setglobal(lstate_server, "common"); lua_pushvalue(lstate_server, LUA_GLOBALSINDEX); lua_setglobal(lstate_server, "_G"); } // load stuff into them #ifndef DEDI icelua_loadfuncs(lstate_client, "client", icelua_client); icelua_loadfuncs(lstate_client, "client", icelua_common); icelua_loadfuncs(lstate_client, "common", icelua_common); icelua_loadfuncs(lstate_client, "client", icelua_common_client); icelua_loadfuncs(lstate_client, "common", icelua_common_client); #endif icelua_loadfuncs(lstate_server, "server", icelua_server); icelua_loadfuncs(lstate_server, "server", icelua_common); icelua_loadfuncs(lstate_server, "common", icelua_common); icelua_loadfuncs(lstate_server, "server", icelua_common_server); icelua_loadfuncs(lstate_server, "common", icelua_common_server); // load some lua base libraries icelua_loadbasefuncs(lstate_client); icelua_loadbasefuncs(lstate_server); // shove some pathnames / versions in if(lstate_server != NULL) { lua_getglobal(lstate_server, "common"); lua_getglobal(lstate_server, "server"); lua_pushstring(lstate_server, mod_basedir+4); lua_setfield(lstate_server, -2, "base_dir"); lua_pop(lstate_server, 1); lua_pushstring(lstate_server, mod_basedir+4); lua_setfield(lstate_server, -2, "base_dir"); lua_pop(lstate_server, 1); icelua_pushversion(lstate_server, "common"); icelua_pushversion(lstate_server, "server"); lua_getglobal(lstate_server, "server"); lua_pushinteger(lstate_server, net_port); lua_setfield(lstate_server, -2, "port"); lua_pop(lstate_server, 1); } if(lstate_client != NULL) { icelua_pushversion(lstate_client, "common"); icelua_pushversion(lstate_client, "client"); } /* NOTE: to call stuff, use lua_pcall. DO NOT use lua_call! if it fails, it will TERMINATE the program! */ // quick test // TODO: set up a "convert/filter file path" function // TODO: split the client/server inits char xpath[128]; snprintf(xpath, 128, "%s/main_server.lua", mod_basedir); if((lstate_server != NULL) && luaL_loadfile(lstate_server, xpath) != 0) { printf("ERROR loading server Lua: %s\n", lua_tostring(lstate_server, -1)); return 1; } argct = (main_largstart == -1 || (main_largstart >= main_argc) ? 0 : main_argc - main_largstart); if(lstate_server != NULL) { for(i = 0; i < argct; i++) lua_pushstring(lstate_server, main_argv[i+main_largstart]); if(lua_pcall(lstate_server, argct, 0, 0) != 0) { printf("ERROR running server Lua: %s\n", lua_tostring(lstate_server, -1)); lua_pop(lstate_server, 1); return 1; } } if(lstate_client != NULL && mod_basedir != NULL) if(icelua_initfetch()) return 1; // dispatch initial connect if(lstate_server != NULL && lstate_client != NULL) { lua_getglobal(lstate_server, "server"); lua_getfield(lstate_server, -1, "hook_connect"); lua_remove(lstate_server, -2); if(!lua_isnil(lstate_server, -1)) { lua_pushboolean(lstate_server, 1); lua_newtable(lstate_server); lua_pushstring(lstate_server, "local"); lua_setfield(lstate_server, -2, "proto"); lua_pushnil(lstate_server); lua_setfield(lstate_server, -2, "addr"); if(lua_pcall(lstate_server, 2, 0, 0) != 0) { printf("ERROR running server Lua (hook_connect): %s\n", lua_tostring(lstate_server, -1)); lua_pop(lstate_server, 2); return 1; } } else { lua_pop(lstate_server, 1); } } return 0; } void icelua_deinit(void) { // TODO! }