basic lua support

This commit is contained in:
milek7
2017-08-30 13:55:07 +02:00
parent 1f2d7feccb
commit 5644206e42
13 changed files with 457 additions and 71 deletions

View File

@@ -65,6 +65,7 @@ set(SOURCES
"mouseinput.cpp"
"translation.cpp"
"material.cpp"
"lua.cpp"
)
if (WIN32)
@@ -125,5 +126,10 @@ find_package(libsndfile REQUIRED)
include_directories(${LIBSNDFILE_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} ${LIBSNDFILE_LIBRARY})
#set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined -g")
find_package(LuaJIT REQUIRED)
include_directories(${LUAJIT_INCLUDE_DIR})
target_link_libraries(${PROJECT_NAME} ${LUAJIT_LIBRARIES})
if (UNIX)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined")
endif()

View File

@@ -0,0 +1,81 @@
# Locate Lua library
# This module defines
# LUAJIT_FOUND, if false, do not try to link to Lua
# LUAJIT_LIBRARIES
# LUAJIT_INCLUDE_DIR, where to find lua.h
# LUAJIT_VERSION_STRING, the version of Lua found (since CMake 2.8.8)
#
# Note that the expected include convention is
# #include "lua.h"
# and not
# #include <lua/lua.h>
# This is because, the lua location is not standardized and may exist
# in locations other than lua/
#=============================================================================
# Copyright 2007-2009 Kitware, Inc.
#
# Distributed under the OSI-approved BSD License (the "License");
# see accompanying file Copyright.txt for details.
#
# This software is distributed WITHOUT ANY WARRANTY; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the License for more information.
#=============================================================================
# (To distribute this file outside of CMake, substitute the full
# License text for the above reference.)
find_path(LUAJIT_INCLUDE_DIR luajit.h
HINTS
$ENV{LUA_DIR}
PATH_SUFFIXES include/luajit-2.0 include
PATHS
~/Library/Frameworks
/Library/Frameworks
/sw # Fink
/opt/local # DarwinPorts
/opt/csw # Blastwave
/opt
)
find_library(LUAJIT_LIBRARY
NAMES luajit luajit-5.1
HINTS
$ENV{LUA_DIR}
PATH_SUFFIXES lib64 lib
PATHS
~/Library/Frameworks
/Library/Frameworks
/sw
/opt/local
/opt/csw
/opt
)
if (LUAJIT_LIBRARY)
# include the math library for Unix
if (UNIX AND NOT APPLE)
find_library(LUAJIT_MATH_LIBRARY m)
set(LUAJIT_LIBRARIES "${LUAJIT_LIBRARY};${LUAJIT_MATH_LIBRARY}" CACHE STRING "Lua Libraries")
# For Windows and Mac, don't need to explicitly include the math library
else ()
set(LUAJIT_LIBRARIES "${LUAJIT_LIBRARY}" CACHE STRING "Lua Libraries")
endif ()
endif ()
if(LUAJIT_INCLUDE_DIR AND EXISTS "${LUAJIT_INCLUDE_DIR}/lua.h")
file(STRINGS "${LUAJIT_INCLUDE_DIR}/lua.h" luajit_version_str REGEX "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua .+\"")
string(REGEX REPLACE "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua ([^\"]+)\".*" "\\1" LUAJIT_VERSION_STRING "${luajit_version_str}")
unset(luajit_version_str)
endif()
include(FindPackageHandleStandardArgs)
# handle the QUIETLY and REQUIRED arguments and set LUAJIT_FOUND to TRUE if
# all listed variables are TRUE
find_package_handle_standard_args(LuaJIT
REQUIRED_VARS LUAJIT_LIBRARIES LUAJIT_INCLUDE_DIR
VERSION_VAR LUAJIT_VERSION_STRING)
mark_as_advanced(LUAJIT_INCLUDE_DIR LUAJIT_LIBRARIES LUAJIT_LIBRARY LUAJIT_MATH_LIBRARY)

View File

@@ -365,7 +365,7 @@ int main(int argc, char *argv[])
}
catch (std::runtime_error e)
{
WriteLog(e.what());
ErrorLog(e.what());
return -1;
}
@@ -406,6 +406,11 @@ int main(int argc, char *argv[])
ErrorLog( "Critical error, memory allocation failure: " + std::string( Error.what() ) );
return -1;
}
catch (std::runtime_error e)
{
ErrorLog(e.what());
return -1;
}
#ifdef _WIN32
Console::Off(); // wyłączenie konsoli (komunikacji zwrotnej)

View File

