Merge pull request #353 from bjornbytes/plugins

Plugins;
This commit is contained in:
Bjorn 2020-12-31 17:18:42 -07:00 committed by GitHub
commit 6756a94cb9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 121 additions and 3068 deletions

1
.gitignore vendored
View File

@ -39,3 +39,4 @@ deps/VrApi
deps/pico
deps/openxr
deps/OpenXR-Oculus
/plugins/*

3
.gitmodules vendored
View File

@ -1,6 +1,3 @@
[submodule "deps/enet"]
path = deps/enet
url = https://github.com/lsalzman/enet
[submodule "deps/glfw"]
path = deps/glfw
url = https://github.com/glfw/glfw

View File

@ -14,9 +14,6 @@ option(LOVR_ENABLE_PHYSICS "Enable the physics module" ON)
option(LOVR_ENABLE_THREAD "Enable the thread module" ON)
option(LOVR_ENABLE_TIMER "Enable the timer module" ON)
option(LOVR_ENABLE_ENET "Bundle with lua-enet" ON)
option(LOVR_ENABLE_JSON "Bundle with lua-cjson" ON)
option(LOVR_USE_LUAJIT "Use LuaJIT instead of Lua" ON)
option(LOVR_USE_OPENVR "Enable the OpenVR backend for the headset module" ON)
option(LOVR_USE_OPENXR "Enable the OpenXR backend for the headset module" OFF)
@ -27,7 +24,6 @@ option(LOVR_USE_PICO "Enable the Pico backend for the headset module" OFF)
option(LOVR_USE_DESKTOP_HEADSET "Enable the keyboard/mouse backend for the headset module" ON)
option(LOVR_USE_LINUX_EGL "Use the EGL graphics extension on Linux" OFF)
option(LOVR_SYSTEM_ENET "Use the system-provided enet" OFF)
option(LOVR_SYSTEM_GLFW "Use the system-provided glfw" OFF)
option(LOVR_SYSTEM_LUA "Use the system-provided Lua" OFF)
option(LOVR_SYSTEM_ODE "Use the system-provided ODE" OFF)
@ -71,22 +67,6 @@ elseif(UNIX)
endif()
endif()
# enet
if(LOVR_ENABLE_ENET AND NOT EMSCRIPTEN)
if(LOVR_SYSTEM_ENET)
pkg_search_module(ENET REQUIRED enet)
include_directories(${ENET_INCLUDE_DIRS})
set(LOVR_ENET ${ENET_LIBRARIES})
else()
add_subdirectory(deps/enet enet)
include_directories(deps/enet/include)
set(LOVR_ENET enet)
if(WIN32)
set(LOVR_ENET ${LOVR_ENET} ws2_32 winmm)
endif()
endif()
endif()
# GLFW
if(NOT (EMSCRIPTEN OR ANDROID))
if(LOVR_SYSTEM_GLFW)
@ -296,23 +276,20 @@ endif()
# LÖVR
# Resources
file(GLOB LOVR_RESOURCES "src/resources/*.ttf" "src/resources/*.json" "src/resources/*.lua")
foreach(path ${LOVR_RESOURCES})
# Turn the absolute path into a C variable like src_resources_boot_lua
file(RELATIVE_PATH identifier ${CMAKE_CURRENT_SOURCE_DIR} ${path})
string(MAKE_C_IDENTIFIER ${identifier} identifier)
# Read the file and turn the bytes into comma-separated hex literals
file(READ ${path} data HEX)
string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," data ${data})
# Generate the output filename by adding .h to the input filename
string(CONCAT output ${path} ".h")
# Write some xxd-compatible C code!
file(WRITE ${output} "const unsigned char ${identifier}[] = {${data}};\nconst unsigned int ${identifier}_len = sizeof(${identifier});\n")
# Plugins
set(LOVR 1)
link_libraries(${LOVR_LUA})
file(GLOB LOVR_PLUGINS plugins/*)
foreach(plugin ${LOVR_PLUGINS})
if(IS_DIRECTORY ${plugin} AND EXISTS ${plugin}/CMakeLists.txt)
add_subdirectory(${plugin})
get_directory_property(PLUGIN_TARGETS DIRECTORY ${plugin} DEFINITION LOVR_PLUGIN_TARGETS)
if(NOT PLUGIN_TARGETS)
get_directory_property(PLUGIN_TARGETS DIRECTORY ${plugin} BUILDSYSTEM_TARGETS)
endif()
set_target_properties(${PLUGIN_TARGETS} PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/plugins/lib")
list(APPEND ALL_PLUGIN_TARGETS ${PLUGIN_TARGETS})
endif()
endforeach()
set(LOVR_SRC
@ -344,7 +321,6 @@ set_target_properties(lovr PROPERTIES C_VISIBILITY_PRESET hidden)
set_target_properties(lovr PROPERTIES C_STANDARD 99)
target_include_directories(lovr PRIVATE src src/modules)
target_link_libraries(lovr
${LOVR_ENET}
${LOVR_GLFW}
${LOVR_LUA}
${LOVR_MSDF}
@ -515,19 +491,24 @@ if(LOVR_ENABLE_TIMER)
target_sources(lovr PRIVATE src/modules/timer/timer.c src/api/l_timer.c)
endif()
if(LOVR_ENABLE_ENET)
target_compile_definitions(lovr PRIVATE LOVR_ENABLE_ENET)
target_sources(lovr PRIVATE src/lib/lua-enet/enet.c)
endif()
# Resources
file(GLOB LOVR_RESOURCES "src/resources/*.ttf" "src/resources/*.json" "src/resources/*.lua")
foreach(path ${LOVR_RESOURCES})
if(LOVR_ENABLE_JSON)
target_compile_definitions(lovr PRIVATE LOVR_ENABLE_JSON)
target_sources(lovr PRIVATE
src/lib/lua-cjson/fpconv.c
src/lib/lua-cjson/lua_cjson.c
src/lib/lua-cjson/strbuf.c
)
endif()
# Turn the absolute path into a C variable like src_resources_boot_lua
file(RELATIVE_PATH identifier ${CMAKE_CURRENT_SOURCE_DIR} ${path})
string(MAKE_C_IDENTIFIER ${identifier} identifier)
# Read the file and turn the bytes into comma-separated hex literals
file(READ ${path} data HEX)
string(REGEX REPLACE "([0-9a-f][0-9a-f])" "0x\\1," data ${data})
# Generate the output filename by adding .h to the input filename
string(CONCAT output ${path} ".h")
# Write some xxd-compatible C code!
file(WRITE ${output} "const unsigned char ${identifier}[] = {${data}};\nconst unsigned int ${identifier}_len = sizeof(${identifier});\n")
endforeach()
# Platforms
if(WIN32)
@ -558,6 +539,9 @@ if(WIN32)
move_dll(${LOVR_OPENAL})
move_dll(${LOVR_OPENVR})
move_dll(${LOVR_MSDF})
foreach(target ${ALL_PLUGIN_TARGETS})
move_dll(${target})
endforeach()
target_compile_definitions(lovr PRIVATE LOVR_GL)
elseif(APPLE)
target_link_libraries(lovr objc)
@ -580,6 +564,9 @@ elseif(APPLE)
move_lib(${LOVR_OPENAL})
move_lib(${LOVR_OPENVR})
move_lib(${LOVR_MSDF})
foreach(target ${ALL_PLUGIN_TARGETS})
move_lib(${target})
endforeach()
target_sources(lovr PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src/resources/lovr.icns")
set_target_properties(lovr PROPERTIES
@ -595,14 +582,14 @@ elseif(EMSCRIPTEN)
target_sources(lovr PRIVATE src/core/os_web.c)
target_compile_definitions(lovr PRIVATE LOVR_WEBGL)
elseif(ANDROID)
target_link_libraries(lovr log EGL GLESv3 android)
target_link_libraries(lovr log EGL GLESv3 android dl)
target_compile_definitions(lovr PRIVATE LOVR_GLES)
target_include_directories(lovr PRIVATE "${ANDROID_NDK}/sources/android/native_app_glue")
# Dynamically linked targets output libraries in lib/<ABI> for easy including in apk with aapt
# Dynamically linked targets output libraries in raw/lib/<ABI> for easy including in apk with aapt
set_target_properties(
lovr ${LOVR_ODE} ${LOVR_OPENAL}
PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/lib/${ANDROID_ABI}"
PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/raw/lib/${ANDROID_ABI}"
)
if(LOVR_BUILD_EXE)
@ -615,7 +602,7 @@ elseif(ANDROID)
endif()
# Flavor-specific config:
# - Imported targets need to have their libraries manually copied to lib/<ABI>
# - Imported targets need to have their libraries manually copied to raw/lib/<ABI>
# - Figure out which Java class (Activity) and AndroidManifest.xml to use
# - Oculus uses the regular android os layer, pico implements its own in the headset backend
# - Some of the Pico SDK is in a jar that has to be added to the classpath and dx invocation
@ -625,20 +612,20 @@ elseif(ANDROID)
set(ACTIVITY "openxr")
target_sources(lovr PRIVATE src/core/os_android.c)
get_target_property(OPENXR_LIB ${LOVR_OPENXR} IMPORTED_LOCATION)
file(COPY ${OPENXR_LIB} DESTINATION lib/${ANDROID_ABI})
file(COPY ${OPENXR_LIB} DESTINATION raw/lib/${ANDROID_ABI})
set(ANDROID_CLASSPATH "${ANDROID_JAR}")
elseif(LOVR_USE_VRAPI)
set(MANIFEST "oculus")
set(ACTIVITY "vrapi")
target_sources(lovr PRIVATE src/core/os_android.c)
get_target_property(VRAPI_LIB ${LOVR_VRAPI} IMPORTED_LOCATION)
file(COPY ${VRAPI_LIB} DESTINATION lib/${ANDROID_ABI})
file(COPY ${VRAPI_LIB} DESTINATION raw/lib/${ANDROID_ABI})
set(ANDROID_CLASSPATH "${ANDROID_JAR}")
elseif(LOVR_USE_PICO)
set(MANIFEST "pico")
set(ACTIVITY "pico")
get_target_property(PICO_LIB ${LOVR_PICO} IMPORTED_LOCATION)
file(COPY ${PICO_LIB} DESTINATION lib/${ANDROID_ABI})
file(COPY ${PICO_LIB} DESTINATION raw/lib/${ANDROID_ABI})
set(EXTRA_JAR "${LOVR_PICO_PATH}/classes.jar")
if(WIN32)
set(ANDROID_CLASSPATH "${ANDROID_JAR};${EXTRA_JAR}")
@ -660,28 +647,35 @@ elseif(ANDROID)
COMMAND ${CMAKE_COMMAND} -E copy "${ANDROID_MANIFEST}" AndroidManifest.xml
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/src/resources/Activity_${ACTIVITY}.java Activity.java
COMMAND ${Java_JAVAC_EXECUTABLE} -classpath "${ANDROID_CLASSPATH}" -d . Activity.java
COMMAND ${ANDROID_TOOLS}/dx --dex --output classes.dex ${EXTRA_JAR} org/lovr/app/Activity.class
COMMAND ${ANDROID_TOOLS}/dx --dex --output raw/classes.dex ${EXTRA_JAR} org/lovr/app/Activity.class
COMMAND
${ANDROID_TOOLS}/aapt
package -f
-0 so
-M AndroidManifest.xml
-I ${ANDROID_JAR}
-F lovr.unaligned.apk
${ANDROID_ASSETS}
COMMAND
${ANDROID_TOOLS}/aapt
add -f lovr.unaligned.apk
classes.dex lib/${ANDROID_ABI}/*.so
COMMAND ${ANDROID_TOOLS}/zipalign -f 4 lovr.unaligned.apk lovr.unsigned.apk
raw
COMMAND ${ANDROID_TOOLS}/zipalign -f -p 4 lovr.unaligned.apk lovr.unsigned.apk
COMMAND ${ANDROID_TOOLS}/apksigner
sign
--ks ${ANDROID_KEYSTORE}
${ANDROID_APKSIGNER_KEYSTORE_PASS} ${ANDROID_KEYSTORE_PASS}
--in lovr.unsigned.apk
--out lovr.apk
COMMAND ${CMAKE_COMMAND} -E remove lovr.unaligned.apk lovr.unsigned.apk AndroidManifest.xml Activity.java classes.dex
COMMAND ${CMAKE_COMMAND} -E remove lovr.unaligned.apk lovr.unsigned.apk AndroidManifest.xml Activity.java
COMMAND ${CMAKE_COMMAND} -E remove_directory org
)
# Copy plugin libraries to lib folder before packaging APK
foreach(target ${ALL_PLUGIN_TARGETS})
add_custom_command(TARGET lovr POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy
$<TARGET_FILE:${target}>
raw/lib/${ANDROID_ABI}/$<TARGET_FILE_NAME:${target}>
)
endforeach()
endif()
elseif(UNIX)
if(LOVR_USE_LINUX_EGL)

1
deps/enet vendored

@ -1 +0,0 @@
Subproject commit a84c120eff13d2fa3eadb41ef7afe0f7819f4d6c

View File

@ -169,8 +169,7 @@ static int l_lovrFilesystemGetRealDirectory(lua_State* L) {
static int l_lovrFilesystemGetRequirePath(lua_State* L) {
lua_pushstring(L, lovrFilesystemGetRequirePath());
lua_pushstring(L, lovrFilesystemGetCRequirePath());
return 2;
return 1;
}
static int l_lovrFilesystemGetSaveDirectory(lua_State* L) {
@ -298,8 +297,7 @@ static int l_lovrFilesystemSetIdentity(lua_State* L) {
}
static int l_lovrFilesystemSetRequirePath(lua_State* L) {
if (lua_type(L, 1) == LUA_TSTRING) lovrFilesystemSetRequirePath(lua_tostring(L, 1));
if (lua_type(L, 2) == LUA_TSTRING) lovrFilesystemSetCRequirePath(lua_tostring(L, 2));
lovrFilesystemSetRequirePath(luaL_checkstring(L, 1));
return 0;
}
@ -404,70 +402,67 @@ static int libLoader(lua_State* L) {
const char* module = lua_tostring(L, 1);
const char* hyphen = strchr(module, '-');
const char* symbol = hyphen ? hyphen + 1 : module;
const char* p = lovrFilesystemGetCRequirePath();
char filename[1024];
char* f = filename;
size_t n = sizeof(filename);
char path[1024];
lua_getglobal(L, "package");
while (1) {
if (*p == ';' || *p == '\0') {
*f = '\0';
// On Android, load libraries directly from the apk by passing a path like this to the linker:
// /path/to/app.apk!/lib/arm64-v8a/lib.so
// On desktop systems, look for libraries next to the executable
#ifdef __ANDROID__
const char* source = lovrFilesystemGetSource();
size_t length = strlen(source);
memcpy(path, source, length);
if (lovrFilesystemIsFile(filename)) {
lua_getfield(L, -1, "loadlib");
// Synthesize the absolute path to the library on disk
luaL_Buffer buffer;
luaL_buffinit(L, &buffer);
luaL_addstring(&buffer, lovrFilesystemGetRealDirectory(filename));
luaL_addchar(&buffer, LOVR_PATH_SEP);
luaL_addstring(&buffer, filename);
luaL_pushresult(&buffer);
// Synthesize the symbol to load: luaopen_ followed by the module name with dots converted
// to underscores, starting after the first hyphen (if there is one).
luaL_buffinit(L, &buffer);
luaL_addstring(&buffer, "luaopen_");
for (const char* s = symbol; *s; s++) {
luaL_addchar(&buffer, *s == '.' ? '_' : *s);
}
luaL_pushresult(&buffer);
// Finally call package.loadlib with the library path and symbol name
lua_call(L, 2, 1);
return 1;
}
if (*p == '\0') {
break;
} else {
p++;
f = filename;
n = sizeof(filename);
}
} else if (*p == '?') {
for (const char* m = module; n && *m; n--, m++) {
*f++ = *m == '.' ? LOVR_PATH_SEP : *m;
}
p++;
if (*p == '?') {
for (const char* e = extension; n && *e; n--, e++) {
*f++ = *e;
}
p++;
}
} else {
*f++ = *p++;
n--;
}
lovrAssert(n > 0, "Tried to require a filename that was too long (%s)", module);
const char* subpath = "!/lib/arm64-v8a/";
size_t subpathLength = strlen(subpath);
char* p = path + length;
if (length + subpathLength >= sizeof(path)) {
return 0;
}
return 0;
memcpy(p, subpath, subpathLength);
length += subpathLength;
p += subpathLength;
#else
size_t length = lovrFilesystemGetExecutablePath(path, sizeof(path));
if (length == 0) {
return 0;
}
char* slash = strrchr(path, LOVR_PATH_SEP);
char* p = slash ? slash + 1 : path;
length = p - path;
#endif
for (const char* m = module; *m && length < sizeof(path); m++, length++) {
*p++ = *m == '.' ? LOVR_PATH_SEP : *m;
}
for (const char* e = extension; *e && length < sizeof(path); e++, length++) {
*p++ = *e;
}
if (length >= sizeof(path)) {
return 0;
}
*p = '\0';
lua_getglobal(L, "package");
lua_getfield(L, -1, "loadlib");
lua_pushlstring(L, path, length);
// Synthesize luaopen_<module> symbol
luaL_Buffer buffer;
luaL_buffinit(L, &buffer);
luaL_addstring(&buffer, "luaopen_");
for (const char* s = symbol; *s; s++) {
luaL_addchar(&buffer, *s == '.' ? '_' : *s);
}
luaL_pushresult(&buffer);
lua_call(L, 2, 1);
return 1;
}
int luaopen_lovr_filesystem(lua_State* L) {

View File

@ -1,8 +1,6 @@
#include "api.h"
#include "core/os.h"
#include "core/util.h"
#include "lib/lua-cjson/lua_cjson.h"
#include "lib/lua-enet/enet.h"
const luaL_Reg lovrModules[] = {
{ "lovr", luaopen_lovr },
@ -35,12 +33,6 @@ const luaL_Reg lovrModules[] = {
#endif
#ifdef LOVR_ENABLE_TIMER
{ "lovr.timer", luaopen_lovr_timer },
#endif
#ifdef LOVR_ENABLE_JSON
{ "cjson", luaopen_cjson },
#endif
#ifdef LOVR_ENABLE_ENET
{ "enet", luaopen_enet },
#endif
{ NULL, NULL }
};

View File

@ -1,20 +0,0 @@
Copyright (c) 2010-2012 Mark Pulford <mark@kyne.com.au>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,205 +0,0 @@
/* fpconv - Floating point conversion routines
*
* Copyright (c) 2011-2012 Mark Pulford <mark@kyne.com.au>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/* JSON uses a '.' decimal separator. strtod() / sprintf() under C libraries
* with locale support will break when the decimal separator is a comma.
*
* fpconv_* will around these issues with a translation buffer if required.
*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>
#include "fpconv.h"
/* Lua CJSON assumes the locale is the same for all threads within a
* process and doesn't change after initialisation.
*
* This avoids the need for per thread storage or expensive checks
* for call. */
static char locale_decimal_point = '.';
/* In theory multibyte decimal_points are possible, but
* Lua CJSON only supports UTF-8 and known locales only have
* single byte decimal points ([.,]).
*
* localconv() may not be thread safe (=>crash), and nl_langinfo() is
* not supported on some platforms. Use sprintf() instead - if the
* locale does change, at least Lua CJSON won't crash. */
static void fpconv_update_locale()
{
char buf[8];
snprintf(buf, sizeof(buf), "%g", 0.5);
/* Failing this test might imply the platform has a buggy dtoa
* implementation or wide characters */
if (buf[0] != '0' || buf[2] != '5' || buf[3] != 0) {
fprintf(stderr, "Error: wide characters found or printf() bug.");
abort();
}
locale_decimal_point = buf[1];
}
/* Check for a valid number character: [-+0-9a-yA-Y.]
* Eg: -0.6e+5, infinity, 0xF0.F0pF0
*
* Used to find the probable end of a number. It doesn't matter if
* invalid characters are counted - strtod() will find the valid
* number if it exists. The risk is that slightly more memory might
* be allocated before a parse error occurs. */
static inline int valid_number_character(char ch)
{
char lower_ch;
if ('0' <= ch && ch <= '9')
return 1;
if (ch == '-' || ch == '+' || ch == '.')
return 1;
/* Hex digits, exponent (e), base (p), "infinity",.. */
lower_ch = ch | 0x20;
if ('a' <= lower_ch && lower_ch <= 'y')
return 1;
return 0;
}
/* Calculate the size of the buffer required for a strtod locale
* conversion. */
static int strtod_buffer_size(const char *s)
{
const char *p = s;
while (valid_number_character(*p))
p++;
return p - s;
}
/* Similar to strtod(), but must be passed the current locale's decimal point
* character. Guaranteed to be called at the start of any valid number in a string */
double fpconv_strtod(const char *nptr, char **endptr)
{
char localbuf[FPCONV_G_FMT_BUFSIZE];
char *buf, *endbuf, *dp;
int buflen;
double value;
/* System strtod() is fine when decimal point is '.' */
if (locale_decimal_point == '.')
return strtod(nptr, endptr);
buflen = strtod_buffer_size(nptr);
if (!buflen) {
/* No valid characters found, standard strtod() return */
*endptr = (char *)nptr;
return 0;
}
/* Duplicate number into buffer */
if (buflen >= FPCONV_G_FMT_BUFSIZE) {
/* Handle unusually large numbers */
buf = (char *)malloc(buflen + 1);
if (!buf) {
fprintf(stderr, "Out of memory");
abort();
}
} else {
/* This is the common case.. */
buf = localbuf;
}
memcpy(buf, nptr, buflen);
buf[buflen] = 0;
/* Update decimal point character if found */
dp = strchr(buf, '.');
if (dp)
*dp = locale_decimal_point;
value = strtod(buf, &endbuf);
*endptr = (char *)&nptr[endbuf - buf];
if (buflen >= FPCONV_G_FMT_BUFSIZE)
free(buf);
return value;
}
/* "fmt" must point to a buffer of at least 6 characters */
static void set_number_format(char *fmt, int precision)
{
int d1, d2, i;
assert(1 <= precision && precision <= 14);
/* Create printf format (%.14g) from precision */
d1 = precision / 10;
d2 = precision % 10;
fmt[0] = '%';
fmt[1] = '.';
i = 2;
if (d1) {
fmt[i++] = '0' + d1;
}
fmt[i++] = '0' + d2;
fmt[i++] = 'g';
fmt[i] = 0;
}
/* Assumes there is always at least 32 characters available in the target buffer */
int fpconv_g_fmt(char *str, double num, int precision)
{
char buf[FPCONV_G_FMT_BUFSIZE];
char fmt[6];
int len;
char *b;
set_number_format(fmt, precision);
/* Pass through when decimal point character is dot. */
if (locale_decimal_point == '.')
return snprintf(str, FPCONV_G_FMT_BUFSIZE, fmt, num);
/* snprintf() to a buffer then translate for other decimal point characters */
len = snprintf(buf, FPCONV_G_FMT_BUFSIZE, fmt, num);
/* Copy into target location. Translate decimal point if required */
b = buf;
do {
*str++ = (*b == locale_decimal_point ? '.' : *b);
} while(*b++);
return len;
}
void fpconv_init()
{
fpconv_update_locale();
}
/* vi:ai et sw=4 ts=4:
*/

