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

From Valve Developer Community
Jump to: navigation, search
(Убрал англиский текст и убрал несколько недочётов)
Line 1: Line 1:
 
{{otherlang2
 
{{otherlang2
|title= Добавление Lua
+
|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++.
  
 
== Исходники ==
 
== Исходники ==
Line 14: Line 15:
  
 
== Инициализация  ==  
 
== Инициализация  ==  
 +
Все изменения будут выполняться в проекте Server.
  
Теперь нужно сделать инициализацию и отключение lua. В 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 23: Line 30:
 
#endif
 
#endif
 
</source>
 
</source>
И добавляем в функцию DLLShutdown:
+
И добавляем вызов в конец функции DLLShutdown:
 
 
 
<source lang=cpp>
 
<source lang=cpp>
 
#ifdef GE_LUA
 
#ifdef GE_LUA
Line 32: 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();
 +
~MyLuaHandle();
 +
 
 +
void Init();
 +
void Shutdown();
 +
 
 +
void RegFunctions();
 +
void RegGlobals();
 +
};
 +
 
 +
MyLuaHandle* g_LuaHandle = NULL;
 +
MyLuaHandle *GetLuaHandle();
 
</source>
 
</source>
 
==Создаём Lua Экземпляра==
 
Это самая интересная часть создания lua экземпляра. Вам необходимо создать класс, который наследуется от LuaHandle и имеет функции Init, Shutdown, RegFunctions and RegGlobals.
 
  
 
=== Init ===
 
=== Init ===
 
 
Init вызывается после инициализации Lua, а это означает, что это лучшее место для загрузки скрипта.
 
Init вызывается после инициализации Lua, а это означает, что это лучшее место для загрузки скрипта.
  
Line 83: Line 98:
 
=== Shutdown ===
 
=== Shutdown ===
  
Тут обрабатывается завершение работы Lua.
+
В функции Shutdown обрабатывается завершение работы Lua.
  
 
=== RegGlobals ===
 
=== RegGlobals ===
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 ===
  
Как и  Globals, RegFunctions здесь все C функции, которые вы можете добавить в 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 ===
 
+
Эта функция говорит о том, инициализирован обработчик или нет.
== Создания экземпляра ==
 
 
 
Вверху нового LuaHandle класса вам нужно добавить функцию добавляющий доступ к Lua экземпляру.
 
Типа этого:
 
 
 
 
<source lang=cpp>
 
<source lang=cpp>
MyLuaHandle* g_LuaHandle = NULL;
 
 
MyLuaHandle *GetLuaHandle()
 
MyLuaHandle *GetLuaHandle()
 
{
 
{
Line 196: Line 206:
 
</source>
 
</source>
  
И в конструкторе твоего LuaHandle добавить вызов экземпляра :
+
== Использование Обработчика ==
 +
 
 +
В конструктор вашего обработчика нужно добавить регистрацию обработчика и установить переменную инициализации :
 
<source lang=cpp>
 
<source lang=cpp>
 
MyLuaHandle::MyLuaHandle() : LuaHandle()
 
MyLuaHandle::MyLuaHandle() : LuaHandle()
Line 205: Line 217:
 
</source>
 
</source>
  
Note: Its important to have Register here other wise it wont work!
+
И наконец в файле правил игры нужно добавить конструктор нашего обработчика:
И наконец в вашем game rules создать новый 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>

Revision as of 06:16, 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");
	}
}