@@ -39,7 +39,8 @@ enum TEventType {
tp_Visible,
tp_Voltage,
tp_Message,
tp_Friction
tp_Friction,
tp_Lua
};
const int update_memstring = 0x0000001; // zmodyfikować tekst (UpdateValues)

View File

@@ -1761,6 +1761,72 @@ void TGround::FirstInit()
WriteLog("FirstInit is done");
};
void TGround::add_event(TEvent *tmp)
{
if (tmp->Type == tp_Unknown)
delete tmp;
else
{ // najpierw sprawdzamy, czy nie ma, a potem dopisujemy
TEvent *found = FindEvent(tmp->asName);
if (found)
{ // jeśli znaleziony duplikat
auto const size = tmp->asName.size();
if( tmp->asName[0] == '#' ) // zawsze jeden znak co najmniej jest
{
delete tmp;
tmp = nullptr;
} // utylizacja duplikatu z krzyżykiem
else if( ( size > 8 )
&& ( tmp->asName.substr( 0, 9 ) == "lineinfo:" ))
// tymczasowo wyjątki
{
delete tmp;
tmp = nullptr;
} // tymczasowa utylizacja duplikatów W5
else if( ( size > 8 )
&& ( tmp->asName.substr( size - 8 ) == "_warning"))
// tymczasowo wyjątki
{
delete tmp;
tmp = nullptr;
} // tymczasowa utylizacja duplikatu z trąbieniem
else if( ( size > 4 )
&& ( tmp->asName.substr( size - 4 ) == "_shp" ))
// nie podlegają logowaniu
{
delete tmp;
tmp = NULL;
} // tymczasowa utylizacja duplikatu SHP
if (tmp) // jeśli nie został zutylizowany
if (Global::bJoinEvents)
found->Append(tmp); // doczepka (taki wirtualny multiple bez warunków)
else
{
ErrorLog("Duplicated event: " + tmp->asName);
found->Append(tmp); // doczepka (taki wirtualny multiple bez warunków)
found->Type = tp_Ignored; // dezaktywacja pierwotnego - taka proteza na
// wsteczną zgodność
// SafeDelete(tmp); //bezlitośnie usuwamy wszelkie duplikaty, żeby nie
// zaśmiecać drzewka
}
}
if ( nullptr != tmp )
{ // jeśli nie duplikat
tmp->evNext2 = RootEvent; // lista wszystkich eventów (m.in. do InitEvents)
RootEvent = tmp;
if (!found)
{ // jeśli nazwa wystąpiła, to do kolejki i wyszukiwarki dodawany jest tylko pierwszy
if( ( RootEvent->Type != tp_Ignored )
&& ( RootEvent->asName.find( "onstart" ) != std::string::npos ) ) {
// event uruchamiany automatycznie po starcie
AddToQuery( RootEvent, NULL ); // dodanie do kolejki
}
m_eventmap.emplace( tmp->asName, tmp ); // dodanie do wyszukiwarki
}
}
}
}
bool TGround::Init(std::string File)
{ // główne wczytywanie scenerii
if (ToLower(File).substr(0, 7) == "scenery")
@@ -1920,68 +1986,14 @@ bool TGround::Init(std::string File)
{
TEvent *tmp = new TEvent();
tmp->Load(&parser, &pOrigin);
if (tmp->Type == tp_Unknown)
delete tmp;
else
{ // najpierw sprawdzamy, czy nie ma, a potem dopisujemy
TEvent *found = FindEvent(tmp->asName);
if (found)
{ // jeśli znaleziony duplikat
auto const size = tmp->asName.size();
if( tmp->asName[0] == '#' ) // zawsze jeden znak co najmniej jest
add_event(tmp);
}
else if (str == "lua")
{
delete tmp;
tmp = nullptr;
} // utylizacja duplikatu z krzyżykiem
else if( ( size > 8 )
&& ( tmp->asName.substr( 0, 9 ) == "lineinfo:" ))
// tymczasowo wyjątki
{
delete tmp;
tmp = nullptr;
} // tymczasowa utylizacja duplikatów W5
else if( ( size > 8 )
&& ( tmp->asName.substr( size - 8 ) == "_warning"))
// tymczasowo wyjątki
{
delete tmp;
tmp = nullptr;
} // tymczasowa utylizacja duplikatu z trąbieniem
else if( ( size > 4 )
&& ( tmp->asName.substr( size - 4 ) == "_shp" ))
// nie podlegają logowaniu
{
delete tmp;
tmp = NULL;
} // tymczasowa utylizacja duplikatu SHP
if (tmp) // jeśli nie został zutylizowany
if (Global::bJoinEvents)
found->Append(tmp); // doczepka (taki wirtualny multiple bez warunków)
else
{
ErrorLog("Duplicated event: " + tmp->asName);
found->Append(tmp); // doczepka (taki wirtualny multiple bez warunków)
found->Type = tp_Ignored; // dezaktywacja pierwotnego - taka proteza na
// wsteczną zgodność
// SafeDelete(tmp); //bezlitośnie usuwamy wszelkie duplikaty, żeby nie
// zaśmiecać drzewka
}
}
if ( nullptr != tmp )
{ // jeśli nie duplikat
tmp->evNext2 = RootEvent; // lista wszystkich eventów (m.in. do InitEvents)
RootEvent = tmp;
if (!found)
{ // jeśli nazwa wystąpiła, to do kolejki i wyszukiwarki dodawany jest tylko pierwszy
if( ( RootEvent->Type != tp_Ignored )
&& ( RootEvent->asName.find( "onstart" ) != std::string::npos ) ) {
// event uruchamiany automatycznie po starcie
AddToQuery( RootEvent, NULL ); // dodanie do kolejki
}
m_eventmap.emplace( tmp->asName, tmp ); // dodanie do wyszukiwarki
}
}
}
parser.getTokens();
std::string file;
parser >> file;
m_lua.interpret(subpath + file);
}
else if (str == "rotate")
{
@@ -3445,6 +3457,9 @@ bool TGround::CheckQuery()
break;
case tp_Message: // wyświetlenie komunikatu
break;
case tp_Lua:
((lua::eventhandler_t)tmpEvent->Params[0].asPointer)(tmpEvent, tmpEvent->Activator);
break;
} // switch (tmpEvent->Type)
} // if (tmpEvent->bEnabled)
} // while

