add example module to game interface. convert gi command registration to a iw4madmin request
This commit is contained in:
parent
2340e30c2d
commit
ad89ecb39d
@ -542,11 +542,11 @@ OnExecuteCommand( event )
|
|||||||
{
|
{
|
||||||
if ( IsDefined( executionContextEntity ) )
|
if ( IsDefined( executionContextEntity ) )
|
||||||
{
|
{
|
||||||
response = executionContextEntity [[command]]( event, data );
|
response = executionContextEntity thread [[command]]( event, data );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
[[command]]( event );
|
thread [[command]]( event );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -52,9 +52,9 @@ OnPlayerConnect()
|
|||||||
if ( player IsTestClient() )
|
if ( player IsTestClient() )
|
||||||
{
|
{
|
||||||
// we don't want to track bots
|
// we don't want to track bots
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
player thread SetPersistentData();
|
player thread SetPersistentData();
|
||||||
player thread WaitForClientEvents();
|
player thread WaitForClientEvents();
|
||||||
}
|
}
|
||||||
|
@ -49,11 +49,14 @@ Setup()
|
|||||||
level.eventTypes.urlRequested = "UrlRequested";
|
level.eventTypes.urlRequested = "UrlRequested";
|
||||||
level.eventTypes.urlRequestCompleted = "UrlRequestCompleted";
|
level.eventTypes.urlRequestCompleted = "UrlRequestCompleted";
|
||||||
level.eventTypes.registerCommandRequested = "RegisterCommandRequested";
|
level.eventTypes.registerCommandRequested = "RegisterCommandRequested";
|
||||||
|
level.eventTypes.getCommandsRequested = "GetCommandsRequested";
|
||||||
|
|
||||||
level.eventCallbacks[level.eventTypes.urlRequestCompleted] = ::OnUrlRequestCompletedCallback;
|
level.eventCallbacks[level.eventTypes.urlRequestCompleted] = ::OnUrlRequestCompletedCallback;
|
||||||
|
level.eventCallbacks[level.eventTypes.getCommandsRequested] = ::OnCommandsRequestedCallback;
|
||||||
|
|
||||||
level.iw4madminIntegrationDefaultPerformance = 200;
|
level.iw4madminIntegrationDefaultPerformance = 200;
|
||||||
level.notifyEntities = [];
|
level.notifyEntities = [];
|
||||||
|
level.customCommands = [];
|
||||||
|
|
||||||
level notify( level.notifyTypes.sharedFunctionsInitialized );
|
level notify( level.notifyTypes.sharedFunctionsInitialized );
|
||||||
level waittill( level.notifyTypes.gameFunctionsInitialized );
|
level waittill( level.notifyTypes.gameFunctionsInitialized );
|
||||||
@ -194,6 +197,32 @@ SaveTrackingMetrics()
|
|||||||
|
|
||||||
// #region register script command
|
// #region register script command
|
||||||
|
|
||||||
|
OnCommandsRequestedCallback( event )
|
||||||
|
{
|
||||||
|
scripts\_integration_base::LogDebug( "Get commands requested" );
|
||||||
|
thread SendCommands( event.data["name"] );
|
||||||
|
}
|
||||||
|
|
||||||
|
SendCommands( commandName )
|
||||||
|
{
|
||||||
|
level endon( level.eventTypes.gameEnd );
|
||||||
|
|
||||||
|
for ( i = 0; i < level.customCommands.size; i++ )
|
||||||
|
{
|
||||||
|
data = level.customCommands[i];
|
||||||
|
|
||||||
|
if ( IsDefined( commandName ) && commandName != data["name"] )
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
scripts\_integration_base::LogDebug( "Sending custom command " + ( i + 1 ) + "/" + level.customCommands.size + ": " + data["name"] );
|
||||||
|
commandRegisterRequest = scripts\_integration_base::BuildEventRequest( false, level.eventTypes.registerCommandRequested, "", undefined, data );
|
||||||
|
// not threading here as there might be a lot of commands to register
|
||||||
|
scripts\_integration_base::QueueEvent( commandRegisterRequest, level.eventTypes.registerCommandRequested, undefined );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RegisterScriptCommandObject( command )
|
RegisterScriptCommandObject( command )
|
||||||
{
|
{
|
||||||
RegisterScriptCommand( command.eventKey, command.name, command.alias, command.description, command.minPermission, command.supportedGames, command.requiresTarget, command.handler );
|
RegisterScriptCommand( command.eventKey, command.name, command.alias, command.description, command.minPermission, command.supportedGames, command.requiresTarget, command.handler );
|
||||||
@ -258,8 +287,7 @@ RegisterScriptCommand( eventKey, name, alias, description, minPermission, suppor
|
|||||||
scripts\_integration_base::LogWarning( "handler not defined for script command " + name );
|
scripts\_integration_base::LogWarning( "handler not defined for script command " + name );
|
||||||
}
|
}
|
||||||
|
|
||||||
commandRegisterRequest = scripts\_integration_base::BuildEventRequest( false, level.eventTypes.registerCommandRequested, "", undefined, data );
|
level.customCommands[level.customCommands.size] = data;
|
||||||
thread scripts\_integration_base::QueueEvent( commandRegisterRequest, level.eventTypes.registerCommandRequested, undefined );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// #end region
|
// #end region
|
||||||
@ -391,7 +419,6 @@ GetNextNotifyEntity()
|
|||||||
return max;
|
return max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// #end region
|
// #end region
|
||||||
|
|
||||||
// #region team balance
|
// #region team balance
|
||||||
|
85
GameFiles/GameInterface/example_module.gsc
Normal file
85
GameFiles/GameInterface/example_module.gsc
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
Init()
|
||||||
|
{
|
||||||
|
// this gives the game interface time to setup
|
||||||
|
waittillframeend;
|
||||||
|
thread ModuleSetup();
|
||||||
|
}
|
||||||
|
|
||||||
|
ModuleSetup()
|
||||||
|
{
|
||||||
|
// waiting until the game specific functions are ready
|
||||||
|
level waittill( level.notifyTypes.gameFunctionsInitialized );
|
||||||
|
|
||||||
|
RegisterCustomCommands();
|
||||||
|
}
|
||||||
|
|
||||||
|
RegisterCustomCommands()
|
||||||
|
{
|
||||||
|
command = SpawnStruct();
|
||||||
|
|
||||||
|
// unique key for each command (how iw4madmin identifies the command)
|
||||||
|
command.eventKey = "PrintLineCommand";
|
||||||
|
|
||||||
|
// name of the command (cannot conflict with existing command names)
|
||||||
|
command.name = "println";
|
||||||
|
|
||||||
|
// short version of the command (cannot conflcit with existing command aliases)
|
||||||
|
command.alias = "pl";
|
||||||
|
|
||||||
|
// description of what the command does
|
||||||
|
command.description = "prints line to game";
|
||||||
|
|
||||||
|
// minimum permision required to execute
|
||||||
|
// valid values: User, Trusted, Moderator, Administrator, SeniorAdmin, Owner
|
||||||
|
command.minPermission = "Trusted";
|
||||||
|
|
||||||
|
// games the command is supported on
|
||||||
|
// separate with comma or don't define for all
|
||||||
|
// valid values: IW3, IW4, IW5, IW6, T4, T5, T6, T7, SHG1, CSGO, H1
|
||||||
|
command.supportedGames = "IW4,IW5,T5,T6";
|
||||||
|
|
||||||
|
// indicates if a target player must be provided to execvute on
|
||||||
|
command.requiresTarget = false;
|
||||||
|
|
||||||
|
// code to run when the command is executed
|
||||||
|
command.handler = ::PrintLnCommandCallback;
|
||||||
|
|
||||||
|
// register the command with integration to be send to iw4madmin
|
||||||
|
scripts\_integration_shared::RegisterScriptCommandObject( command );
|
||||||
|
|
||||||
|
// you can also register via parameters
|
||||||
|
scripts\_integration_shared::RegisterScriptCommand( "AffirmationCommand", "affirm", "af", "provide affirmations", "User", undefined, false, ::AffirmationCommandCallback );
|
||||||
|
}
|
||||||
|
|
||||||
|
PrintLnCommandCallback( event )
|
||||||
|
{
|
||||||
|
if ( IsDefined( event.data["args"] ) )
|
||||||
|
{
|
||||||
|
IPrintLnBold( event.data["args"] );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
scripts\_integration_base::LogDebug( "No data was provided for PrintLnCallback" );
|
||||||
|
}
|
||||||
|
|
||||||
|
AffirmationCommandCallback( event, _ )
|
||||||
|
{
|
||||||
|
level endon( level.eventTypes.gameEnd );
|
||||||
|
|
||||||
|
request = SpawnStruct();
|
||||||
|
request.url = "https://www.affirmations.dev";
|
||||||
|
request.method = "GET";
|
||||||
|
|
||||||
|
// If making a post request you can also provide more data
|
||||||
|
// request.body = "Body of the post message";
|
||||||
|
// request.headers = [];
|
||||||
|
// request.headers["Authorization"] = "api-key";
|
||||||
|
|
||||||
|
scripts\_integration_shared::RequestUrlObject( request );
|
||||||
|
request waittill( level.eventTypes.urlRequestCompleted, response );
|
||||||
|
|
||||||
|
// horrible json parsing.. but it's just an example
|
||||||
|
parsedResponse = strtok( response, "\"" );
|
||||||
|
|
||||||
|
self IPrintLnBold ( "^5" + parsedResponse[parsedResponse.size - 2] );
|
||||||
|
}
|
@ -86,6 +86,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GameInterface", "GameInterf
|
|||||||
GameFiles\GameInterface\_integration_t5zm.gsc = GameFiles\GameInterface\_integration_t5zm.gsc
|
GameFiles\GameInterface\_integration_t5zm.gsc = GameFiles\GameInterface\_integration_t5zm.gsc
|
||||||
GameFiles\GameInterface\_integration_t6.gsc = GameFiles\GameInterface\_integration_t6.gsc
|
GameFiles\GameInterface\_integration_t6.gsc = GameFiles\GameInterface\_integration_t6.gsc
|
||||||
GameFiles\GameInterface\_integration_t6zm_helper.gsc = GameFiles\GameInterface\_integration_t6zm_helper.gsc
|
GameFiles\GameInterface\_integration_t6zm_helper.gsc = GameFiles\GameInterface\_integration_t6zm_helper.gsc
|
||||||
|
GameFiles\GameInterface\example_module.gsc = GameFiles\GameInterface\example_module.gsc
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AntiCheat", "AntiCheat", "{AB83BAC0-C539-424A-BF00-78487C10753C}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "AntiCheat", "AntiCheat", "{AB83BAC0-C539-424A-BF00-78487C10753C}"
|
||||||
|
@ -147,6 +147,18 @@ namespace Integrations.Cod
|
|||||||
{
|
{
|
||||||
var convertedRConPassword = ConvertEncoding(RConPassword);
|
var convertedRConPassword = ConvertEncoding(RConPassword);
|
||||||
var convertedParameters = ConvertEncoding(parameters);
|
var convertedParameters = ConvertEncoding(parameters);
|
||||||
|
byte SafeConversion(char c)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return Convert.ToByte(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
return (byte)'.';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
switch (type)
|
switch (type)
|
||||||
{
|
{
|
||||||
@ -154,30 +166,30 @@ namespace Integrations.Cod
|
|||||||
waitForResponse = true;
|
waitForResponse = true;
|
||||||
payload = string
|
payload = string
|
||||||
.Format(_config.CommandPrefixes.RConGetDvar, convertedRConPassword,
|
.Format(_config.CommandPrefixes.RConGetDvar, convertedRConPassword,
|
||||||
convertedParameters + '\0').Select(Convert.ToByte).ToArray();
|
convertedParameters + '\0').Select(SafeConversion).ToArray();
|
||||||
break;
|
break;
|
||||||
case StaticHelpers.QueryType.SET_DVAR:
|
case StaticHelpers.QueryType.SET_DVAR:
|
||||||
payload = string
|
payload = string
|
||||||
.Format(_config.CommandPrefixes.RConSetDvar, convertedRConPassword,
|
.Format(_config.CommandPrefixes.RConSetDvar, convertedRConPassword,
|
||||||
convertedParameters + '\0').Select(Convert.ToByte).ToArray();
|
convertedParameters + '\0').Select(SafeConversion).ToArray();
|
||||||
break;
|
break;
|
||||||
case StaticHelpers.QueryType.COMMAND:
|
case StaticHelpers.QueryType.COMMAND:
|
||||||
payload = string
|
payload = string
|
||||||
.Format(_config.CommandPrefixes.RConCommand, convertedRConPassword,
|
.Format(_config.CommandPrefixes.RConCommand, convertedRConPassword,
|
||||||
convertedParameters + '\0').Select(Convert.ToByte).ToArray();
|
convertedParameters + '\0').Select(SafeConversion).ToArray();
|
||||||
break;
|
break;
|
||||||
case StaticHelpers.QueryType.GET_STATUS:
|
case StaticHelpers.QueryType.GET_STATUS:
|
||||||
waitForResponse = true;
|
waitForResponse = true;
|
||||||
payload = (_config.CommandPrefixes.RConGetStatus + '\0').Select(Convert.ToByte).ToArray();
|
payload = (_config.CommandPrefixes.RConGetStatus + '\0').Select(SafeConversion).ToArray();
|
||||||
break;
|
break;
|
||||||
case StaticHelpers.QueryType.GET_INFO:
|
case StaticHelpers.QueryType.GET_INFO:
|
||||||
waitForResponse = true;
|
waitForResponse = true;
|
||||||
payload = (_config.CommandPrefixes.RConGetInfo + '\0').Select(Convert.ToByte).ToArray();
|
payload = (_config.CommandPrefixes.RConGetInfo + '\0').Select(SafeConversion).ToArray();
|
||||||
break;
|
break;
|
||||||
case StaticHelpers.QueryType.COMMAND_STATUS:
|
case StaticHelpers.QueryType.COMMAND_STATUS:
|
||||||
waitForResponse = true;
|
waitForResponse = true;
|
||||||
payload = string.Format(_config.CommandPrefixes.RConCommand, convertedRConPassword, "status\0")
|
payload = string.Format(_config.CommandPrefixes.RConCommand, convertedRConPassword, "status\0")
|
||||||
.Select(Convert.ToByte).ToArray();
|
.Select(SafeConversion).ToArray();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -92,9 +92,7 @@ const plugin = {
|
|||||||
const input = serverState.inQueue.shift();
|
const input = serverState.inQueue.shift();
|
||||||
|
|
||||||
// if we queued an event then the next loop will be at the value set complete
|
// if we queued an event then the next loop will be at the value set complete
|
||||||
if (await this.processEventMessage(input, serverValueEvent.server)) {
|
await this.processEventMessage(input, serverValueEvent.server);
|
||||||
// return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.logDebug('loop complete');
|
this.logger.logDebug('loop complete');
|
||||||
@ -134,7 +132,8 @@ const plugin = {
|
|||||||
serverState.enabled = true;
|
serverState.enabled = true;
|
||||||
serverState.running = true;
|
serverState.running = true;
|
||||||
serverState.initializationInProgress = false;
|
serverState.initializationInProgress = false;
|
||||||
|
|
||||||
|
this.sendEventMessage(responseEvent.server, true, 'GetCommandsRequested', null, null, null, {});
|
||||||
this.requestGetDvar(inDvar, responseEvent.server);
|
this.requestGetDvar(inDvar, responseEvent.server);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -145,7 +144,9 @@ const plugin = {
|
|||||||
const serverState = servers[responseEvent.server.id];
|
const serverState = servers[responseEvent.server.id];
|
||||||
serverState.outQueue.shift();
|
serverState.outQueue.shift();
|
||||||
|
|
||||||
if (responseEvent.server.connectedClients.count === 0) {
|
const utilities = importNamespace('SharedLibraryCore.Utilities');
|
||||||
|
|
||||||
|
if (responseEvent.server.connectedClients.count === 0 && !utilities.isDevelopment) {
|
||||||
// no clients connected so we don't need to query
|
// no clients connected so we don't need to query
|
||||||
serverState.running = false;
|
serverState.running = false;
|
||||||
return;
|
return;
|
||||||
@ -304,9 +305,22 @@ const plugin = {
|
|||||||
this.scriptHelper.requestUrl(urlRequest, response => {
|
this.scriptHelper.requestUrl(urlRequest, response => {
|
||||||
this.logger.logDebug('Got response for gamescript web request - {Response}', response);
|
this.logger.logDebug('Got response for gamescript web request - {Response}', response);
|
||||||
|
|
||||||
|
if ( typeof response !== 'string' && !(response instanceof String) )
|
||||||
|
{
|
||||||
|
response = JSON.stringify(response);
|
||||||
|
}
|
||||||
|
|
||||||
const max = 10;
|
const max = 10;
|
||||||
this.logger.logDebug(`response length ${response.length}`);
|
this.logger.logDebug(`response length ${response.length}`);
|
||||||
let chunks = chunkString(response.replace(/"/gm, '\\"').replace(/[\n|\t]/gm, ''), 800);
|
|
||||||
|
let quoteReplace = '\\"';
|
||||||
|
// todo: may be more than just T6
|
||||||
|
if (server.gameCode === 'T6')
|
||||||
|
{
|
||||||
|
quoteReplace = '\\\\"';
|
||||||
|
}
|
||||||
|
|
||||||
|
let chunks = chunkString(response.replace(/"/gm, quoteReplace).replace(/[\n|\t]/gm, ''), 800);
|
||||||
if (chunks.length > max)
|
if (chunks.length > max)
|
||||||
{
|
{
|
||||||
this.logger.logWarning(`Response chunks greater than max (${max}). Data truncated!`);
|
this.logger.logWarning(`Response chunks greater than max (${max}). Data truncated!`);
|
||||||
@ -454,9 +468,15 @@ const plugin = {
|
|||||||
if (!validateEnabled(gameEvent.owner, gameEvent.origin)) {
|
if (!validateEnabled(gameEvent.owner, gameEvent.origin)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
sendScriptCommand(gameEvent.owner, `${event.data['eventKey']}Execute`, gameEvent.origin, gameEvent.target, {
|
|
||||||
args: gameEvent.data
|
if (gameEvent.data === '--reload')
|
||||||
});
|
{
|
||||||
|
this.sendEventMessage(gameEvent.owner, true, 'GetCommandsRequested', null, null, null, { name: gameEvent.extra.name });
|
||||||
|
} else {
|
||||||
|
sendScriptCommand(gameEvent.owner, `${event.data['eventKey']}Execute`, gameEvent.origin, gameEvent.target, {
|
||||||
|
args: gameEvent.data
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user