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 ) )
|
||||
{
|
||||
response = executionContextEntity [[command]]( event, data );
|
||||
response = executionContextEntity thread [[command]]( event, data );
|
||||
}
|
||||
else
|
||||
{
|
||||
[[command]]( event );
|
||||
thread [[command]]( event );
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -52,9 +52,9 @@ OnPlayerConnect()
|
||||
if ( player IsTestClient() )
|
||||
{
|
||||
// we don't want to track bots
|
||||
continue;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
player thread SetPersistentData();
|
||||
player thread WaitForClientEvents();
|
||||
}
|
||||
|
@ -49,11 +49,14 @@ Setup()
|
||||
level.eventTypes.urlRequested = "UrlRequested";
|
||||
level.eventTypes.urlRequestCompleted = "UrlRequestCompleted";
|
||||
level.eventTypes.registerCommandRequested = "RegisterCommandRequested";
|
||||
level.eventTypes.getCommandsRequested = "GetCommandsRequested";
|
||||
|
||||
level.eventCallbacks[level.eventTypes.urlRequestCompleted] = ::OnUrlRequestCompletedCallback;
|
||||
level.eventCallbacks[level.eventTypes.getCommandsRequested] = ::OnCommandsRequestedCallback;
|
||||
|
||||
level.iw4madminIntegrationDefaultPerformance = 200;
|
||||
level.notifyEntities = [];
|
||||
level.customCommands = [];
|
||||
|
||||
level notify( level.notifyTypes.sharedFunctionsInitialized );
|
||||
level waittill( level.notifyTypes.gameFunctionsInitialized );
|
||||
@ -194,6 +197,32 @@ SaveTrackingMetrics()
|
||||
|
||||
// #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 )
|
||||
{
|
||||
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 );
|
||||
}
|
||||
|
||||
commandRegisterRequest = scripts\_integration_base::BuildEventRequest( false, level.eventTypes.registerCommandRequested, "", undefined, data );
|
||||
thread scripts\_integration_base::QueueEvent( commandRegisterRequest, level.eventTypes.registerCommandRequested, undefined );
|
||||
level.customCommands[level.customCommands.size] = data;
|
||||
}
|
||||
|
||||
// #end region
|
||||
@ -391,7 +419,6 @@ GetNextNotifyEntity()
|
||||
return max;
|
||||
}
|
||||
|
||||
|
||||
// #end region
|
||||
|
||||
// #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_t6.gsc = GameFiles\GameInterface\_integration_t6.gsc
|
||||
GameFiles\GameInterface\_integration_t6zm_helper.gsc = GameFiles\GameInterface\_integration_t6zm_helper.gsc
|
||||
GameFiles\GameInterface\example_module.gsc = GameFiles\GameInterface\example_module.gsc
|
||||
EndProjectSection
|
||||
EndProject
|
||||
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 convertedParameters = ConvertEncoding(parameters);
|
||||
byte SafeConversion(char c)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Convert.ToByte(c);
|
||||
}
|
||||
|
||||
catch
|
||||
{
|
||||
return (byte)'.';
|
||||
}
|
||||
};
|
||||
|
||||
switch (type)
|
||||
{
|
||||
@ -154,30 +166,30 @@ namespace Integrations.Cod
|
||||
waitForResponse = true;
|
||||
payload = string
|
||||
.Format(_config.CommandPrefixes.RConGetDvar, convertedRConPassword,
|
||||
convertedParameters + '\0').Select(Convert.ToByte).ToArray();
|
||||
convertedParameters + '\0').Select(SafeConversion).ToArray();
|
||||
break;
|
||||
case StaticHelpers.QueryType.SET_DVAR:
|
||||
payload = string
|
||||
.Format(_config.CommandPrefixes.RConSetDvar, convertedRConPassword,
|
||||
convertedParameters + '\0').Select(Convert.ToByte).ToArray();
|
||||
convertedParameters + '\0').Select(SafeConversion).ToArray();
|
||||
break;
|
||||
case StaticHelpers.QueryType.COMMAND:
|
||||
payload = string
|
||||
.Format(_config.CommandPrefixes.RConCommand, convertedRConPassword,
|
||||
convertedParameters + '\0').Select(Convert.ToByte).ToArray();
|
||||
convertedParameters + '\0').Select(SafeConversion).ToArray();
|
||||
break;
|
||||
case StaticHelpers.QueryType.GET_STATUS:
|
||||
waitForResponse = true;
|
||||
payload = (_config.CommandPrefixes.RConGetStatus + '\0').Select(Convert.ToByte).ToArray();
|
||||
payload = (_config.CommandPrefixes.RConGetStatus + '\0').Select(SafeConversion).ToArray();
|
||||
break;
|
||||
case StaticHelpers.QueryType.GET_INFO:
|
||||
waitForResponse = true;
|
||||
payload = (_config.CommandPrefixes.RConGetInfo + '\0').Select(Convert.ToByte).ToArray();
|
||||
payload = (_config.CommandPrefixes.RConGetInfo + '\0').Select(SafeConversion).ToArray();
|
||||
break;
|
||||
case StaticHelpers.QueryType.COMMAND_STATUS:
|
||||
waitForResponse = true;
|
||||
payload = string.Format(_config.CommandPrefixes.RConCommand, convertedRConPassword, "status\0")
|
||||
.Select(Convert.ToByte).ToArray();
|
||||
.Select(SafeConversion).ToArray();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -92,9 +92,7 @@ const plugin = {
|
||||
const input = serverState.inQueue.shift();
|
||||
|
||||
// if we queued an event then the next loop will be at the value set complete
|
||||
if (await this.processEventMessage(input, serverValueEvent.server)) {
|
||||
// return;
|
||||
}
|
||||
await this.processEventMessage(input, serverValueEvent.server);
|
||||
}
|
||||
|
||||
this.logger.logDebug('loop complete');
|
||||
@ -134,7 +132,8 @@ const plugin = {
|
||||
serverState.enabled = true;
|
||||
serverState.running = true;
|
||||
serverState.initializationInProgress = false;
|
||||
|
||||
|
||||
this.sendEventMessage(responseEvent.server, true, 'GetCommandsRequested', null, null, null, {});
|
||||
this.requestGetDvar(inDvar, responseEvent.server);
|
||||
},
|
||||
|
||||
@ -145,7 +144,9 @@ const plugin = {
|
||||
const serverState = servers[responseEvent.server.id];
|
||||
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
|
||||
serverState.running = false;
|
||||
return;
|
||||
@ -304,9 +305,22 @@ const plugin = {
|
||||
this.scriptHelper.requestUrl(urlRequest, 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;
|
||||
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)
|
||||
{
|
||||
this.logger.logWarning(`Response chunks greater than max (${max}). Data truncated!`);
|
||||
@ -454,9 +468,15 @@ const plugin = {
|
||||
if (!validateEnabled(gameEvent.owner, gameEvent.origin)) {
|
||||
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