View File

@@ -20,6 +20,7 @@ http://mozilla.org/MPL/2.0/.
#include "Float3d.h"
#include "Names.h"
#include "lightarray.h"
#include "lua.h"
typedef int TGroundNodeType;
// Ra: zmniejszone liczby, aby zrobić tabelkę i zoptymalizować wyszukiwanie
@@ -260,6 +261,7 @@ class TGround
event_map m_eventmap;
TNames<TGroundNode *> m_trackmap;
light_array m_lights; // collection of dynamic light sources present in the scene
lua m_lua;
vector3 pOrigin;
vector3 aRotate;
@@ -342,6 +344,8 @@ class TGround
void IsolatedBusyList();
void IsolatedBusy(const std::string t);
void Silence(vector3 gdzie);
void add_event(TEvent *event);
};
//---------------------------------------------------------------------------

View File

@@ -121,7 +121,6 @@ private:
TCamera Camera;
TCamera DebugCamera;
TGround Ground;
world_environment Environment;
TTrain *Train;
TDynamicObject *pDynamicNearest;
@@ -147,6 +146,8 @@ private:
void CabChange(TDynamicObject *old, TDynamicObject *now);
// handles vehicle change flag
void ChangeDynamic();
TGround Ground; //m7todo: tmp
};
//---------------------------------------------------------------------------

View File

@@ -15,5 +15,7 @@ cmake ../.. -T v140_xp ^
-DOPENAL_INCLUDE_DIR=%DEPS_DIR%/openal/include ^
-DOPENAL_LIBRARY=%DEPS_DIR%/openal/lib/win32/OpenAL32.lib ^
-DLIBSNDFILE_INCLUDE_DIR=%DEPS_DIR%/libsndfile/include ^
-DLIBSNDFILE_LIBRARY=%DEPS_DIR%/libsndfile/lib/win32/libsndfile-1.lib
-DLIBSNDFILE_LIBRARY=%DEPS_DIR%/libsndfile/lib/win32/libsndfile-1.lib ^
-DLUAJIT_INCLUDE_DIR=%DEPS_DIR%/luajit/include ^
-DLUAJIT_LIBRARIES=%DEPS_DIR%/luajit/lib/win32/lua51.lib
popd

View File

@@ -15,5 +15,7 @@ cmake ../.. -A x64 ^
-DOPENAL_INCLUDE_DIR=%DEPS_DIR%/openal/include ^
-DOPENAL_LIBRARY=%DEPS_DIR%/openal/lib/win64/OpenAL32.lib ^
-DLIBSNDFILE_INCLUDE_DIR=%DEPS_DIR%/libsndfile/include ^
-DLIBSNDFILE_LIBRARY=%DEPS_DIR%/libsndfile/lib/win64/libsndfile-1.lib
-DLIBSNDFILE_LIBRARY=%DEPS_DIR%/libsndfile/lib/win64/libsndfile-1.lib ^
-DLUAJIT_INCLUDE_DIR=%DEPS_DIR%/luajit/include ^
-DLUAJIT_LIBRARIES=%DEPS_DIR%/luajit/lib/win64/lua51.lib
popd

