implement initial url request functionality for game interface
This commit is contained in:
parent
e843f839f5
commit
2fcbab9a37
@ -377,7 +377,6 @@ namespace IW4MAdmin
|
|||||||
if (E.Origin.State != ClientState.Connected)
|
if (E.Origin.State != ClientState.Connected)
|
||||||
{
|
{
|
||||||
E.Origin.State = ClientState.Connected;
|
E.Origin.State = ClientState.Connected;
|
||||||
E.Origin.LastConnection = DateTime.UtcNow;
|
|
||||||
E.Origin.Connections += 1;
|
E.Origin.Connections += 1;
|
||||||
|
|
||||||
ChatHistory.Add(new ChatInfo()
|
ChatHistory.Add(new ChatInfo()
|
||||||
|
@ -37,7 +37,7 @@ Setup()
|
|||||||
level.clientDataKey = "clientData";
|
level.clientDataKey = "clientData";
|
||||||
|
|
||||||
level.eventTypes = spawnstruct();
|
level.eventTypes = spawnstruct();
|
||||||
level.eventTypes.localClientEvent = "client_event";
|
level.eventTypes.eventAvailable = "EventAvailable";
|
||||||
level.eventTypes.clientDataReceived = "ClientDataReceived";
|
level.eventTypes.clientDataReceived = "ClientDataReceived";
|
||||||
level.eventTypes.clientDataRequested = "ClientDataRequested";
|
level.eventTypes.clientDataRequested = "ClientDataRequested";
|
||||||
level.eventTypes.setClientDataRequested = "SetClientDataRequested";
|
level.eventTypes.setClientDataRequested = "SetClientDataRequested";
|
||||||
@ -70,6 +70,9 @@ Setup()
|
|||||||
_SetDvarIfUninitialized( level.eventBus.outVar, "" );
|
_SetDvarIfUninitialized( level.eventBus.outVar, "" );
|
||||||
_SetDvarIfUninitialized( level.commonKeys.enabled, 1 );
|
_SetDvarIfUninitialized( level.commonKeys.enabled, 1 );
|
||||||
_SetDvarIfUninitialized( "sv_iw4madmin_integration_debug", 0 );
|
_SetDvarIfUninitialized( "sv_iw4madmin_integration_debug", 0 );
|
||||||
|
_SetDvarIfUninitialized( "GroupSeparatorChar", "" );
|
||||||
|
_SetDvarIfUninitialized( "RecordSeparatorChar", "" );
|
||||||
|
_SetDvarIfUninitialized( "UnitSeparatorChar", "" );
|
||||||
|
|
||||||
if ( GetDvarInt( level.commonKeys.enabled ) != 1 )
|
if ( GetDvarInt( level.commonKeys.enabled ) != 1 )
|
||||||
{
|
{
|
||||||
@ -77,35 +80,44 @@ Setup()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// start long running tasks
|
// start long running tasks
|
||||||
thread MonitorClientEvents();
|
thread MonitorEvents();
|
||||||
thread MonitorBus();
|
thread MonitorBus();
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////////////////////
|
MonitorEvents()
|
||||||
// Client Methods
|
|
||||||
//////////////////////////////////
|
|
||||||
|
|
||||||
MonitorClientEvents()
|
|
||||||
{
|
{
|
||||||
level endon( level.eventTypes.gameEnd );
|
level endon( level.eventTypes.gameEnd );
|
||||||
|
|
||||||
for ( ;; )
|
for ( ;; )
|
||||||
{
|
{
|
||||||
level waittill( level.eventTypes.localClientEvent, client );
|
level waittill( level.eventTypes.eventAvailable, event );
|
||||||
|
|
||||||
LogDebug( "Processing Event " + client.event.type + "-" + client.event.subtype );
|
LogDebug( "Processing Event " + event.type + "-" + event.subtype );
|
||||||
|
|
||||||
eventHandler = level.eventCallbacks[client.event.type];
|
eventHandler = level.eventCallbacks[event.type];
|
||||||
|
|
||||||
if ( IsDefined( eventHandler ) )
|
if ( IsDefined( eventHandler ) )
|
||||||
{
|
{
|
||||||
client [[eventHandler]]( client.event );
|
if ( IsDefined( event.entity ) )
|
||||||
LogDebug( "notify client for " + client.event.type );
|
{
|
||||||
client notify( level.eventTypes.localClientEvent, client.event );
|
event.entity [[eventHandler]]( event );
|
||||||
client notify( client.event.type, client.event );
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
[[eventHandler]]( event );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( IsDefined( event.entity ) )
|
||||||
|
{
|
||||||
|
LogDebug( "Notify client for " + event.type );
|
||||||
|
event.entity notify( event.type, event );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
LogDebug( "Notify level for " + event.type );
|
||||||
|
level notify( event.type, event );
|
||||||
}
|
}
|
||||||
|
|
||||||
client.eventData = [];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -163,7 +175,7 @@ _Log( LogLevel, message )
|
|||||||
{
|
{
|
||||||
for( i = 0; i < level.logger._logger.size; i++ )
|
for( i = 0; i < level.logger._logger.size; i++ )
|
||||||
{
|
{
|
||||||
[[level.logger._logger[i]]]( LogLevel, message );
|
[[level.logger._logger[i]]]( LogLevel, GetSubStr( message, 0, 1000 ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -246,18 +258,20 @@ DecrementClientMeta( metaKey, decrementValue, clientId )
|
|||||||
|
|
||||||
SetClientMeta( metaKey, metaValue, clientId, direction )
|
SetClientMeta( metaKey, metaValue, clientId, direction )
|
||||||
{
|
{
|
||||||
data = "key=" + metaKey + "|value=" + metaValue;
|
data = [];
|
||||||
|
data["key"] = metaKey;
|
||||||
|
data["value"] = metaValue;
|
||||||
clientNumber = -1;
|
clientNumber = -1;
|
||||||
|
|
||||||
if ( IsDefined ( clientId ) )
|
if ( IsDefined ( clientId ) )
|
||||||
{
|
{
|
||||||
data = data + "|clientId=" + clientId;
|
data["clientId"] = clientId;
|
||||||
clientNumber = -1;
|
clientNumber = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( IsDefined( direction ) )
|
if ( IsDefined( direction ) )
|
||||||
{
|
{
|
||||||
data = data + "|direction=" + direction;
|
data["direction"] = direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( IsPlayer( self ) )
|
if ( IsPlayer( self ) )
|
||||||
@ -292,9 +306,12 @@ BuildEventRequest( responseExpected, eventType, eventSubtype, entOrId, data )
|
|||||||
{
|
{
|
||||||
request = "1";
|
request = "1";
|
||||||
}
|
}
|
||||||
|
|
||||||
request = request + ";" + eventType + ";" + eventSubtype + ";" + entOrId + ";" + data;
|
data = BuildDataString( data );
|
||||||
return request;
|
groupSeparator = GetSubStr( GetDvar( "GroupSeparatorChar" ), 0, 1 );
|
||||||
|
request = request + groupSeparator + eventType + groupSeparator + eventSubtype + groupSeparator + entOrId + groupSeparator + data;
|
||||||
|
|
||||||
|
eturn request;
|
||||||
}
|
}
|
||||||
|
|
||||||
MonitorBus()
|
MonitorBus()
|
||||||
@ -319,7 +336,8 @@ MonitorBus()
|
|||||||
}
|
}
|
||||||
LogDebug( "-> " + eventString );
|
LogDebug( "-> " + eventString );
|
||||||
|
|
||||||
NotifyClientEvent( strtok( eventString, ";" ) );
|
groupSeparator = GetSubStr( GetDvar( "GroupSeparatorChar" ), 0, 1 );
|
||||||
|
NotifyEvent( strtok( eventString, groupSeparator ) );
|
||||||
|
|
||||||
SetDvar( level.eventBus.outVar, "" );
|
SetDvar( level.eventBus.outVar, "" );
|
||||||
}
|
}
|
||||||
@ -361,7 +379,7 @@ QueueEvent( request, eventType, notifyEntity )
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
LogDebug("<- " + request );
|
LogDebug( "<- " + request );
|
||||||
|
|
||||||
SetDvar( level.eventBus.inVar, request );
|
SetDvar( level.eventBus.inVar, request );
|
||||||
}
|
}
|
||||||
@ -374,13 +392,13 @@ ParseDataString( data )
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
dataParts = strtok( data, "|" );
|
dataParts = strtok( data, GetSubStr( GetDvar( "RecordSeparatorChar" ), 0, 1 ) );
|
||||||
dict = [];
|
dict = [];
|
||||||
|
|
||||||
for ( i = 0; i < dataParts.size; i++ )
|
for ( i = 0; i < dataParts.size; i++ )
|
||||||
{
|
{
|
||||||
part = dataParts[i];
|
part = dataParts[i];
|
||||||
splitPart = strtok( part, "=" );
|
splitPart = strtok( part, GetSubStr( GetDvar( "UnitSeparatorChar" ), 0, 1 ) );
|
||||||
key = splitPart[0];
|
key = splitPart[0];
|
||||||
value = splitPart[1];
|
value = splitPart[1];
|
||||||
dict[key] = value;
|
dict[key] = value;
|
||||||
@ -390,6 +408,26 @@ ParseDataString( data )
|
|||||||
return dict;
|
return dict;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BuildDataString( data )
|
||||||
|
{
|
||||||
|
if ( IsString( data ) )
|
||||||
|
{
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
dataString = "";
|
||||||
|
keys = GetArrayKeys( data );
|
||||||
|
unitSeparator = GetSubStr( GetDvar( "UnitSeparatorChar" ), 0, 1 );
|
||||||
|
recordSeparator = GetSubStr( GetDvar( "RecordSeparatorChar" ), 0, 1 );
|
||||||
|
|
||||||
|
for ( i = 0; i < keys.size; i++ )
|
||||||
|
{
|
||||||
|
dataString = dataString + keys[i] + unitSeparator + data[keys[i]] + recordSeparator;
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataString;
|
||||||
|
}
|
||||||
|
|
||||||
NotifyClientEventTimeout( eventType )
|
NotifyClientEventTimeout( eventType )
|
||||||
{
|
{
|
||||||
// todo: make this actual eventing
|
// todo: make this actual eventing
|
||||||
@ -399,7 +437,7 @@ NotifyClientEventTimeout( eventType )
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NotifyClientEvent( eventInfo )
|
NotifyEvent( eventInfo )
|
||||||
{
|
{
|
||||||
origin = [[level.overrideMethods[level.commonFunctions.getPlayerFromClientNum]]]( int( eventInfo[3] ) );
|
origin = [[level.overrideMethods[level.commonFunctions.getPlayerFromClientNum]]]( int( eventInfo[3] ) );
|
||||||
target = [[level.overrideMethods[level.commonFunctions.getPlayerFromClientNum]]]( int( eventInfo[4] ) );
|
target = [[level.overrideMethods[level.commonFunctions.getPlayerFromClientNum]]]( int( eventInfo[4] ) );
|
||||||
@ -407,15 +445,10 @@ NotifyClientEvent( eventInfo )
|
|||||||
event = spawnstruct();
|
event = spawnstruct();
|
||||||
event.type = eventInfo[1];
|
event.type = eventInfo[1];
|
||||||
event.subtype = eventInfo[2];
|
event.subtype = eventInfo[2];
|
||||||
event.data = eventInfo[5];
|
event.data = ParseDataString( eventInfo[5] );
|
||||||
event.origin = origin;
|
event.origin = origin;
|
||||||
event.target = target;
|
event.target = target;
|
||||||
|
|
||||||
if ( IsDefined( event.data ) )
|
|
||||||
{
|
|
||||||
LogDebug( "NotifyClientEvent->" + event.data );
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( int( eventInfo[3] ) != -1 && !IsDefined( origin ) )
|
if ( int( eventInfo[3] ) != -1 && !IsDefined( origin ) )
|
||||||
{
|
{
|
||||||
LogDebug( "origin is null but the slot id is " + int( eventInfo[3] ) );
|
LogDebug( "origin is null but the slot id is " + int( eventInfo[3] ) );
|
||||||
@ -425,23 +458,15 @@ NotifyClientEvent( eventInfo )
|
|||||||
LogDebug( "target is null but the slot id is " + int( eventInfo[4] ) );
|
LogDebug( "target is null but the slot id is " + int( eventInfo[4] ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( IsDefined( target ) )
|
client = event.origin;
|
||||||
|
|
||||||
|
if ( !IsDefined( client ) )
|
||||||
{
|
{
|
||||||
client = event.target;
|
client = event.target;
|
||||||
}
|
}
|
||||||
else if ( IsDefined( origin ) )
|
|
||||||
{
|
event.entity = client;
|
||||||
client = event.origin;
|
level notify( level.eventTypes.eventAvailable, event );
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LogDebug( "Neither origin or target are set but we are a Client Event, aborting" );
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
client.event = event;
|
|
||||||
level notify( level.eventTypes.localClientEvent, client );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AddClientCommand( commandName, shouldRunAsTarget, callback, shouldOverwrite )
|
AddClientCommand( commandName, shouldRunAsTarget, callback, shouldOverwrite )
|
||||||
@ -461,7 +486,6 @@ AddClientCommand( commandName, shouldRunAsTarget, callback, shouldOverwrite )
|
|||||||
|
|
||||||
OnClientDataReceived( event )
|
OnClientDataReceived( event )
|
||||||
{
|
{
|
||||||
event.data = ParseDataString( event.data );
|
|
||||||
clientData = self.pers[level.clientDataKey];
|
clientData = self.pers[level.clientDataKey];
|
||||||
|
|
||||||
if ( event.subtype == "Fail" )
|
if ( event.subtype == "Fail" )
|
||||||
@ -497,7 +521,7 @@ OnClientDataReceived( event )
|
|||||||
|
|
||||||
OnExecuteCommand( event )
|
OnExecuteCommand( event )
|
||||||
{
|
{
|
||||||
data = ParseDataString( event.data );
|
data = event.data;
|
||||||
response = "";
|
response = "";
|
||||||
|
|
||||||
command = level.clientCommandCallbacks[event.subtype];
|
command = level.clientCommandCallbacks[event.subtype];
|
||||||
@ -527,8 +551,7 @@ OnExecuteCommand( event )
|
|||||||
|
|
||||||
OnSetClientDataCompleted( event )
|
OnSetClientDataCompleted( event )
|
||||||
{
|
{
|
||||||
data = ParseDataString( event.data );
|
LogDebug( "Set Client Data -> subtype = " + CoerceUndefined( event.subType ) + ", status = " + CoerceUndefined( event.data["status"] ) );
|
||||||
LogDebug( "Set Client Data -> subtype = " + CoerceUndefined( event.subType ) + ", status = " + CoerceUndefined( data["status"] ) );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
CoerceUndefined( object )
|
CoerceUndefined( object )
|
||||||
|
@ -85,7 +85,7 @@ WaitForClientEvents()
|
|||||||
|
|
||||||
for ( ;; )
|
for ( ;; )
|
||||||
{
|
{
|
||||||
self waittill( level.eventTypes.localClientEvent, event );
|
self waittill( level.eventTypes.eventAvailable, event );
|
||||||
|
|
||||||
scripts\_integration_base::LogDebug( "Received client event " + event.type );
|
scripts\_integration_base::LogDebug( "Received client event " + event.type );
|
||||||
|
|
||||||
|
@ -45,8 +45,14 @@ Setup()
|
|||||||
level.eventTypes.joinSpec = "joined_spectators";
|
level.eventTypes.joinSpec = "joined_spectators";
|
||||||
level.eventTypes.spawned = "spawned_player";
|
level.eventTypes.spawned = "spawned_player";
|
||||||
level.eventTypes.gameEnd = "game_ended";
|
level.eventTypes.gameEnd = "game_ended";
|
||||||
|
|
||||||
|
level.eventTypes.urlRequested = "UrlRequested";
|
||||||
|
level.eventTypes.urlRequestCompleted = "UrlRequestCompleted";
|
||||||
|
|
||||||
|
level.eventCallbacks[level.eventTypes.urlRequestCompleted] = ::OnUrlRequestCompletedCallback;
|
||||||
|
|
||||||
level.iw4madminIntegrationDefaultPerformance = 200;
|
level.iw4madminIntegrationDefaultPerformance = 200;
|
||||||
|
level.notifyEntities = [];
|
||||||
|
|
||||||
level notify( level.notifyTypes.sharedFunctionsInitialized );
|
level notify( level.notifyTypes.sharedFunctionsInitialized );
|
||||||
level waittill( level.notifyTypes.gameFunctionsInitialized );
|
level waittill( level.notifyTypes.gameFunctionsInitialized );
|
||||||
@ -185,6 +191,135 @@ SaveTrackingMetrics()
|
|||||||
scripts\_integration_base::IncrementClientMeta( "TotalShotsFired", change, self.persistentClientId );
|
scripts\_integration_base::IncrementClientMeta( "TotalShotsFired", change, self.persistentClientId );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #region web requests
|
||||||
|
|
||||||
|
RequestUrlObject( request )
|
||||||
|
{
|
||||||
|
return RequestUrl( request.url, request.method, request.body, request.headers, request );
|
||||||
|
}
|
||||||
|
|
||||||
|
RequestUrl( url, method, body, headers, webNotify )
|
||||||
|
{
|
||||||
|
if ( !IsDefined( webNotify ) )
|
||||||
|
{
|
||||||
|
webNotify = SpawnStruct();
|
||||||
|
webNotify.url = url;
|
||||||
|
webNotify.method = method;
|
||||||
|
webNotify.body = body;
|
||||||
|
webNotify.headers = headers;
|
||||||
|
}
|
||||||
|
|
||||||
|
webNotify.index = GetNextNotifyEntity();
|
||||||
|
|
||||||
|
scripts\_integration_base::LogDebug( "next notify index is " + webNotify.index );
|
||||||
|
level.notifyEntities[webNotify.index] = webNotify;
|
||||||
|
|
||||||
|
data = [];
|
||||||
|
data["url"] = webNotify.url;
|
||||||
|
data["entity"] = webNotify.index;
|
||||||
|
|
||||||
|
if ( IsDefined( method ) )
|
||||||
|
{
|
||||||
|
data["method"] = method;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( IsDefined( body ) )
|
||||||
|
{
|
||||||
|
data["body"] = body;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( IsDefined( headers ) )
|
||||||
|
{
|
||||||
|
headerString = "";
|
||||||
|
|
||||||
|
keys = GetArrayKeys( headers );
|
||||||
|
for ( i = 0; i < keys.size; i++ )
|
||||||
|
{
|
||||||
|
headerString = headerString + keys[i] + ":" + headers[keys[i]] + ",";
|
||||||
|
}
|
||||||
|
|
||||||
|
data["headers"] = headerString;
|
||||||
|
}
|
||||||
|
|
||||||
|
webNotifyEvent = scripts\_integration_base::BuildEventRequest( true, level.eventTypes.urlRequested, "", webNotify.index, data );
|
||||||
|
thread scripts\_integration_base::QueueEvent( webNotifyEvent, level.eventTypes.urlRequested, webNotify );
|
||||||
|
webNotify thread WaitForUrlRequestComplete();
|
||||||
|
|
||||||
|
return webNotify;
|
||||||
|
}
|
||||||
|
|
||||||
|
WaitForUrlRequestComplete()
|
||||||
|
{
|
||||||
|
level endon( level.eventTypes.gameEnd );
|
||||||
|
|
||||||
|
timeoutResult = self [[level.overrideMethods[level.commonFunctions.waitTillAnyTimeout]]]( 30, level.eventTypes.urlRequestCompleted );
|
||||||
|
|
||||||
|
if ( timeoutResult == level.eventBus.timeoutKey )
|
||||||
|
{
|
||||||
|
scripts\_integration_base::LogWarning( "Request to " + self.url + " timed out" );
|
||||||
|
self notify ( level.eventTypes.urlRequestCompleted, "error" );
|
||||||
|
}
|
||||||
|
|
||||||
|
scripts\_integration_base::LogDebug( "Request to " + self.url + " completed" );
|
||||||
|
|
||||||
|
//self delete();
|
||||||
|
level.notifyEntities[self.index] = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
OnUrlRequestCompletedCallback( event )
|
||||||
|
{
|
||||||
|
if ( !IsDefined( event ) || !IsDefined( event.data ) )
|
||||||
|
{
|
||||||
|
scripts\_integration_base::LogWarning( "Incomplete data for url request callback. [1]" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
notifyEnt = event.data["entity"];
|
||||||
|
response = event.data["response"];
|
||||||
|
|
||||||
|
if ( !IsDefined( notifyEnt ) || !IsDefined( response ) )
|
||||||
|
{
|
||||||
|
scripts\_integration_base::LogWarning( "Incomplete data for url request callback. [2] " + scripts\_integration_base::CoerceUndefined( notifyEnt ) + " , " + scripts\_integration_base::CoerceUndefined( response ) );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
webNotify = level.notifyEntities[int( notifyEnt )];
|
||||||
|
|
||||||
|
if ( !IsDefined( webNotify.response ) )
|
||||||
|
{
|
||||||
|
webNotify.response = response;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
webNotify.response = webNotify.response + response;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( int( event.data["remaining"] ) != 0 )
|
||||||
|
{
|
||||||
|
scripts\_integration_base::LogDebug( "Additional data available for url request " + notifyEnt + " (" + event.data["remaining"] + " chunks remaining)" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
scripts\_integration_base::LogDebug( "Notifying " + notifyEnt + " that url request completed" );
|
||||||
|
webNotify notify( level.eventTypes.urlRequestCompleted, webNotify.response );
|
||||||
|
}
|
||||||
|
|
||||||
|
GetNextNotifyEntity()
|
||||||
|
{
|
||||||
|
max = level.notifyEntities.size + 1;
|
||||||
|
|
||||||
|
for ( i = 0; i < max; i++ )
|
||||||
|
{
|
||||||
|
if ( !IsDefined( level.notifyEntities[i] ) )
|
||||||
|
{
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// #end region
|
||||||
|
|
||||||
// #region team balance
|
// #region team balance
|
||||||
|
|
||||||
OnPlayerDisconnect()
|
OnPlayerDisconnect()
|
||||||
|
@ -72,6 +72,9 @@ EndProject
|
|||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mute", "Plugins\Mute\Mute.csproj", "{259824F3-D860-4233-91D6-FF73D4DD8B18}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mute", "Plugins\Mute\Mute.csproj", "{259824F3-D860-4233-91D6-FF73D4DD8B18}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GameFiles", "GameFiles", "{6CBF412C-EFEE-45F7-80FD-AC402C22CDB9}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GameFiles", "GameFiles", "{6CBF412C-EFEE-45F7-80FD-AC402C22CDB9}"
|
||||||
|
ProjectSection(SolutionItems) = preProject
|
||||||
|
GameFiles\deploy.bat = GameFiles\deploy.bat
|
||||||
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GameInterface", "GameInterface", "{5C2BE2A8-EA1D-424F-88E1-7FC33EEC2E55}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GameInterface", "GameInterface", "{5C2BE2A8-EA1D-424F-88E1-7FC33EEC2E55}"
|
||||||
ProjectSection(SolutionItems) = preProject
|
ProjectSection(SolutionItems) = preProject
|
||||||
@ -80,6 +83,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "GameInterface", "GameInterf
|
|||||||
GameFiles\GameInterface\_integration_iw5.gsc = GameFiles\GameInterface\_integration_iw5.gsc
|
GameFiles\GameInterface\_integration_iw5.gsc = GameFiles\GameInterface\_integration_iw5.gsc
|
||||||
GameFiles\GameInterface\_integration_shared.gsc = GameFiles\GameInterface\_integration_shared.gsc
|
GameFiles\GameInterface\_integration_shared.gsc = GameFiles\GameInterface\_integration_shared.gsc
|
||||||
GameFiles\GameInterface\_integration_t5.gsc = GameFiles\GameInterface\_integration_t5.gsc
|
GameFiles\GameInterface\_integration_t5.gsc = GameFiles\GameInterface\_integration_t5.gsc
|
||||||
|
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
|
||||||
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}"
|
||||||
|
@ -3,33 +3,38 @@ const inDvar = 'sv_iw4madmin_in';
|
|||||||
const outDvar = 'sv_iw4madmin_out';
|
const outDvar = 'sv_iw4madmin_out';
|
||||||
const integrationEnabledDvar = 'sv_iw4madmin_integration_enabled';
|
const integrationEnabledDvar = 'sv_iw4madmin_integration_enabled';
|
||||||
const pollingRate = 300;
|
const pollingRate = 300;
|
||||||
|
const groupSeparatorChar = '\x1d';
|
||||||
|
const recordSeparatorChar = '\x1e';
|
||||||
|
const unitSeparatorChar = '\x1f';
|
||||||
|
|
||||||
const init = (registerNotify, serviceResolver, config) => {
|
const init = (registerNotify, serviceResolver, config, scriptHelper) => {
|
||||||
registerNotify('IManagementEventSubscriptions.ClientStateInitialized', (clientEvent, _) => plugin.onClientEnteredMatch(clientEvent));
|
registerNotify('IManagementEventSubscriptions.ClientStateInitialized', (clientEvent, _) => plugin.onClientEnteredMatch(clientEvent));
|
||||||
registerNotify('IGameServerEventSubscriptions.ServerValueReceived', (serverValueEvent, _) => plugin.onServerValueReceived(serverValueEvent));
|
registerNotify('IGameServerEventSubscriptions.ServerValueReceived', (serverValueEvent, _) => plugin.onServerValueReceived(serverValueEvent));
|
||||||
registerNotify('IGameServerEventSubscriptions.ServerValueSetCompleted', (serverValueEvent, _) => plugin.onServerValueSetCompleted(serverValueEvent));
|
registerNotify('IGameServerEventSubscriptions.ServerValueSetCompleted', (serverValueEvent, _) => plugin.onServerValueSetCompleted(serverValueEvent));
|
||||||
registerNotify('IGameServerEventSubscriptions.MonitoringStarted', (monitorStartEvent, _) => plugin.onServerMonitoringStart(monitorStartEvent));
|
registerNotify('IGameServerEventSubscriptions.MonitoringStarted', (monitorStartEvent, _) => plugin.onServerMonitoringStart(monitorStartEvent));
|
||||||
registerNotify('IManagementEventSubscriptions.ClientPenaltyAdministered', (penaltyEvent, _) => plugin.onPenalty(penaltyEvent));
|
registerNotify('IManagementEventSubscriptions.ClientPenaltyAdministered', (penaltyEvent, _) => plugin.onPenalty(penaltyEvent));
|
||||||
|
|
||||||
plugin.onLoad(serviceResolver, config);
|
plugin.onLoad(serviceResolver, config, scriptHelper);
|
||||||
return plugin;
|
return plugin;
|
||||||
};
|
};
|
||||||
|
|
||||||
const plugin = {
|
const plugin = {
|
||||||
author: 'RaidMax',
|
author: 'RaidMax',
|
||||||
version: '2.0',
|
version: '2.1',
|
||||||
name: 'Game Interface',
|
name: 'Game Interface',
|
||||||
serviceResolver: null,
|
serviceResolver: null,
|
||||||
eventManager: null,
|
eventManager: null,
|
||||||
logger: null,
|
logger: null,
|
||||||
commands: null,
|
commands: null,
|
||||||
|
scriptHelper: null,
|
||||||
|
|
||||||
onLoad: function (serviceResolver, config) {
|
onLoad: function (serviceResolver, config, scriptHelper) {
|
||||||
this.serviceResolver = serviceResolver;
|
this.serviceResolver = serviceResolver;
|
||||||
this.eventManager = serviceResolver.resolveService('IManager');
|
this.eventManager = serviceResolver.resolveService('IManager');
|
||||||
this.logger = serviceResolver.resolveService('ILogger', ['ScriptPluginV2']);
|
this.logger = serviceResolver.resolveService('ILogger', ['ScriptPluginV2']);
|
||||||
this.commands = commands;
|
this.commands = commands;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
|
this.scriptHelper = scriptHelper;
|
||||||
},
|
},
|
||||||
|
|
||||||
onClientEnteredMatch: function (clientEvent) {
|
onClientEnteredMatch: function (clientEvent) {
|
||||||
@ -96,6 +101,10 @@ const plugin = {
|
|||||||
// loop restarts
|
// loop restarts
|
||||||
this.requestGetDvar(inDvar, serverValueEvent.server);
|
this.requestGetDvar(inDvar, serverValueEvent.server);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
onServerMonitoringStart: function (monitorStartEvent) {
|
||||||
|
this.initializeServer(monitorStartEvent.server);
|
||||||
|
},
|
||||||
|
|
||||||
initializeServer: function (server) {
|
initializeServer: function (server) {
|
||||||
servers[server.id] = {
|
servers[server.id] = {
|
||||||
@ -287,17 +296,48 @@ const plugin = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event.eventType === 'UrlRequested') {
|
||||||
|
const urlRequest = this.parseUrlRequest(event);
|
||||||
|
|
||||||
|
this.logger.logDebug('Making gamescript web request {@Request}', urlRequest);
|
||||||
|
|
||||||
|
this.scriptHelper.requestUrl(urlRequest, response => {
|
||||||
|
this.logger.logDebug('Got response for gamescript web request - {Response}', response);
|
||||||
|
|
||||||
|
const max = 10;
|
||||||
|
this.logger.logDebug(`response length ${response.length}`);
|
||||||
|
let chunks = chunkString(response.replace(/"/gm, '\\"').replace(/[\n|\t]/gm, ''), 800);
|
||||||
|
if (chunks.length > max)
|
||||||
|
{
|
||||||
|
this.logger.logWarning(`Response chunks greater than max (${max}). Data truncated!`);
|
||||||
|
chunks = chunks.slice(0, max);
|
||||||
|
}
|
||||||
|
this.logger.logDebug(`chunk size ${chunks.length}`);
|
||||||
|
|
||||||
|
for (let i = 0; i < chunks.length; i++) {
|
||||||
|
this.sendEventMessage(server, false, 'UrlRequestCompleted', null, null,
|
||||||
|
null, { entity: event.data.entity, remaining: chunks.length - (i + 1), response: chunks[i]});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
tokenSource.dispose();
|
tokenSource.dispose();
|
||||||
return messageQueued;
|
return messageQueued;
|
||||||
},
|
},
|
||||||
|
|
||||||
sendEventMessage: function (server, responseExpected, event, subtype, origin, target, data) {
|
sendEventMessage: function (server, responseExpected, event, subtype, origin, target, data) {
|
||||||
let targetClientNumber = -1;
|
let targetClientNumber = -1;
|
||||||
|
let originClientNumber = -1;
|
||||||
|
|
||||||
if (target != null) {
|
if (target != null) {
|
||||||
targetClientNumber = target.ClientNumber;
|
targetClientNumber = target.clientNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
const output = `${responseExpected ? '1' : '0'};${event};${subtype};${origin.ClientNumber};${targetClientNumber};${buildDataString(data)}`;
|
if (origin != null) {
|
||||||
|
originClientNumber = origin.clientNumber
|
||||||
|
}
|
||||||
|
|
||||||
|
const output = `${responseExpected ? '1' : '0'}${groupSeparatorChar}${event}${groupSeparatorChar}${subtype}${groupSeparatorChar}${originClientNumber}${groupSeparatorChar}${targetClientNumber}${groupSeparatorChar}${buildDataString(data)}`;
|
||||||
this.logger.logDebug('Queuing output for server {output}', output);
|
this.logger.logDebug('Queuing output for server {output}', output);
|
||||||
|
|
||||||
servers[server.id].commandQueue.push(output);
|
servers[server.id].commandQueue.push(output);
|
||||||
@ -365,8 +405,35 @@ const plugin = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onServerMonitoringStart: function (monitorStartEvent) {
|
parseUrlRequest: function(event) {
|
||||||
this.initializeServer(monitorStartEvent.server);
|
const url = event.data?.url;
|
||||||
|
|
||||||
|
if (url === undefined) {
|
||||||
|
this.logger.logWarning('No url provided for gamescript web request - {Event}', event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = event.data?.body;
|
||||||
|
const method = event.data?.method || 'GET';
|
||||||
|
const contentType = event.data?.contentType || 'text/plain';
|
||||||
|
const headers = event.data?.headers;
|
||||||
|
|
||||||
|
const dictionary = System.Collections.Generic.Dictionary(System.String, System.String);
|
||||||
|
const headerDict = new dictionary();
|
||||||
|
|
||||||
|
if (headers) {
|
||||||
|
const eachHeader = headers.split(',');
|
||||||
|
|
||||||
|
for (let eachKeyValue of eachHeader) {
|
||||||
|
const keyValueSplit = eachKeyValue.split(':');
|
||||||
|
if (keyValueSplit.length === 2) {
|
||||||
|
headerDict.add(keyValueSplit[0], keyValueSplit[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const script = importNamespace('IW4MAdmin.Application.Plugin.Script');
|
||||||
|
return new script.ScriptPluginWebRequest(url, body, method, contentType, headerDict);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -634,7 +701,7 @@ const parseEvent = (input) => {
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const eventInfo = input.split(';');
|
const eventInfo = input.split(groupSeparatorChar);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
eventType: eventInfo[1],
|
eventType: eventInfo[1],
|
||||||
@ -652,7 +719,7 @@ const buildDataString = data => {
|
|||||||
let formattedData = '';
|
let formattedData = '';
|
||||||
|
|
||||||
for (let [key, value] of Object.entries(data)) {
|
for (let [key, value] of Object.entries(data)) {
|
||||||
formattedData += `${key}=${value}|`;
|
formattedData += `${key}${unitSeparatorChar}${value}${recordSeparatorChar}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
return formattedData.slice(0, -1);
|
return formattedData.slice(0, -1);
|
||||||
@ -664,11 +731,11 @@ const parseDataString = data => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const dict = {};
|
const dict = {};
|
||||||
const split = data.split('|');
|
const split = data.split(recordSeparatorChar);
|
||||||
|
|
||||||
for (let i = 0; i < split.length; i++) {
|
for (let i = 0; i < split.length; i++) {
|
||||||
const segment = split[i];
|
const segment = split[i];
|
||||||
const keyValue = segment.split('=');
|
const keyValue = segment.split(unitSeparatorChar);
|
||||||
if (keyValue.length !== 2) {
|
if (keyValue.length !== 2) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -689,3 +756,12 @@ const validateEnabled = (server, origin) => {
|
|||||||
const isEmpty = (value) => {
|
const isEmpty = (value) => {
|
||||||
return value == null || false || value === '' || value === 'null';
|
return value == null || false || value === '' || value === 'null';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const chunkString = (str, chunkSize) => {
|
||||||
|
const result = [];
|
||||||
|
for (let i = 0; i < str.length; i += chunkSize) {
|
||||||
|
result.push(str.slice(i, i + chunkSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user