Resolved #9 (Добавить поддержку серверных команд)

This commit is contained in:
Kernell 2015-12-12 22:50:24 +03:00
parent a745ff12ed
commit 013a924092
18 changed files with 536 additions and 8 deletions

View File

@ -21,10 +21,22 @@ namespace MultiTheftAuto.Native
[MethodImpl( MethodImplOptions.InternalCall )]
public static extern bool OutputConsole( string text, UInt32 element );
[MethodImpl( MethodImplOptions.InternalCall )]
public static extern bool OutputServerLog( string text );
[MethodImpl( MethodImplOptions.InternalCall )]
public static extern bool SetPassword( string password, bool bSave );
[MethodImpl( MethodImplOptions.InternalCall )]
public static extern ServerVersion GetVersion();
[MethodImpl( MethodImplOptions.InternalCall )]
public static extern bool AddCommandHandler( string name, Delegate handler, bool restricted = false, bool caseSensitive = true );
[MethodImpl( MethodImplOptions.InternalCall )]
public static extern bool ExecuteCommandHandler( string name, UInt32 player, string args );
[MethodImpl( MethodImplOptions.InternalCall )]
public static extern bool RemoveCommandHandler( string name, Delegate handler );
}
}

View File

@ -3,15 +3,28 @@ using System.Runtime.CompilerServices;
namespace MultiTheftAuto
{
public class Server
public delegate void CommandHandler( Player player, string command, string[] args );
public static class Server
{
public static bool OutputChatBox( string text, Element element, Color color, bool colorCoded )
{
return Native.Server.OutputChatBox( text, element.userdata, color, colorCoded );
}
public static bool OutputConsole( string text, Element element )
public static bool AddCommandHandler( string name, CommandHandler handler, bool restricted = false, bool caseSensitive = true )
{
return Native.Server.OutputConsole( text, element.userdata );
return Native.Server.AddCommandHandler( name, handler, restricted, caseSensitive );
}
public static bool ExecuteCommandHandler( string name, Player player, string args )
{
return Native.Server.ExecuteCommandHandler( name, player.userdata, args );
}
public static bool RemoveCommandHandler( string name, CommandHandler handler )
{
return Native.Server.RemoveCommandHandler( name, handler );
}
}
}

View File