View File

@ -1,22 +0,0 @@
/* Lua CJSON floating point conversion routines */
/* Buffer required to store the largest string representation of a double.
*
* Longest double printed with %.14g is 21 characters long:
* -1.7976931348623e+308 */
# define FPCONV_G_FMT_BUFSIZE 32
#ifdef USE_INTERNAL_FPCONV
static inline void fpconv_init()
{
/* Do nothing - not required */
}
#else
extern void fpconv_init();
#endif
extern int fpconv_g_fmt(char*, double, int);
extern double fpconv_strtod(const char*, char**);
/* vi:ai et sw=4 ts=4:
*/

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +0,0 @@
#include "api/api.h"
#pragma once
int luaopen_cjson(lua_State *l);

View File

@ -1,252 +0,0 @@
/* strbuf - String buffer routines
*
* Copyright (c) 2010-2012 Mark Pulford <mark@kyne.com.au>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "strbuf.h"
static void die(const char *fmt, ...)
{
va_list arg;
va_start(arg, fmt);
vfprintf(stderr, fmt, arg);
va_end(arg);
fprintf(stderr, "\n");
exit(-1);
}
void strbuf_init(strbuf_t *s, int len)
{
int size;
if (len <= 0)
size = STRBUF_DEFAULT_SIZE;
else
size = len + 1; /* \0 terminator */
s->buf = NULL;
s->size = size;
s->length = 0;
s->increment = STRBUF_DEFAULT_INCREMENT;
s->dynamic = 0;
s->reallocs = 0;
s->debug = 0;
s->buf = (char *)malloc(size);
if (!s->buf)
die("Out of memory");
strbuf_ensure_null(s);
}
strbuf_t *strbuf_new(int len)
{
strbuf_t *s;
s = (strbuf_t*)malloc(sizeof(strbuf_t));
if (!s)
die("Out of memory");
strbuf_init(s, len);
/* Dynamic strbuf allocation / deallocation */
s->dynamic = 1;
return s;
}
void strbuf_set_increment(strbuf_t *s, int increment)
{
/* Increment > 0: Linear buffer growth rate
* Increment < -1: Exponential buffer growth rate */
if (increment == 0 || increment == -1)
die("BUG: Invalid string increment");
s->increment = increment;
}
static inline void debug_stats(strbuf_t *s)
{
if (s->debug) {
fprintf(stderr, "strbuf(%p) reallocs: %d, length: %d, size: %d\n",
(void*) s, s->reallocs, s->length, s->size);
}
}
/* If strbuf_t has not been dynamically allocated, strbuf_free() can
* be called any number of times strbuf_init() */
void strbuf_free(strbuf_t *s)
{
debug_stats(s);
if (s->buf) {
free(s->buf);
s->buf = NULL;
}
if (s->dynamic)
free(s);
}
char *strbuf_free_to_string(strbuf_t *s, int *len)
{
char *buf;
debug_stats(s);
strbuf_ensure_null(s);
buf = s->buf;
if (len)
*len = s->length;
if (s->dynamic)
free(s);
return buf;
}
static int calculate_new_size(strbuf_t *s, int len)
{
int reqsize, newsize;
if (len <= 0)
die("BUG: Invalid strbuf length requested");
/* Ensure there is room for optional NULL termination */
reqsize = len + 1;
/* If the user has requested to shrink the buffer, do it exactly */
if (s->size > reqsize)
return reqsize;
newsize = s->size;
if (s->increment < 0) {
/* Exponential sizing */
while (newsize < reqsize)
newsize *= -s->increment;
} else {
/* Linear sizing */
newsize = ((newsize + s->increment - 1) / s->increment) * s->increment;
}
return newsize;
}
/* Ensure strbuf can handle a string length bytes long (ignoring NULL
* optional termination). */
void strbuf_resize(strbuf_t *s, int len)
{
int newsize;
newsize = calculate_new_size(s, len);
if (s->debug > 1) {
fprintf(stderr, "strbuf(%p) resize: %d => %d\n",
(void*) s, s->size, newsize);
}
s->size = newsize;
s->buf = (char *)realloc(s->buf, s->size);
if (!s->buf)
die("Out of memory");
s->reallocs++;
}
void strbuf_append_string(strbuf_t *s, const char *str)
{
int space, i;
space = strbuf_empty_length(s);
for (i = 0; str[i]; i++) {
if (space < 1) {
strbuf_resize(s, s->length + 1);
space = strbuf_empty_length(s);
}
s->buf[s->length] = str[i];
s->length++;
space--;
}
}
/* strbuf_append_fmt() should only be used when an upper bound
* is known for the output string. */
void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...)
{
va_list arg;
int fmt_len;
strbuf_ensure_empty_length(s, len);
va_start(arg, fmt);
fmt_len = vsnprintf(s->buf + s->length, len, fmt, arg);
va_end(arg);
if (fmt_len < 0)
die("BUG: Unable to convert number"); /* This should never happen.. */
s->length += fmt_len;
}
/* strbuf_append_fmt_retry() can be used when the there is no known
* upper bound for the output string. */
void strbuf_append_fmt_retry(strbuf_t *s, const char *fmt, ...)
{
va_list arg;
int fmt_len;
int empty_len;
int t;
/* If the first attempt to append fails, resize the buffer appropriately
* and try again */
for (t = 0; ; t++) {
va_start(arg, fmt);
/* Append the new formatted string */
/* fmt_len is the length of the string required, excluding the
* trailing NULL */
empty_len = strbuf_empty_length(s);
/* Add 1 since there is also space to store the terminating NULL. */
fmt_len = vsnprintf(s->buf + s->length, empty_len + 1, fmt, arg);
va_end(arg);
if (fmt_len <= empty_len)
break; /* SUCCESS */
if (t > 0)
die("BUG: length of formatted string changed");
strbuf_resize(s, s->length + fmt_len);
}
s->length += fmt_len;
}
/* vi:ai et sw=4 ts=4:
*/