View File

@@ -1,2 +1,2 @@
powershell "$wc = New-Object System.Net.WebClient; $wc.DownloadFile(\"https://milek7.pl/.stuff/eu07exe/builddep2.zip\", \"%cd%\deps_win.zip\")"
powershell "$wc = New-Object System.Net.WebClient; $wc.DownloadFile(\"https://milek7.pl/.stuff/eu07exe/builddep3.zip\", \"%cd%\deps_win.zip\")"
powershell "$s = New-Object -ComObject shell.application; $z = $s.Namespace(\"%cd%\deps_win.zip\"); foreach ($i in $z.items()) { $s.Namespace(\"%cd%\").CopyHere($i) }"

170
lua.cpp Normal file
View File

@@ -0,0 +1,170 @@
#include "stdafx.h"
#include "lua.h"
#include "Event.h"
#include "Logs.h"
#include "MemCell.h"
#include "World.h"
#include "Driver.h"
#include "lua_ffi.h"
extern TWorld World;
lua::lua()
{
state = luaL_newstate();
if (!state)
throw std::runtime_error("cannot create lua state");
lua_atpanic(state, atpanic);
luaL_openlibs(state);
lua_getglobal(state, "package");
lua_pushstring(state, "preload");
lua_gettable(state, -2);
lua_pushcclosure(state, openffi, 0);
lua_setfield(state, -2, "eu07.events");
lua_settop(state, 0);
}
lua::~lua()
{
lua_close(state);
state = nullptr;
}
void lua::interpret(std::string file)
{
if (luaL_dofile(state, file.c_str()))
throw std::runtime_error(lua_tostring(state, -1));
}
// NOTE: we cannot throw exceptions in callbacks
// because it is not supported by LuaJIT on x86 windows
int lua::atpanic(lua_State *s)
{
ErrorLog(std::string(lua_tostring(s, -1)));
return 0;
}
int lua::openffi(lua_State *s)
{
if (luaL_dostring(s, lua_ffi))
{
ErrorLog(std::string(lua_tostring(s, -1)));
return 0;
}
return 1;
}
extern "C"
{
TEvent* scriptapi_event_create(const char* name, lua::eventhandler_t handler, double delay)
{
TEvent *event = new TEvent();
event->bEnabled = true;
event->Type = tp_Lua;
event->asName = std::string(name);
event->fDelay = delay;
event->Params[0].asPointer = (void*)handler;
World.Ground.add_event(event);
return event;
}
TEvent* scriptapi_event_find(const char* name)
{
std::string str(name);
TEvent *e = World.Ground.FindEvent(str);
if (e)
return e;
else
WriteLog("missing event: " + str);
return nullptr;
}
TTrack* scriptapi_track_find(const char* name)
{
std::string str(name);
TGroundNode *n = World.Ground.FindGroundNode(str, TP_TRACK);
if (n)
return n->pTrack;
else
WriteLog("missing track: " + str);
return nullptr;
}
bool scriptapi_track_isoccupied(TTrack* track)
{
if (track)
return !track->IsEmpty();
return false;
}
const char* scriptapi_event_getname(TEvent *e)
{
if (e)
return e->asName.c_str();
return nullptr;
}
const char* scriptapi_train_getname(TDynamicObject *dyn)
{
if (dyn && dyn->Mechanik)
return dyn->Mechanik->TrainName().c_str();
return nullptr;
}
void scriptapi_event_dispatch(TEvent *e, TDynamicObject *activator)
{
if (e)
World.Ground.AddToQuery(e, activator);
}
double scriptapi_random(double a, double b)
{
return Random(a, b);
}
void scriptapi_writelog(const char* txt)
{
WriteLog("lua log: " + std::string(txt));
}
struct memcell_values { const char *str; double num1; double num2; };
TMemCell* scriptapi_memcell_find(const char *name)
{
std::string str(name);
TGroundNode *n = World.Ground.FindGroundNode(str, TP_MEMCELL);
if (n)
return n->MemCell;
else
WriteLog("missing memcell: " + str);
return nullptr;
}
memcell_values scriptapi_memcell_read(TMemCell *mc)
{
if (!mc)
return { nullptr, 0.0, 0.0 };
return { mc->Text().c_str(), mc->Value1(), mc->Value2() };
}
void scriptapi_memcell_update(TMemCell *mc, const char *str, double num1, double num2)
{
if (!mc)
return;
mc->UpdateValues(std::string(str), num1, num2,
update_memstring | update_memval1 | update_memval2);
}
void scriptapi_dynobj_putvalues(TDynamicObject *dyn, const char *str, double num1, double num2)
{
if (!dyn)
return;
TLocation loc;
if (dyn->Mechanik)
dyn->Mechanik->PutCommand(std::string(str), num1, num2, nullptr);
else
dyn->MoverParameters->PutCommand(std::string(str), num1, num2, loc);
}
}

