Difference between revisions of "Добавление Lua"

From Valve Developer Community
Jump to: navigation, search
(Created page with "{{otherlang2 |en=Adding_Lua |de=Adding_Lua:de }} Добавить [http://en.wikipedia.org/wiki/Lua_%28programming_language%29 Lua] в Source очень просто, А созд...")
 
m (VAX325 moved page Adding Lua:ru to Добавление Lua: Перевод названия на русский язык.)
 
(10 intermediate revisions by 4 users not shown)
Line 1: Line 1:
 
{{otherlang2
 
{{otherlang2
 +
|title= Добавление Lua в Source
 
|en=Adding_Lua
 
|en=Adding_Lua
 
|de=Adding_Lua:de
 
|de=Adding_Lua:de
 
}}
 
}}
Добавить [http://en.wikipedia.org/wiki/Lua_%28programming_language%29 Lua] в Source очень просто, А создание несколько экземпляров ещё проще.
+
Добавить [http://en.wikipedia.org/wiki/Lua_%28programming_language%29 Lua] в Source очень просто, А создать несколько обработчиков ещё проще.
 +
Главное иметь базовые знания в c++.
  
 
== Исходники ==
 
== Исходники ==
  
Надо добавить два файла в ваш порект:
+
Надо добавить два файла в ваш проект:
  
 
*[[LuaManager_CPP]]
 
*[[LuaManager_CPP]]
 
*[[LuaManager_H]]
 
*[[LuaManager_H]]
  
== Инцализация ==  
+
== Инициализация ==  
 
+
Все изменения будут выполняться в проекте Server.
Теперь нужно инициализацию  и завершение functions. В gameinterface.cpp добавьте этот код в функции  DLLInit перед return true строкой (557 строка):
 
  
 +
Сначала добавте include в файл gameinterface.cpp.
 +
<source lang=cpp>
 +
#ifdef GE_LUA
 +
#include "ge_luamanager.h"
 +
#endif
 +
</source>
 +
В gameinterface.cpp добавьте этот вызов в функцию  DLLInit перед "return true".
 
<source lang=cpp>
 
<source lang=cpp>
 
#ifdef GE_LUA
 
#ifdef GE_LUA
Line 22: Line 30:
 
#endif
 
#endif
 
</source>
 
</source>
И добавляем в функцию DLLShutdown:
+
И добавляем вызов в конец функции DLLShutdown:
 
 
 
<source lang=cpp>
 
<source lang=cpp>
 
#ifdef GE_LUA
 
#ifdef GE_LUA
Line 31: Line 38:
 
</source>
 
</source>
  
Также убедитесь что вы подключение заголовочный файл.  
+
== Создаём Lua Обработчик ==
 +
Это самая интересная часть. Вам необходимо создать класс, который наследуеться от LuaHandle и имеет функции Init, Shutdown, RegFunctions и RegGlobals.
  
 +
Это изначальный вид класса (g_LuaHandle и GetLuaHandle() нам понадобяться в будуещем):
 
<source lang=cpp>
 
<source lang=cpp>
#ifdef GE_LUA
+
class MyLuaHandle : LuaHandle
#include "ge_luamanager.h"
+
{
#endif
+
MyLuaHandle();
</source>
+
~MyLuaHandle();
 +
 
 +
void Init();
 +
void Shutdown();
  
== Making Your own Lua Instance ==
+
void RegFunctions();
 +
void RegGlobals();
 +
};
  
Now this is the fun part, making your own lua instance. You will need to make your own class that inherits from LuaHandle and provides functionality for Init, Shutdown, RegFunctions and RegGlobals.
+
MyLuaHandle* g_LuaHandle = NULL;
 +
MyLuaHandle *GetLuaHandle();
 +
</source>
  
 
=== Init ===
 
=== Init ===
 
+
Init вызывается после инициализации Lua, а это означает, что это лучшее место для загрузки скрипта.
Init gets called after Lua gets init and thus provides the best place to load your script.
 
  
 
<source lang=cpp>
 
<source lang=cpp>
Line 83: Line 98:
 
=== Shutdown ===
 
=== Shutdown ===
  
Shutdown handles the shutting down of Lua and should do things in here like call shutdown functions in your script.
+
В функции Shutdown обрабатывается завершение работы Lua.
  
 
=== RegGlobals ===
 
=== RegGlobals ===
  
RegGlobals allows us to register global variables in lua.
+
RegGlobals регистрирует глобальные переменные lua.
  
 
<source lang=cpp>
 
<source lang=cpp>
Line 113: Line 128:
 
</source>
 
</source>
  
Macros provided allow for different types as well. LG_DEFINE_INT for int, LG_DEFINE_STRING for string and LG_DEFINE_BOOL for boolean.
+
Данные макросы также могут регистрировать и другие типы данных (LG_DEFINE_INT для чисел,LG_DEFINE_STRING для строк и LG_DEFINE_BOOL для булева).
  
 
=== RegFunctions ===
 
=== RegFunctions ===
  
Like Globals, RegFunctions is where you put all the c functions you want to expose to Lua.
+
В этой функции вы регистрируете функции для Lua.
  
 
<source lang=cpp>
 
<source lang=cpp>
Line 129: Line 144:
 
</source>
 
</source>
  
Again this has been shorten using a macro. And thus you will need to define this functions in another file.
+
Также вам необходимо определить эти функции в другом файле.
 +
Необходимо объявлять с приставкой lua. Например: REG_FUNCTION( Msg ) тогда объявление будет int luaMsg(lua_State *L).
  
 
<source lang=cpp>
 
<source lang=cpp>
Line 181: Line 197:
 
</source>
 
</source>
  
Note: The function name must be the same as the one used in the macro with lua infront.
+
=== GetLuaHandle ===
 
+
Эта функция говорит о том, инициализирован обработчик или нет.
== Creating The Instance ==
 
 
 
On the top of your new LuaHandle class you need to add a function allowing global access to your Lua instance. Add something like this:
 
 
 
 
<source lang=cpp>
 
<source lang=cpp>
MyLuaHandle* g_LuaHandle = NULL;
 
 
MyLuaHandle *GetLuaHandle()
 
MyLuaHandle *GetLuaHandle()
 
{
 
{
Line 195: Line 206:
 
</source>
 
</source>
  
And in your constructor of your LuaHandle add a call to set the instance when you make a new one:
+
== Использование Обработчика ==
 +
 
 +
В конструктор вашего обработчика нужно добавить регистрацию обработчика и установить переменную инициализации :
 
<source lang=cpp>
 
<source lang=cpp>
 
MyLuaHandle::MyLuaHandle() : LuaHandle()
 
MyLuaHandle::MyLuaHandle() : LuaHandle()
Line 204: Line 217:
 
</source>
 
</source>
  
Note: Its important to have Register here other wise it wont work!
+
И наконец в файле правил игры нужно добавить конструктор нашего обработчика:
 
 
And finally in your game rules constructor make a new LuaHandle:
 
 
<source lang=cpp>
 
<source lang=cpp>
 
CGameRules::CGameRules()
 
CGameRules::CGameRules()
Line 213: Line 224:
 
//other stuff here
 
//other stuff here
  
// Start our LUA GamePlay Engine
 
 
if (!GetLuaHandle())
 
if (!GetLuaHandle())
 
new MyLuaHandle();
 
new MyLuaHandle();
Line 219: Line 229:
 
</source>
 
</source>
  
== Project Settings ==
+
Не забудте добавить include с вашим обработчиком.
 +
== Под конец ==
  
In the server project settings you need to add GE_LUA to the preprocesser options (Configure properties -> c++ -> Preprocesser -> Preprocesser defines).
+
В вашем проекте "Server" нужно добавить новое опредиление препроцессора (Свойства -> C++ -> Препроцессор -> Определения препроцессора).
Also you will need to add the lua lib (should be the same name as the lib file, mines lua5.1.lib) to the linker settings (Configure properties -> Linker -> Input -> Additional Dependencies )
+
Также вы должны иметь скомпилированную библиотеку lua (в моём случае lua5.1.lib) и добавить её в зависимости компоновщика (Свойства -> Компоновщик -> Ввод -> Дополнительные зависимости )
  
Note: Make sure you do this for both release and debug.
+
Вы дожны сделать это и для Debug и Release конфигурации.
  
Now place the lua lib into the src/lib folder. And you should be able to compile and now have a working Lua.
+
Также поместите вашу lua библиотеку в папку "src/lib/public/".
  
== Creating Calls from c into Lua ==
+
== Привязка вызовов к луа ==
  
This is a bit harder and you will need to consult the lua documents for this but here is an example on how ges does it:
+
Это посложнее чем обработчик. Вот пример:
  
 
<source lang=cpp>
 
<source lang=cpp>

Latest revision as of 06:26, 3 March 2020

English Deutsch

Добавить Lua в Source очень просто, А создать несколько обработчиков ещё проще. Главное иметь базовые знания в c++.

Исходники

Надо добавить два файла в ваш проект:

Инициализация

Все изменения будут выполняться в проекте Server.

Сначала добавте include в файл gameinterface.cpp.

#ifdef GE_LUA
#include "ge_luamanager.h"
#endif

В gameinterface.cpp добавьте этот вызов в функцию DLLInit перед "return true".

#ifdef GE_LUA
	// Start LUA
	GELua()->InitDll();
#endif

И добавляем вызов в конец функции DLLShutdown:

#ifdef GE_LUA
	// Shutdown LUA, close all open gameplays
	GELua()->ShutdownDll();
#endif

Создаём Lua Обработчик

Это самая интересная часть. Вам необходимо создать класс, который наследуеться от LuaHandle и имеет функции Init, Shutdown, RegFunctions и RegGlobals.

Это изначальный вид класса (g_LuaHandle и GetLuaHandle() нам понадобяться в будуещем):

class MyLuaHandle : LuaHandle
{
	MyLuaHandle();
	~MyLuaHandle();

	void Init();
	void Shutdown();

	void RegFunctions();
	void RegGlobals();
};

MyLuaHandle* g_LuaHandle = NULL;
MyLuaHandle *GetLuaHandle();

Init

Init вызывается после инициализации Lua, а это означает, что это лучшее место для загрузки скрипта.

void MyLuaHandle::Init()
{
	const char* luaFile = "myLuaFile.lua";

	//Load into buffer
	FileHandle_t f = filesystem->Open( luaFile, "rb", "MOD" );
	if (!f)
		return;

	// load file into a null-terminated buffer
	int fileSize = filesystem->Size(f);
	unsigned bufSize = ((IFileSystem *)filesystem)->GetOptimalReadSize( f, fileSize + 1 );

	char *buffer = (char*)((IFileSystem *)filesystem)->AllocOptimalReadBuffer( f, bufSize );
	Assert(buffer);

	((IFileSystem *)filesystem)->ReadEx( buffer, bufSize, fileSize, f ); // read into local buffer
	buffer[fileSize] = '\0'; // null terminate file as EOF
	filesystem->Close( f );	// close file after reading

	int error = luaL_loadbuffer( GetLua(), buffer, fileSize, luaFile );
	if (error)
	{
		Warning("[LUA-ERR] %s\n", lua_tostring(GetLua(), -1));
		lua_pop(GetLua(), 1);  /* pop error message from the stack */
		Warning("[LUA-ERR] One or more errors occured while loading lua script!\n");
		return;
	}
	CallLUA(GetLua(), 0, LUA_MULTRET, 0, luaFile );
	m_bLuaLoaded = true;
}

Shutdown

В функции Shutdown обрабатывается завершение работы Lua.

RegGlobals

RegGlobals регистрирует глобальные переменные lua.

void MyLuaHandle::RegGlobals()
{
	LG_DEFINE_INT("FOR_ALL_PLAYERS", -1);
	LG_DEFINE_INT("INVALID_ENTITY", -1);
	LG_DEFINE_INT("NULL", 0);
	LG_DEFINE_INT("GE_MAX_HEALTH", MAX_HEALTH);
	LG_DEFINE_INT("GE_MAX_ARMOR", MAX_ARMOR);
	LG_DEFINE_INT("MAX_PLAYERS", gpGlobals->maxClients);

	//Team Indices
	LG_DEFINE_INT("TEAM_NONE",TEAM_UNASSIGNED);
	LG_DEFINE_INT("TEAM_SPECTATOR",TEAM_SPECTATOR);
	LG_DEFINE_INT("TEAM_MI6",TEAM_MI6);
	LG_DEFINE_INT("TEAM_JANUS",TEAM_JANUS);

	//ClientPrintAll Types
	LG_DEFINE_INT("HUD_PRINTNOTIFY",HUD_PRINTNOTIFY);
	LG_DEFINE_INT("HUD_PRINTCONSOLE",HUD_PRINTCONSOLE);
	LG_DEFINE_INT("HUD_PRINTTALK",HUD_PRINTTALK);
	LG_DEFINE_INT("HUD_PRINTCENTER",HUD_PRINTCENTER);
}

Данные макросы также могут регистрировать и другие типы данных (LG_DEFINE_INT для чисел,LG_DEFINE_STRING для строк и LG_DEFINE_BOOL для булева).

RegFunctions

В этой функции вы регистрируете функции для Lua.

void MyLuaHandle::RegFunctions()
{
	REG_FUNCTION( Msg );
	REG_FUNCTION( ConMsg );
	REG_FUNCTION( ClientPrintAll );
	REG_FUNCTION( GetTime );
}

Также вам необходимо определить эти функции в другом файле. Необходимо объявлять с приставкой lua. Например: REG_FUNCTION( Msg ) тогда объявление будет int luaMsg(lua_State *L).

extern "C"
{
	#include <lua.h>
	#include <lauxlib.h>
	#include <lualib.h>
}

int luaClientPrintAll(lua_State *L)
{
	int n = lua_gettop(L);    /* number of arguments */
	switch(n)
	{
	case 2:
		UTIL_ClientPrintAll( lua_tointeger(L,1), lua_tostring(L,2));
		break;
	case 3:
		UTIL_ClientPrintAll( lua_tointeger(L,1), lua_tostring(L,2),lua_tostring(L,3));
		break;
	case 4:
		UTIL_ClientPrintAll( lua_tointeger(L,1), lua_tostring(L,2),lua_tostring(L,3),lua_tostring(L,4));
		break;
	case 5:
		UTIL_ClientPrintAll( lua_tointeger(L,1), lua_tostring(L,2),lua_tostring(L,3),lua_tostring(L,4),lua_tostring(L,5));
		break;
	case 6:
		UTIL_ClientPrintAll( lua_tointeger(L,1), lua_tostring(L,2),lua_tostring(L,3),lua_tostring(L,4),lua_tostring(L,5),lua_tostring(L,6));
		break;
	}
	return 0;
}

int luaMsg(lua_State *L)
{
	Msg("%s\n",lua_tostring(L,1));
	return 0;
}

int luaConMsg(lua_State *L)
{
	return luaMsg(L);
}

int luaGetTime(lua_State *L)
{
	lua_pushnumber( L, gpGlobals->curtime );
	return 1;
}

GetLuaHandle

Эта функция говорит о том, инициализирован обработчик или нет.

MyLuaHandle *GetLuaHandle()
{
	return g_LuaHandle;
}

Использование Обработчика

В конструктор вашего обработчика нужно добавить регистрацию обработчика и установить переменную инициализации :

MyLuaHandle::MyLuaHandle() : LuaHandle()
{
	g_LuaHandle = this;
	Register();
}

И наконец в файле правил игры нужно добавить конструктор нашего обработчика:

CGameRules::CGameRules()
{

	//other stuff here

	if (!GetLuaHandle())
		new MyLuaHandle();
}

Не забудте добавить include с вашим обработчиком.

Под конец

В вашем проекте "Server" нужно добавить новое опредиление препроцессора (Свойства -> C++ -> Препроцессор -> Определения препроцессора). Также вы должны иметь скомпилированную библиотеку lua (в моём случае lua5.1.lib) и добавить её в зависимости компоновщика (Свойства -> Компоновщик -> Ввод -> Дополнительные зависимости )

Вы дожны сделать это и для Debug и Release конфигурации.

Также поместите вашу lua библиотеку в папку "src/lib/public/".

Привязка вызовов к луа

Это посложнее чем обработчик. Вот пример:

void CGELUAGamePlay::PostRoundBegin()
{
	if (m_bLuaLoaded)
	{
		lua_getglobal(GetLua(), "RoundStart");
		CallLUA(GetLua(), 0, 0, 0, "RoundStart");
	}
}