View File

@ -1,154 +0,0 @@
/* strbuf - String buffer routines
*
* Copyright (c) 2010-2012 Mark Pulford <mark@kyne.com.au>
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdarg.h>
/* Size: Total bytes allocated to *buf
* Length: String length, excluding optional NULL terminator.
* Increment: Allocation increments when resizing the string buffer.
* Dynamic: True if created via strbuf_new()
*/
typedef struct {
char *buf;
int size;
int length;
int increment;
int dynamic;
int reallocs;
int debug;
} strbuf_t;
#ifndef STRBUF_DEFAULT_SIZE
#define STRBUF_DEFAULT_SIZE 1023
#endif
#ifndef STRBUF_DEFAULT_INCREMENT
#define STRBUF_DEFAULT_INCREMENT -2
#endif
/* Initialise */
extern strbuf_t *strbuf_new(int len);
extern void strbuf_init(strbuf_t *s, int len);
extern void strbuf_set_increment(strbuf_t *s, int increment);
/* Release */
extern void strbuf_free(strbuf_t *s);
extern char *strbuf_free_to_string(strbuf_t *s, int *len);
/* Management */
extern void strbuf_resize(strbuf_t *s, int len);
static int strbuf_empty_length(strbuf_t *s);
static int strbuf_length(strbuf_t *s);
static char *strbuf_string(strbuf_t *s, int *len);
static void strbuf_ensure_empty_length(strbuf_t *s, int len);
static char *strbuf_empty_ptr(strbuf_t *s);
static void strbuf_extend_length(strbuf_t *s, int len);
/* Update */
extern void strbuf_append_fmt(strbuf_t *s, int len, const char *fmt, ...);
extern void strbuf_append_fmt_retry(strbuf_t *s, const char *format, ...);
static void strbuf_append_mem(strbuf_t *s, const char *c, int len);
extern void strbuf_append_string(strbuf_t *s, const char *str);
static void strbuf_append_char(strbuf_t *s, const char c);
static void strbuf_ensure_null(strbuf_t *s);
/* Reset string for before use */
static inline void strbuf_reset(strbuf_t *s)
{
s->length = 0;
}
static inline int strbuf_allocated(strbuf_t *s)
{
return s->buf != NULL;
}
/* Return bytes remaining in the string buffer
* Ensure there is space for a NULL terminator. */
static inline int strbuf_empty_length(strbuf_t *s)
{
return s->size - s->length - 1;
}
static inline void strbuf_ensure_empty_length(strbuf_t *s, int len)
{
if (len > strbuf_empty_length(s))
strbuf_resize(s, s->length + len);
}
static inline char *strbuf_empty_ptr(strbuf_t *s)
{
return s->buf + s->length;
}
static inline void strbuf_extend_length(strbuf_t *s, int len)
{
s->length += len;
}
static inline int strbuf_length(strbuf_t *s)
{
return s->length;
}
static inline void strbuf_append_char(strbuf_t *s, const char c)
{
strbuf_ensure_empty_length(s, 1);
s->buf[s->length++] = c;
}
static inline void strbuf_append_char_unsafe(strbuf_t *s, const char c)
{
s->buf[s->length++] = c;
}
static inline void strbuf_append_mem(strbuf_t *s, const char *c, int len)
{
strbuf_ensure_empty_length(s, len);
memcpy(s->buf + s->length, c, len);
s->length += len;
}
static inline void strbuf_append_mem_unsafe(strbuf_t *s, const char *c, int len)
{
memcpy(s->buf + s->length, c, len);
s->length += len;
}
static inline void strbuf_ensure_null(strbuf_t *s)
{
s->buf[s->length] = 0;
}
static inline char *strbuf_string(strbuf_t *s, int *len)
{
if (len)
*len = s->length;
return s->buf;
}
/* vi:ai et sw=4 ts=4:
*/