21
lua.h Normal file
View File

@@ -0,0 +1,21 @@
#pragma once
#include <lua.hpp>
class TEvent;
class TDynamicObject;
class lua
{
lua_State *state;
static int atpanic(lua_State *s);
static int openffi(lua_State *s);
public:
lua();
~lua();
void interpret(std::string file);
typedef void (*eventhandler_t)(TEvent*, TDynamicObject*);
};

78
lua_ffi.h Normal file
View File

@@ -0,0 +1,78 @@
const char lua_ffi[] = "local ffi = require(\"ffi\")\n"
"ffi.cdef[[\n"
"struct memcell_values { const char *str; double num1; double num2; };\n"
"\n"
"typedef struct TEvent TEvent;\n"
"typedef struct TTrack TTrack;\n"
"typedef struct TDynamicObject TDynamicObject;\n"
"typedef struct TMemCell TMemCell;\n"
"typedef struct memcell_values memcell_values;\n"
"\n"
"TEvent* scriptapi_event_create(const char* name, void (*handler)(TEvent*, TDynamicObject*), double delay);\n"
"TEvent* scriptapi_event_find(const char* name);\n"
"const char* scriptapi_event_getname(TEvent *e);\n"
"void scriptapi_event_dispatch(TEvent *e, TDynamicObject *activator);\n"
"\n"
"TTrack* scriptapi_track_find(const char* name);\n"
"bool scriptapi_track_isoccupied(TTrack *track);\n"
"\n"
"const char* scriptapi_train_getname(TDynamicObject *dyn);\n"
"void scriptapi_dynobj_putvalues(TDynamicObject *dyn, const char *str, double num1, double num2);\n"
"\n"
"TMemCell* scriptapi_memcell_find(const char *name);\n"
"memcell_values scriptapi_memcell_read(TMemCell *mc);\n"
"void scriptapi_memcell_update(TMemCell *mc, const char *str, double num1, double num2);\n"
"\n"
"double scriptapi_random(double a, double b);\n"
"void scriptapi_writelog(const char* txt);\n"
"]]\n"
"\n"
"local ns = ffi.C\n"
"\n"
"local module = {}\n"
"\n"
"module.event_create = ns.scriptapi_event_create\n"
"module.event_find = ns.scriptapi_event_find\n"
"function module.event_getname(a)\n"
" return ffi.string(ns.scriptapi_event_getname(a))\n"
"end\n"
"module.event_dispatch = ns.scriptapi_event_dispatch\n"
"function module.event_dispatch_n(a, b)\n"
" ns.scriptapi_event_dispatch(ns.scriptapi_event_find(a), b)\n"
"end\n"
"\n"
"module.track_find = ns.scriptapi_track_find\n"
"module.track_isoccupied = ns.scriptapi_track_isoccupied\n"
"function module.track_isoccupied_n(a)\n"
" return ns.scriptapi_track_isoccupied(ns.scriptapi_track_find(a))\n"
"end\n"
"\n"
"function module.train_getname(a)\n"
" return ffi.string(ns.scriptapi_train_getname(a))\n"
"end\n"
"function module.dynobj_putvalues(a, b)\n"
" ns.scriptapi_dynobj_putvalues(a, b.str, b.num1, b.num2)\n"
"end\n"
"\n"
"module.memcell_find = ns.scriptapi_memcell_find\n"
"function module.memcell_read(a)\n"
" native = ns.scriptapi_memcell_read(a)\n"
" mc = { }\n"
" mc.str = ffi.string(native.str)\n"
" mc.num1 = native.num1\n"
" mc.num2 = native.num2\n"
" return mc\n"
"end\n"
"function module.memcell_read_n(a)\n"
" return module.memcell_read(ns.scriptapi_memcell_find(a))\n"
"end\n"
"function module.memcell_update(a, b)\n"
" ns.scriptapi_memcell_update(a, b.str, b.num1, b.num2)\n"
"end\n"
"function module.memcell_update_n(a, b)\n"
" ns.scriptapi_memcell_update(ns.scriptapi_memcell_find(a), b.str, b.num1, b.num2)\n"
"end\n"
"\n"
"module.random = ns.scriptapi_random\n"
"module.writelog = ns.scriptapi_writelog\n"
"\nreturn module\n";