@ -7,8 +7,15 @@ namespace Test
{
public class Program
{
static void MonoCommandHandler( Player player, string command, string[] args )
{
Debug.Info( player.GetName() + " executed command '" + command + "' with args: " + string.Join( " ", args ) );
}
static void Main( string[] args )
{
Server.AddCommandHandler( "mono", new CommandHandler( MonoCommandHandler ) );
Element.Root.OnPlayerJoin += Root_OnPlayerJoin;
//Element.Root.OnElementDestroy += ( Element sender, ElementEventArgs e ) =>

BIN
mta-mono/lib/mono-2.0.lib Normal file

Binary file not shown.

View File

@ -171,6 +171,7 @@
<ClCompile Include="src\CMonoMTALib.cpp" />
<ClCompile Include="src\CMonoObject.cpp" />
<ClCompile Include="src\Common.cpp" />
<ClCompile Include="src\CRegisteredCommands.cpp" />
<ClCompile Include="src\CResource.cpp" />
<ClCompile Include="src\CResourceManager.cpp" />
<ClCompile Include="src\extra\Vector2.cpp" />
@ -198,6 +199,7 @@
<ClInclude Include="src\CMonoMethod.h" />
<ClInclude Include="src\CMonoMTALib.h" />
<ClInclude Include="src\CMonoObject.h" />
<ClInclude Include="src\CRegisteredCommands.h" />
<ClInclude Include="src\CResource.h" />
<ClInclude Include="src\CResourceManager.h" />
<ClInclude Include="src\extra\Vector2.h" />

View File

@ -121,6 +121,9 @@
<ClCompile Include="src\CEvent.cpp">
<Filter>ResourceInterface</Filter>
</ClCompile>
<ClCompile Include="src\CRegisteredCommands.cpp">
<Filter>ResourceInterface</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\include\ILuaModuleManager.h">
@ -278,6 +281,9 @@
<ClInclude Include="src\CEvent.h">
<Filter>ResourceInterface</Filter>
</ClInclude>
<ClInclude Include="src\CRegisteredCommands.h">
<Filter>ResourceInterface</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Filter Include="MonoInterface">

View File

@ -51,7 +51,7 @@ int CFunctions::monoEventHandler( lua_State *pLuaVM )
if( pResource )
{
string strEventName;
void* pThis = nullptr;
void* pThis = nullptr;
CLuaArguments pLuaArgs;
@ -113,3 +113,69 @@ int CFunctions::monoEventHandler( lua_State *pLuaVM )
return 0;
}
int CFunctions::monoCommandHandler( lua_State* pLuaVM )
{
if( pLuaVM )
{
CResource *pResource = g_pResourceManager->GetFromList( pLuaVM );
if( pResource )
{
CLuaArguments pLuaArgs;
pLuaArgs.ReadArguments( pLuaVM );
if( pLuaArgs.Count() == 0 )
{
return 0;
}
void* pPlayerSource;
string strCommandName;
uint i = 0;
list< string > argv;
for( auto iter : pLuaArgs.GetArguments() )
{
int iLuaType = iter->GetType();
switch( i )
{
case 0:
{
pPlayerSource = iter->GetLightUserData();
break;
}
case 1:
{
strCommandName = iter->GetString();
break;
}
default:
{
if( iter->GetType() == LUA_TSTRING )
{
argv.push_back( iter->GetString() );
}
break;
}
}
i++;
}
if( pResource->ExecuteCommand( pPlayerSource, strCommandName, argv ) )
{
return 1;
}
}
}
return 0;
}

View File

@ -27,8 +27,9 @@ extern ILuaModuleManager10 *g_pModuleManager;
class CFunctions
{
public:
static int monoInit ( lua_State *pLuaVM );
static int monoEventHandler ( lua_State *pLuaVM );
static int monoInit ( lua_State* pLuaVM );
static int monoEventHandler ( lua_State* pLuaVM );
static int monoCommandHandler ( lua_State* pLuaVM );
};
#endif

View File

@ -28,6 +28,10 @@ void CMonoFunctions::AddInternals( void )
MONO_DECLARE( Server, SetPassword );
MONO_DECLARE( Server, GetVersion );
MONO_DECLARE( Server, AddCommandHandler );
MONO_DECLARE( Server, ExecuteCommandHandler );
MONO_DECLARE( Server, RemoveCommandHandler );
MONO_DECLARE( Game, GetType );
MONO_DECLARE( Game, GetMapName );
@ -728,6 +732,84 @@ bool CMonoFunctions::Server::SetPassword( MonoString* msPassword, bool bSave )
return false;
}
bool CMonoFunctions::Server::AddCommandHandler( MonoString* msCommand, MonoObject* pDelegate, bool bRestricted, bool bCaseSensitive )
{
if( RESOURCE )
{
if( !pDelegate )
{
g_pModuleManager->ErrorPrintf( "Invalid argument #1 in method 'Server::AddCommandHandler'\n" );
return false;
}
string strCommandName = mono_string_to_utf8( msCommand );
if( strCommandName.length() == 0 )
{
g_pModuleManager->ErrorPrintf( "Invalid argument #2 in method 'Server::AddCommandHandler'\n" );
return false;
}
if( RESOURCE->GetCommandManager()->Add( strCommandName, pDelegate, bRestricted, bCaseSensitive ) )
{
CLuaFunctionDefinitions::AddCommandHandler( RESOURCE->GetLua(), strCommandName.c_str(), CFunctions::monoCommandHandler, bRestricted, bCaseSensitive );
return true;
}
}
return false;
}
bool CMonoFunctions::Server::ExecuteCommandHandler( MonoString* msCommand, DWORD pUserData, MonoString* msArgs )
{
if( RESOURCE )
{
string strCommandName = mono_string_to_utf8( msCommand );
if( strCommandName.length() == 0 )
{
g_pModuleManager->ErrorPrintf( "Invalid argument #1 in method 'Server::ExecuteCommandHandler'\n" );
return false;
}
if( !pUserData )
{
g_pModuleManager->ErrorPrintf( "Invalid argument #2 in method 'Server::ExecuteCommandHandler'\n" );
return false;
}
string strArguments = mono_string_to_utf8( msArgs );
return CLuaFunctionDefinitions::ExecuteCommandHandler( RESOURCE->GetLua(), strCommandName.c_str(), (void*)pUserData, strArguments.c_str() );
}
return false;
}
bool CMonoFunctions::Server::RemoveCommandHandler( MonoString* msCommand, MonoObject* pDelegate )
{
if( RESOURCE )
{
string strCommandName = mono_string_to_utf8( msCommand );
if( strCommandName.length() == 0 )
{
g_pModuleManager->ErrorPrintf( "Invalid argument #1 in method 'Server::RemoveCommandHandler'\n" );
return false;
}
return RESOURCE->GetCommandManager()->Remove( strCommandName.c_str(), pDelegate );
}
return false;
}
MonoObject* CMonoFunctions::Server::GetVersion( void )
{
if( RESOURCE )
@ -854,4 +936,3 @@ bool CMonoFunctions::Game::RemoveRuleValue( MonoString* msKey )
return false;
}

View File

@ -62,6 +62,10 @@ public:
static bool OutputConsole ( MonoString* szText, DWORD pElement );
static bool SetPassword ( MonoString* msPassword, bool bSave );
static MonoObject* GetVersion ( void );
static bool AddCommandHandler ( MonoString* msCommand, MonoObject* pDelegate, bool bRestricted = false, bool bCaseSensitive = true );
static bool ExecuteCommandHandler ( MonoString* msCommand, DWORD pUserData, MonoString* msArgs );
static bool RemoveCommandHandler ( MonoString* msCommand, MonoObject* pDelegate = nullptr );
};
class Game

View File

@ -0,0 +1,191 @@
/*********************************************************
*
* Copyright © 2013, Innovation Roleplay Engine.
*
* All Rights Reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification,
* is permitted only for authors.
*
*********************************************************/
#include "CRegisteredCommands.h"
CRegisteredCommands::CRegisteredCommands( CResource* pResource )
{
this->m_pResource = pResource;
}
CRegisteredCommands::~CRegisteredCommands( void )
{
this->ClearCommands();
this->m_pResource = nullptr;
}
bool CRegisteredCommands::Add( string strCommandName, MonoObject* pDelegate, bool bRestricted, bool bCaseSensitive )
{
SCommand* pCommand = this->GetCommand( strCommandName );
if( pCommand && pCommand->pDelegate == pDelegate )
{
return false;
}
pCommand = new SCommand;
pCommand->strName = strCommandName;
pCommand->pDelegate = pDelegate;
pCommand->bRestricted = bRestricted;
pCommand->bCaseSensitive = bCaseSensitive;
this->m_Commands.push_back( pCommand );
return true;
}
bool CRegisteredCommands::Execute( void* pPlayer, string strCommandName, list< string > argv )
{
bool bHandled = false;
int iCompareResult;
for( CRegisteredCommands::SCommand* pCommand : this->m_Commands )
{
if( pCommand->bCaseSensitive )
{
iCompareResult = strcmp( pCommand->strName.c_str(), strCommandName.c_str() );
}
else
{
iCompareResult = stricmp( pCommand->strName.c_str(), strCommandName.c_str() );
}
if( iCompareResult == 0 )
{
this->Invoke( pPlayer, pCommand->pDelegate, strCommandName, argv );
bHandled = true;
}
}
return bHandled;
}
bool CRegisteredCommands::Remove( string strCommandName, MonoObject* pDelegate )
{
bool bFound = false;
iterator iter = this->m_Commands.begin();
int iCompareResult;
while( iter != this->m_Commands.end() )
{
if( ( *iter )->bCaseSensitive )
{
iCompareResult = strcmp( ( *iter )->strName.c_str(), strCommandName.c_str() );
}
else
{
iCompareResult = stricmp( ( *iter )->strName.c_str(), strCommandName.c_str() );
}
if( iCompareResult == 0 )
{
if( ( *iter )->pDelegate != pDelegate )
{
iter++;
continue;
}
delete *iter;
iter = this->m_Commands.erase( iter );
bFound = true;
}
else
{
iter++;
}
}
return bFound;
}
void CRegisteredCommands::ClearCommands( void )
{
const_iterator iter = this->m_Commands.begin();
for( ; iter != this->m_Commands.end(); iter++ )
{
delete *iter;
}
this->m_Commands.clear();
}
CRegisteredCommands::SCommand* CRegisteredCommands::GetCommand( string strName )
{
for( CRegisteredCommands::SCommand* pCommand : this->m_Commands )
{
pCommand->strName.compare( strName );
if( pCommand->bCaseSensitive )
{
if( pCommand->strName == strName )
{
return pCommand;
}
}
else if( stricmp( pCommand->strName.c_str(), strName.c_str() ) )
{
return pCommand;
}
}
return nullptr;
}
void CRegisteredCommands::Invoke( void* pUserData, MonoObject* pDelegate, string strCommandName, list< string > argv )
{
CMonoMTALib* pMTALib = this->m_pResource->GetDomain()->GetMTALib();
CMonoCorlib* pCorlib = this->m_pResource->GetDomain()->GetCorlib();
assert( pMTALib );
assert( pCorlib );
MonoObject* pPlayer = pMTALib->RegisterElement( pUserData );
if( !pPlayer )
{
return;
}
MonoString* pCommandName = this->m_pResource->GetDomain()->NewString( strCommandName );
MonoArray* pArguments = mono_array_new( this->m_pResource->GetDomain()->GetMonoPtr(), pCorlib->Class[ "string" ]->GetMonoPtr(), argv.size() );
uint index = 0;
for( string arg : argv )
{
mono_array_set( pArguments, MonoString*, index++, this->m_pResource->GetDomain()->NewString( arg ) );
}
gpointer* params = new gpointer[ 3 ];
params[ 0 ] = pPlayer;
params[ 1 ] = pCommandName;
params[ 2 ] = pArguments;
MonoObject* pException = nullptr;
mono_runtime_delegate_invoke( pDelegate, params, &pException );
delete [] params;
this->m_pResource->GetDomain()->HandleException( pException );
}

View File

@ -0,0 +1,53 @@
/*********************************************************
*
* Copyright © 2013, Innovation Roleplay Engine.
*
* All Rights Reserved.
*
* Redistribution and use in source and binary forms,
* with or without modification,
* is permitted only for authors.
*
*********************************************************/
class CRegisteredCommands;
#ifndef __CREGISTEREDCOMMANDS_H
#define __CREGISTEREDCOMMANDS_H
#include "CResource.h"
class CRegisteredCommands
{
private:
struct SCommand
{
string strName;
MonoObject* pDelegate;
bool bRestricted;
bool bCaseSensitive;
};
typedef list< SCommand* >::iterator iterator;
typedef list< SCommand* >::const_iterator const_iterator;
CResource* m_pResource;
list< SCommand* > m_Commands;
public:
CRegisteredCommands ( CResource* pResource );
~CRegisteredCommands ( void );
bool Add ( string strCommandName, MonoObject* pDelegate, bool bRestricted = false, bool bCaseSensitive = true );
bool Execute ( void* pPlayer, string strCommandName, list< string > argv );
bool Remove ( string strCommandName, MonoObject* pDelegate = nullptr );
void ClearCommands ( void );
private:
void Invoke ( void* pPlayer, MonoObject* pDelegate, string strCommandName, list< string > argv );
SCommand* GetCommand ( string strName );
};
#endif

View File

@ -21,6 +21,7 @@ CResource::CResource( CMonoInterface* pMono, lua_State *pLuaVM, string sName )
this->m_pMonoDomain = nullptr;
this->m_pEventManager = new CEventManager( this );
this->m_pRegisteredCommands = new CRegisteredCommands( this );
}
CResource::~CResource( void )
@ -31,6 +32,7 @@ CResource::~CResource( void )
g_pResourceManager->RemoveFromList( this );
SAFE_DELETE( this->m_pRegisteredCommands );
SAFE_DELETE( this->m_pEventManager );
this->GetMono()->SetDomain( nullptr, true );
@ -84,6 +86,16 @@ bool CResource::RemoveEvent( const char* szName, const char* szHandleElement )
return false;
}
bool CResource::ExecuteCommand( void* pPlayer, string strCommandName, list< string > argv )
{
if( !pPlayer )
{
return false;
}
return this->m_pRegisteredCommands->Execute( pPlayer, strCommandName, argv );
}
void CResource::RegisterEvents( void )
{
if( this->m_pLuaVM )

View File

@ -22,6 +22,7 @@ class CResource;
#include "CResourceManager.h"
#include "CEventManager.h"
#include "CRegisteredCommands.h"
#include "CFunctions.h"
#include "extra/CLuaArgument.h"
@ -43,6 +44,7 @@ private:
CMonoDomain* m_pMonoDomain;
CEventManager* m_pEventManager;
CRegisteredCommands* m_pRegisteredCommands;
public:
CResource ( CMonoInterface* m_pMono, lua_State *pLuaVM, string sName );
@ -52,6 +54,8 @@ public:
bool AddEvent ( const char* szName, const char* szHandleElement );
bool RemoveEvent ( const char* szName, const char* szHandleElement );
bool ExecuteCommand ( void* pPlayer, string strCommandName, list< string > argv );
void RegisterEvents ( void );
void RemoveEvents ( void );
bool Init ( void );
@ -68,6 +72,7 @@ public:
CMonoInterface* GetMono ( void ) { return this->m_pMono; }
CMonoDomain* GetDomain ( void ) { return this->m_pMonoDomain; }
CEventManager* GetEventManager ( void ) { return this->m_pEventManager; }
CRegisteredCommands* GetCommandManager ( void ) { return this->m_pRegisteredCommands; }
private:

View File

@ -46,6 +46,14 @@ extern "C"
#include "Common.h"
#ifndef stricmp
#ifdef _MSC_VER
#define stricmp _stricmp
#else
#define stricmp strcasecmp
#endif
#endif
#define SAFE_DELETE(p) { if(p) { delete (p); (p)=nullptr; } }
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=nullptr; } }