View File

@ -1,808 +0,0 @@
/**
*
* Copyright (C) 2014 by Leaf Corcoran
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALING IN
* THE SOFTWARE.
*/
#include <stdlib.h>
#include <string.h>
// For lua5.2 support, instead we could replace all the luaL_register's with whatever
// lua5.2's equivalent function is, but this is easier so whatever.
#define LUA_COMPAT_MODULE
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
#include <enet/enet.h>
#include <stdbool.h>
#define check_host(l, idx)\
*(ENetHost**)luaL_checkudata(l, idx, "enet_host")
#define check_peer(l, idx)\
*(ENetPeer**)luaL_checkudata(l, idx, "enet_peer")
/**
* Parse address string, eg:
* *:5959
* 127.0.0.1:*
* website.com:8080
*/
static void parse_address(lua_State *l, const char *addr_str, ENetAddress *address) {
int host_i = 0, port_i = 0;
char host_str[128] = {0};
char port_str[32] = {0};
int scanning_port = 0;
char *c = (char *)addr_str;
while (*c != 0) {
if (host_i >= 128 || port_i >= 32 ) luaL_error(l, "Hostname too long");
if (scanning_port) {
port_str[port_i++] = *c;
} else {
if (*c == ':') {
scanning_port = 1;
} else {
host_str[host_i++] = *c;
}
}
c++;
}
host_str[host_i] = '\0';
port_str[port_i] = '\0';
if (host_i == 0) luaL_error(l, "Failed to parse address");
if (port_i == 0) luaL_error(l, "Missing port in address");
if (strcmp("*", host_str) == 0) {
address->host = ENET_HOST_ANY;
} else {
if (enet_address_set_host(address, host_str) != 0) {
luaL_error(l, "Failed to resolve host name");
}
}
if (strcmp("*", port_str) == 0) {
address->port = ENET_PORT_ANY;
} else {
address->port = atoi(port_str);
}
}
/**
* Find the index of a given peer for which we only have the pointer.
*/
size_t find_peer_index (lua_State *l, ENetHost *enet_host, ENetPeer *peer) {
size_t peer_index;
for (peer_index = 0; peer_index < enet_host->peerCount; peer_index++) {
if (peer == &(enet_host->peers[peer_index]))
return peer_index;
}
luaL_error (l, "enet: could not find peer id!");
return peer_index;
}
static void push_peer(lua_State *l, ENetPeer *peer) {
// try to find in peer table
lua_getfield(l, LUA_REGISTRYINDEX, "enet_peers");
lua_pushlightuserdata(l, peer);
lua_gettable(l, -2);
if (lua_isnil(l, -1)) {
// printf("creating new peer\n");
lua_pop(l, 1);
*(ENetPeer**)lua_newuserdata(l, sizeof(void*)) = peer;
luaL_getmetatable(l, "enet_peer");
lua_setmetatable(l, -2);
lua_pushlightuserdata(l, peer);
lua_pushvalue(l, -2);
lua_settable(l, -4);
}
lua_remove(l, -2); // remove enet_peers
}
static void push_event(lua_State *l, ENetEvent *event) {
lua_newtable(l); // event table
if (event->peer) {
push_peer(l, event->peer);
lua_setfield(l, -2, "peer");
}
switch (event->type) {
case ENET_EVENT_TYPE_CONNECT:
lua_pushinteger(l, event->data);
lua_setfield(l, -2, "data");
lua_pushstring(l, "connect");
break;
case ENET_EVENT_TYPE_DISCONNECT:
lua_pushinteger(l, event->data);
lua_setfield(l, -2, "data");
lua_pushstring(l, "disconnect");
break;
case ENET_EVENT_TYPE_RECEIVE:
lua_pushlstring(l, (const char *)event->packet->data, event->packet->dataLength);
lua_setfield(l, -2, "data");
lua_pushinteger(l, event->channelID);
lua_setfield(l, -2, "channel");
lua_pushstring(l, "receive");
enet_packet_destroy(event->packet);
break;
case ENET_EVENT_TYPE_NONE:
lua_pushstring(l, "none");
break;
}
lua_setfield(l, -2, "type");
}
/**
* Read a packet off the stack as a string
* idx is position of string
*/
static ENetPacket *read_packet(lua_State *l, int idx, enet_uint8 *channel_id) {
size_t size;
int argc = lua_gettop(l);
const void *data = luaL_checklstring(l, idx, &size);
ENetPacket *packet;
enet_uint32 flags = ENET_PACKET_FLAG_RELIABLE;
*channel_id = 0;
if (argc >= idx+2 && !lua_isnil(l, idx+2)) {
const char *flag_str = luaL_checkstring(l, idx+2);
if (strcmp("unsequenced", flag_str) == 0) {
flags = ENET_PACKET_FLAG_UNSEQUENCED;
} else if (strcmp("reliable", flag_str) == 0) {
flags = ENET_PACKET_FLAG_RELIABLE;
} else if (strcmp("unreliable", flag_str) == 0) {
flags = 0;
} else {
luaL_error(l, "Unknown packet flag: %s", flag_str);
}
}
if (argc >= idx+1 && !lua_isnil(l, idx+1)) {
*channel_id = luaL_checkint(l, idx+1);
}
packet = enet_packet_create(data, size, flags);
if (packet == NULL) {
luaL_error(l, "Failed to create packet");
}
return packet;
}
/**
* Create a new host
* Args:
* address (nil for client)
* [peer_count = 64]
* [channel_count = 1]
* [in_bandwidth = 0]
* [out_bandwidth = 0]
*/
static int host_create(lua_State *l) {
ENetHost *host;
size_t peer_count = 64, channel_count = 1;
enet_uint32 in_bandwidth = 0, out_bandwidth = 0;
int have_address = 1;
ENetAddress address;
if (lua_gettop(l) == 0 || lua_isnil(l, 1)) {
have_address = 0;
} else {
parse_address(l, luaL_checkstring(l, 1), &address);
}
switch (lua_gettop(l)) {
case 5:
if (!lua_isnil(l, 5)) out_bandwidth = luaL_checkint(l, 5);
case 4:
if (!lua_isnil(l, 4)) in_bandwidth = luaL_checkint(l, 4);
case 3:
if (!lua_isnil(l, 3)) channel_count = luaL_checkint(l, 3);
case 2:
if (!lua_isnil(l, 2)) peer_count = luaL_checkint(l, 2);
}
// printf("host create, peers=%d, channels=%d, in=%d, out=%d\n",
// peer_count, channel_count, in_bandwidth, out_bandwidth);
host = enet_host_create(have_address ? &address : NULL, peer_count,
channel_count, in_bandwidth, out_bandwidth);
if (host == NULL) {
lua_pushnil (l);
lua_pushstring(l, "enet: failed to create host (already listening?)");
return 2;
}
*(ENetHost**)lua_newuserdata(l, sizeof(void*)) = host;
luaL_getmetatable(l, "enet_host");
lua_setmetatable(l, -2);
return 1;
}
static int linked_version(lua_State *l) {
lua_pushfstring(l, "%d.%d.%d",
ENET_VERSION_GET_MAJOR(enet_linked_version()),
ENET_VERSION_GET_MINOR(enet_linked_version()),
ENET_VERSION_GET_PATCH(enet_linked_version()));
return 1;
}
/**
* Serice a host
* Args:
* timeout
*
* Return
* nil on no event
* an event table on event
*/
static int host_service(lua_State *l) {
ENetHost *host = check_host(l, 1);
if (!host) {
return luaL_error(l, "Tried to index a nil host!");
}
ENetEvent event;
int timeout = 0, out;
if (lua_gettop(l) > 1)
timeout = luaL_checkint(l, 2);
out = enet_host_service(host, &event, timeout);
if (out == 0) return 0;
if (out < 0) return luaL_error(l, "Error during service");
push_event(l, &event);
return 1;
}
/**
* Dispatch a single event if available
*/
static int host_check_events(lua_State *l) {
ENetHost *host = check_host(l, 1);
if (!host) {
return luaL_error(l, "Tried to index a nil host!");
}
ENetEvent event;
int out = enet_host_check_events(host, &event);
if (out == 0) return 0;
if (out < 0) return luaL_error(l, "Error checking event");
push_event(l, &event);
return 1;
}
/**
* Enables an adaptive order-2 PPM range coder for the transmitted data of
* all peers.
*/
static int host_compress_with_range_coder(lua_State *l) {
ENetHost *host = check_host(l, 1);
if (!host) {
return luaL_error(l, "Tried to index a nil host!");
}
int result = enet_host_compress_with_range_coder (host);
if (result == 0) {
lua_pushboolean (l, 1);
} else {
lua_pushboolean (l, 0);
}
return 1;
}
/**
* Connect a host to an address
* Args:
* the address
* [channel_count = 1]
* [data = 0]
*/
static int host_connect(lua_State *l) {
ENetHost *host = check_host(l, 1);
if (!host) {
return luaL_error(l, "Tried to index a nil host!");
}
ENetAddress address;
ENetPeer *peer;
enet_uint32 data = 0;
size_t channel_count = 1;
parse_address(l, luaL_checkstring(l, 2), &address);
switch (lua_gettop(l)) {
case 4:
if (!lua_isnil(l, 4)) data = luaL_checkint(l, 4);
case 3:
if (!lua_isnil(l, 3)) channel_count = luaL_checkint(l, 3);
}
// printf("host connect, channels=%d, data=%d\n", channel_count, data);
peer = enet_host_connect(host, &address, channel_count, data);
if (peer == NULL) {
return luaL_error(l, "Failed to create peer");
}
push_peer(l, peer);
return 1;
}
static int host_flush(lua_State *l) {
ENetHost *host = check_host(l, 1);
if (!host) {
return luaL_error(l, "Tried to index a nil host!");
}
enet_host_flush(host);
return 0;
}
static int host_broadcast(lua_State *l) {
ENetHost *host = check_host(l, 1);
if (!host) {
return luaL_error(l, "Tried to index a nil host!");
}
enet_uint8 channel_id;
ENetPacket *packet = read_packet(l, 2, &channel_id);
enet_host_broadcast(host, channel_id, packet);
return 0;
}
// Args: limit:number
static int host_channel_limit(lua_State *l) {
ENetHost *host = check_host(l, 1);
if (!host) {
return luaL_error(l, "Tried to index a nil host!");
}
int limit = luaL_checkint(l, 2);
enet_host_channel_limit(host, limit);
return 0;
}
static int host_bandwidth_limit(lua_State *l) {
ENetHost *host = check_host(l, 1);
if (!host) {
return luaL_error(l, "Tried to index a nil host!");
}
enet_uint32 in_bandwidth = luaL_checkint(l, 2);
enet_uint32 out_bandwidth = luaL_checkint(l, 2);
enet_host_bandwidth_limit(host, in_bandwidth, out_bandwidth);
return 0;
}
static int host_get_socket_address(lua_State *l) {
ENetHost *host = check_host(l, 1);
if (!host) {
return luaL_error(l, "Tried to index a nil host!");
}
ENetAddress address;
enet_socket_get_address (host->socket, &address);
lua_pushfstring(l, "%d.%d.%d.%d:%d",
((address.host) & 0xFF),
((address.host >> 8) & 0xFF),
((address.host >> 16) & 0xFF),
(address.host >> 24& 0xFF),
address.port);
return 1;
}
static int host_total_sent_data(lua_State *l) {
ENetHost *host = check_host(l, 1);
if (!host) {
return luaL_error(l, "Tried to index a nil host!");
}
lua_pushinteger (l, host->totalSentData);
return 1;
}
static int host_total_received_data(lua_State *l) {
ENetHost *host = check_host(l, 1);
if (!host) {
return luaL_error(l, "Tried to index a nil host!");
}
lua_pushinteger (l, host->totalReceivedData);
return 1;
}
static int host_service_time(lua_State *l) {
ENetHost *host = check_host(l, 1);
if (!host) {
return luaL_error(l, "Tried to index a nil host!");
}
lua_pushinteger (l, host->serviceTime);
return 1;
}
static int host_peer_count(lua_State *l) {
ENetHost *host = check_host(l, 1);
if (!host) {
return luaL_error(l, "Tried to index a nil host!");
}
lua_pushinteger (l, host->peerCount);
return 1;
}
static int host_get_peer(lua_State *l) {
ENetHost *host = check_host(l, 1);
if (!host) {
return luaL_error(l, "Tried to index a nil host!");
}
size_t peer_index = (size_t) luaL_checkint(l, 2) - 1;
if (peer_index >= host->peerCount) {
luaL_argerror (l, 2, "Invalid peer index");
}
ENetPeer *peer = &(host->peers[peer_index]);
push_peer (l, peer);
return 1;
}
static int host_gc(lua_State *l) {
// We have to manually grab the userdata so that we can set it to NULL.
ENetHost** host = luaL_checkudata(l, 1, "enet_host");
// We don't want to crash by destroying a non-existant host.
if (*host) {
enet_host_destroy(*host);
}
*host = NULL;
return 0;
}
static int peer_tostring(lua_State *l) {
ENetPeer *peer = check_peer(l, 1);
char host_str[128];
enet_address_get_host_ip(&peer->address, host_str, 128);
lua_pushstring(l, host_str);
lua_pushstring(l, ":");
lua_pushinteger(l, peer->address.port);
lua_concat(l, 3);
return 1;
}
static int peer_ping(lua_State *l) {
ENetPeer *peer = check_peer(l, 1);
enet_peer_ping(peer);
return 0;
}
static int peer_throttle_configure(lua_State *l) {
ENetPeer *peer = check_peer(l, 1);
enet_uint32 interval = luaL_checkint(l, 2);
enet_uint32 acceleration = luaL_checkint(l, 3);
enet_uint32 deceleration = luaL_checkint(l, 4);
enet_peer_throttle_configure(peer, interval, acceleration, deceleration);
return 0;
}
static int peer_round_trip_time(lua_State *l) {
ENetPeer *peer = check_peer(l, 1);
if (lua_gettop(l) > 1) {
enet_uint32 round_trip_time = luaL_checkint(l, 2);
peer->roundTripTime = round_trip_time;
}
lua_pushinteger (l, peer->roundTripTime);
return 1;
}
static int peer_last_round_trip_time(lua_State *l) {
ENetPeer *peer = check_peer(l, 1);
if (lua_gettop(l) > 1) {
enet_uint32 round_trip_time = luaL_checkint(l, 2);
peer->lastRoundTripTime = round_trip_time;
}
lua_pushinteger (l, peer->lastRoundTripTime);
return 1;
}
static int peer_ping_interval(lua_State *l) {
ENetPeer *peer = check_peer(l, 1);
if (lua_gettop(l) > 1) {
enet_uint32 interval = luaL_checkint(l, 2);
enet_peer_ping_interval (peer, interval);
}
lua_pushinteger (l, peer->pingInterval);
return 1;
}
static int peer_timeout(lua_State *l) {
ENetPeer *peer = check_peer(l, 1);
enet_uint32 timeout_limit = 0;
enet_uint32 timeout_minimum = 0;
enet_uint32 timeout_maximum = 0;
switch (lua_gettop(l)) {
case 4:
if (!lua_isnil(l, 4)) timeout_maximum = luaL_checkint(l, 4);
case 3:
if (!lua_isnil(l, 3)) timeout_minimum = luaL_checkint(l, 3);
case 2:
if (!lua_isnil(l, 2)) timeout_limit = luaL_checkint(l, 2);
}
enet_peer_timeout (peer, timeout_limit, timeout_minimum, timeout_maximum);
lua_pushinteger (l, peer->timeoutLimit);
lua_pushinteger (l, peer->timeoutMinimum);
lua_pushinteger (l, peer->timeoutMaximum);
return 3;
}
static int peer_disconnect(lua_State *l) {
ENetPeer *peer = check_peer(l, 1);
enet_uint32 data = lua_gettop(l) > 1 ? luaL_checkint(l, 2) : 0;
enet_peer_disconnect(peer, data);
return 0;
}
static int peer_disconnect_now(lua_State *l) {
ENetPeer *peer = check_peer(l, 1);
enet_uint32 data = lua_gettop(l) > 1 ? luaL_checkint(l, 2) : 0;
enet_peer_disconnect_now(peer, data);
return 0;
}
static int peer_disconnect_later(lua_State *l) {
ENetPeer *peer = check_peer(l, 1);
enet_uint32 data = lua_gettop(l) > 1 ? luaL_checkint(l, 2) : 0;
enet_peer_disconnect_later(peer, data);
return 0;
}
static int peer_index(lua_State *l) {
ENetPeer *peer = check_peer(l, 1);
size_t peer_index = find_peer_index (l, peer->host, peer);
lua_pushinteger (l, peer_index + 1);
return 1;
}
static int peer_state(lua_State *l) {
ENetPeer *peer = check_peer(l, 1);
switch (peer->state) {
case (ENET_PEER_STATE_DISCONNECTED):
lua_pushstring (l, "disconnected");
break;
case (ENET_PEER_STATE_CONNECTING):
lua_pushstring (l, "connecting");
break;
case (ENET_PEER_STATE_ACKNOWLEDGING_CONNECT):
lua_pushstring (l, "acknowledging_connect");
break;
case (ENET_PEER_STATE_CONNECTION_PENDING):
lua_pushstring (l, "connection_pending");
break;
case (ENET_PEER_STATE_CONNECTION_SUCCEEDED):
lua_pushstring (l, "connection_succeeded");
break;
case (ENET_PEER_STATE_CONNECTED):
lua_pushstring (l, "connected");
break;
case (ENET_PEER_STATE_DISCONNECT_LATER):
lua_pushstring (l, "disconnect_later");
break;
case (ENET_PEER_STATE_DISCONNECTING):
lua_pushstring (l, "disconnecting");
break;
case (ENET_PEER_STATE_ACKNOWLEDGING_DISCONNECT):
lua_pushstring (l, "acknowledging_disconnect");
break;
case (ENET_PEER_STATE_ZOMBIE):
lua_pushstring (l, "zombie");
break;
default:
lua_pushstring (l, "unknown");
}
return 1;
}
static int peer_connect_id(lua_State *l) {
ENetPeer *peer = check_peer(l, 1);
lua_pushinteger (l, peer->connectID);
return 1;
}
static int peer_reset(lua_State *l) {
ENetPeer *peer = check_peer(l, 1);
enet_peer_reset(peer);
return 0;
}
static int peer_receive(lua_State *l) {
ENetPeer *peer = check_peer(l, 1);
ENetPacket *packet;
enet_uint8 channel_id = 0;
if (lua_gettop(l) > 1) {
channel_id = luaL_checkint(l, 2);
}
packet = enet_peer_receive(peer, &channel_id);
if (packet == NULL) return 0;
lua_pushlstring(l, (const char *)packet->data, packet->dataLength);
lua_pushinteger(l, channel_id);
enet_packet_destroy(packet);
return 2;
}
/**
* Send a lua string to a peer
* Args:
* packet data, string
* channel id
* flags ["reliable", nil]
*
*/
static int peer_send(lua_State *l) {
ENetPeer *peer = check_peer(l, 1);
enet_uint8 channel_id;
ENetPacket *packet = read_packet(l, 2, &channel_id);
// printf("sending, channel_id=%d\n", channel_id);
enet_peer_send(peer, channel_id, packet);
return 0;
}
static const struct luaL_Reg enet_funcs [] = {
{"host_create", host_create},
{"linked_version", linked_version},
{NULL, NULL}
};
static const struct luaL_Reg enet_host_funcs [] = {
{"service", host_service},
{"check_events", host_check_events},
{"compress_with_range_coder", host_compress_with_range_coder},
{"connect", host_connect},
{"flush", host_flush},
{"broadcast", host_broadcast},
{"channel_limit", host_channel_limit},
{"bandwidth_limit", host_bandwidth_limit},
// Since ENetSocket isn't part of enet-lua, we should try to keep
// naming conventions the same as the rest of the lib.
{"get_socket_address", host_get_socket_address},
// We need this function to free up our ports when needed!
{"destroy", host_gc},
// additional convenience functions (mostly accessors)
{"total_sent_data", host_total_sent_data},
{"total_received_data", host_total_received_data},
{"service_time", host_service_time},
{"peer_count", host_peer_count},
{"get_peer", host_get_peer},
{NULL, NULL}
};
static const struct luaL_Reg enet_peer_funcs [] = {
{"disconnect", peer_disconnect},
{"disconnect_now", peer_disconnect_now},
{"disconnect_later", peer_disconnect_later},
{"reset", peer_reset},
{"ping", peer_ping},
{"receive", peer_receive},
{"send", peer_send},
{"throttle_configure", peer_throttle_configure},
{"ping_interval", peer_ping_interval},
{"timeout", peer_timeout},
// additional convenience functions to member variables
{"index", peer_index},
{"state", peer_state},
{"connect_id", peer_connect_id},
{"round_trip_time", peer_round_trip_time},
{"last_round_trip_time", peer_last_round_trip_time},
{NULL, NULL}
};
static bool enitAlreadyInit = false;
int luaopen_enet(lua_State *l) {
enet_initialize();
if (!enitAlreadyInit) {
atexit(enet_deinitialize);
enitAlreadyInit = true;
}
// create metatables
luaL_newmetatable(l, "enet_host");
lua_newtable(l); // index
luaL_register(l, NULL, enet_host_funcs);
lua_setfield(l, -2, "__index");
lua_pushcfunction(l, host_gc);
lua_setfield(l, -2, "__gc");
luaL_newmetatable(l, "enet_peer");
lua_newtable(l);
luaL_register(l, NULL, enet_peer_funcs);
lua_setfield(l, -2, "__index");
lua_pushcfunction(l, peer_tostring);
lua_setfield(l, -2, "__tostring");
// set up peer table
lua_newtable(l);
lua_newtable(l); // metatable
lua_pushstring(l, "v");
lua_setfield(l, -2, "__mode");
lua_setmetatable(l, -2);
lua_setfield(l, LUA_REGISTRYINDEX, "enet_peers");
luaL_register(l, "enet", enet_funcs);
return 1;
}

View File

@ -1,5 +0,0 @@
#include "api/api.h"
#pragma once
int luaopen_enet(lua_State *l);

View File

@ -59,7 +59,7 @@ static struct {
size_t savePathLength;
char savePath[1024];
char source[1024];
char requirePath[2][1024];
char requirePath[1024];
char identity[64];
bool fused;
} state;
@ -116,7 +116,6 @@ bool lovrFilesystemInit(const char* argExe, const char* argGame, const char* arg
arr_reserve(&state.archives, 2);
lovrFilesystemSetRequirePath("?.lua;?/init.lua");
lovrFilesystemSetCRequirePath("??");
// First, try to mount a bundled archive
const char* root = NULL;
@ -407,19 +406,11 @@ size_t lovrFilesystemGetWorkingDirectory(char* buffer, size_t size) {
}
const char* lovrFilesystemGetRequirePath() {
return state.requirePath[0];
}
const char* lovrFilesystemGetCRequirePath() {
return state.requirePath[1];
return state.requirePath;
}
void lovrFilesystemSetRequirePath(const char* requirePath) {
strncpy(state.requirePath[0], requirePath, sizeof(state.requirePath[0]) - 1);
}
void lovrFilesystemSetCRequirePath(const char* requirePath) {
strncpy(state.requirePath[1], requirePath, sizeof(state.requirePath[1]) - 1);
strncpy(state.requirePath, requirePath, sizeof(state.requirePath) - 1);
}
// Archive: dir

View File

@ -36,6 +36,4 @@ size_t lovrFilesystemGetExecutablePath(char* buffer, size_t size);
size_t lovrFilesystemGetUserDirectory(char* buffer, size_t size);
size_t lovrFilesystemGetWorkingDirectory(char* buffer, size_t size);
const char* lovrFilesystemGetRequirePath(void);
const char* lovrFilesystemGetCRequirePath(void);
void lovrFilesystemSetRequirePath(const char* requirePath);
void lovrFilesystemSetCRequirePath(const char* requirePath);

View File

@ -7,7 +7,7 @@
<uses-permission android:name="oculus.permission.HAND_TRACKING"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<application android:allowBackup="false" android:label="LÖVR">
<application android:allowBackup="false" android:label="LÖVR" android:extractNativeLibs="false">
<meta-data android:name="com.samsung.android.vr.application.mode" android:value="vr_only"/>
<activity android:name="Activity">
<meta-data android:name="android.app.lib_name" android:value="lovr"/>