View File

@ -200,6 +200,69 @@ bool CLuaFunctionDefinitions::SetPlayerAnnounceValue( lua_State* pLuaVM, void* p
return false;
}
bool CLuaFunctionDefinitions::AddCommandHandler( lua_State* pLuaVM, const char* szCommand, lua_CFunction iLuaFunction, bool bRestricted, bool bCaseSensitive )
{
CLuaArguments pLuaArguments;
pLuaArguments.PushString( szCommand );
pLuaArguments.PushFunction( iLuaFunction );
pLuaArguments.PushBoolean( bRestricted );
pLuaArguments.PushBoolean( bCaseSensitive );
if( pLuaArguments.Call( pLuaVM, "addCommandHandler", 1 ) )
{
CLuaArgument pLuaArgument( pLuaVM, -1 );
if( pLuaArgument.GetType() == LUA_TBOOLEAN )
{
return pLuaArgument.GetBoolean();
}
}
return false;
}
bool CLuaFunctionDefinitions::ExecuteCommandHandler( lua_State* pLuaVM, const char* szCommand, void* pUserData, const char* szArgs )
{
CLuaArguments pLuaArguments;
pLuaArguments.PushString( szCommand );
pLuaArguments.PushUserData( pUserData );
pLuaArguments.PushString( szArgs );
if( pLuaArguments.Call( pLuaVM, "executeCommandHandler", 1 ) )
{
CLuaArgument pLuaArgument( pLuaVM, -1 );
if( pLuaArgument.GetType() == LUA_TBOOLEAN )
{
return pLuaArgument.GetBoolean();
}
}
return false;
}
bool CLuaFunctionDefinitions::RemoveCommandHandler( lua_State* pLuaVM, const char* szCommand, lua_CFunction iLuaFunction )
{
CLuaArguments pLuaArguments;
pLuaArguments.PushString( szCommand );
pLuaArguments.PushFunction( iLuaFunction );
if( pLuaArguments.Call( pLuaVM, "removeCommandHandler", 1 ) )
{
CLuaArgument pLuaArgument( pLuaVM, -1 );
if( pLuaArgument.GetType() == LUA_TBOOLEAN )
{
return pLuaArgument.GetBoolean();
}
}
return false;
}
bool CLuaFunctionDefinitions::AddEvent( lua_State* pLuaVM, const char* szName, bool bAllowRemoteTrigger )
{
CLuaArguments pLuaArguments;

View File

@ -37,6 +37,10 @@ public:
static string GetGameType ( lua_State* pLuaVM );
static string GetMapName ( lua_State* pLuaVM );
static bool AddCommandHandler ( lua_State* pLuaVM, const char* szCommand, lua_CFunction iLuaFunction, bool bRestricted = false, bool bCaseSensitive = true );
static bool ExecuteCommandHandler ( lua_State* pLuaVM, const char* szCommand, void* pUserData, const char* szArgs );
static bool RemoveCommandHandler ( lua_State* pLuaVM, const char* szCommand, lua_CFunction iLuaFunction );
// static int CallRemote ( lua_State* luaVM );
// static int FetchRemote ( lua_State* luaVM );

View File

@ -12,7 +12,7 @@
#define MODULE_NAME "Mono 4.2.1"
#define MODULE_AUTHOR "Dmitry Korolev <kernell@mtaroleplay.ru>"
#define MODULE_VERSION 0.23f
#define MODULE_VERSION 0.24f
#include "CFunctions.h"
#include "CResource.h"