implement dynamic command registration through game interface
This commit is contained in:
parent
2fcbab9a37
commit
3f0bdfe3a9
@ -76,6 +76,11 @@ public class ScriptPluginHelper
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void RegisterDynamicCommand(JsValue command)
|
||||||
|
{
|
||||||
|
_scriptPlugin.RegisterDynamicCommand(command.ToObject());
|
||||||
|
}
|
||||||
|
|
||||||
private object RequestInternal(ScriptPluginWebRequest request)
|
private object RequestInternal(ScriptPluginWebRequest request)
|
||||||
{
|
{
|
||||||
var entered = false;
|
var entered = false;
|
||||||
|
@ -47,6 +47,7 @@ public class ScriptPluginV2 : IPluginV2
|
|||||||
private readonly List<string> _registeredCommandNames = new();
|
private readonly List<string> _registeredCommandNames = new();
|
||||||
private readonly List<string> _registeredInteractions = new();
|
private readonly List<string> _registeredInteractions = new();
|
||||||
private readonly Dictionary<MethodInfo, List<object>> _registeredEvents = new();
|
private readonly Dictionary<MethodInfo, List<object>> _registeredEvents = new();
|
||||||
|
private IManager _manager;
|
||||||
private bool _firstInitialization = true;
|
private bool _firstInitialization = true;
|
||||||
|
|
||||||
private record ScriptPluginDetails(string Name, string Author, string Version,
|
private record ScriptPluginDetails(string Name, string Author, string Version,
|
||||||
@ -112,8 +113,15 @@ public class ScriptPluginV2 : IPluginV2
|
|||||||
}, _logger, _fileName, _onProcessingScript);
|
}, _logger, _fileName, _onProcessingScript);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void RegisterDynamicCommand(object command)
|
||||||
|
{
|
||||||
|
var parsedCommand = ParseScriptCommandDetails(command);
|
||||||
|
RegisterCommand(_manager, parsedCommand.First());
|
||||||
|
}
|
||||||
|
|
||||||
private async Task OnLoad(IManager manager, CancellationToken token)
|
private async Task OnLoad(IManager manager, CancellationToken token)
|
||||||
{
|
{
|
||||||
|
_manager = manager;
|
||||||
var entered = false;
|
var entered = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -253,9 +261,13 @@ public class ScriptPluginV2 : IPluginV2
|
|||||||
command.Permission, command.TargetRequired,
|
command.Permission, command.TargetRequired,
|
||||||
command.Arguments, Execute, command.SupportedGames);
|
command.Arguments, Execute, command.SupportedGames);
|
||||||
|
|
||||||
|
manager.RemoveCommandByName(scriptCommand.Name);
|
||||||
manager.AddAdditionalCommand(scriptCommand);
|
manager.AddAdditionalCommand(scriptCommand);
|
||||||
|
if (!_registeredCommandNames.Contains(scriptCommand.Name))
|
||||||
|
{
|
||||||
_registeredCommandNames.Add(scriptCommand.Name);
|
_registeredCommandNames.Add(scriptCommand.Name);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void ResetEngineState()
|
private void ResetEngineState()
|
||||||
{
|
{
|
||||||
@ -480,6 +492,33 @@ public class ScriptPluginV2 : IPluginV2
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static ScriptPluginDetails AsScriptPluginInstance(dynamic source)
|
private static ScriptPluginDetails AsScriptPluginInstance(dynamic source)
|
||||||
|
{
|
||||||
|
var commandDetails = ParseScriptCommandDetails(source);
|
||||||
|
|
||||||
|
var interactionDetails = Array.Empty<ScriptPluginInteractionDetails>();
|
||||||
|
if (HasProperty(source, "interactions") && source.interactions is dynamic[])
|
||||||
|
{
|
||||||
|
interactionDetails = ((dynamic[])source.interactions).Select(interaction =>
|
||||||
|
{
|
||||||
|
var name = HasProperty(interaction, "name") && interaction.name is string
|
||||||
|
? (string)interaction.name
|
||||||
|
: string.Empty;
|
||||||
|
var action = HasProperty(interaction, "action") && interaction.action is Delegate
|
||||||
|
? (Delegate)interaction.action
|
||||||
|
: null;
|
||||||
|
|
||||||
|
return new ScriptPluginInteractionDetails(name, action);
|
||||||
|
}).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
var name = HasProperty(source, "name") && source.name is string ? (string)source.name : string.Empty;
|
||||||
|
var author = HasProperty(source, "author") && source.author is string ? (string)source.author : string.Empty;
|
||||||
|
var version = HasProperty(source, "version") && source.version is string ? (string)source.author : string.Empty;
|
||||||
|
|
||||||
|
return new ScriptPluginDetails(name, author, version, commandDetails, interactionDetails);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ScriptPluginCommandDetails[] ParseScriptCommandDetails(dynamic source)
|
||||||
{
|
{
|
||||||
var commandDetails = Array.Empty<ScriptPluginCommandDetails>();
|
var commandDetails = Array.Empty<ScriptPluginCommandDetails>();
|
||||||
if (HasProperty(source, "commands") && source.commands is dynamic[])
|
if (HasProperty(source, "commands") && source.commands is dynamic[])
|
||||||
@ -513,7 +552,7 @@ public class ScriptPluginV2 : IPluginV2
|
|||||||
(bool)command.targetRequired;
|
(bool)command.targetRequired;
|
||||||
var supportedGames =
|
var supportedGames =
|
||||||
HasProperty(command, "supportedGames") && command.supportedGames is IEnumerable<object>
|
HasProperty(command, "supportedGames") && command.supportedGames is IEnumerable<object>
|
||||||
? ((IEnumerable<object>)command.supportedGames).Where(game => game?.ToString() is not null)
|
? ((IEnumerable<object>)command.supportedGames).Where(game => !string.IsNullOrEmpty(game?.ToString()))
|
||||||
.Select(game =>
|
.Select(game =>
|
||||||
Enum.Parse<Reference.Game>(game.ToString()!))
|
Enum.Parse<Reference.Game>(game.ToString()!))
|
||||||
: Array.Empty<Reference.Game>();
|
: Array.Empty<Reference.Game>();
|
||||||
@ -523,31 +562,10 @@ public class ScriptPluginV2 : IPluginV2
|
|||||||
|
|
||||||
return new ScriptPluginCommandDetails(name, description, alias, permission, isTargetRequired,
|
return new ScriptPluginCommandDetails(name, description, alias, permission, isTargetRequired,
|
||||||
commandArgs, supportedGames, execute);
|
commandArgs, supportedGames, execute);
|
||||||
|
|
||||||
}).ToArray();
|
}).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
var interactionDetails = Array.Empty<ScriptPluginInteractionDetails>();
|
return commandDetails;
|
||||||
if (HasProperty(source, "interactions") && source.interactions is dynamic[])
|
|
||||||
{
|
|
||||||
interactionDetails = ((dynamic[])source.interactions).Select(interaction =>
|
|
||||||
{
|
|
||||||
var name = HasProperty(interaction, "name") && interaction.name is string
|
|
||||||
? (string)interaction.name
|
|
||||||
: string.Empty;
|
|
||||||
var action = HasProperty(interaction, "action") && interaction.action is Delegate
|
|
||||||
? (Delegate)interaction.action
|
|
||||||
: null;
|
|
||||||
|
|
||||||
return new ScriptPluginInteractionDetails(name, action);
|
|
||||||
}).ToArray();
|
|
||||||
}
|
|
||||||
|
|
||||||
var name = HasProperty(source, "name") && source.name is string ? (string)source.name : string.Empty;
|
|
||||||
var author = HasProperty(source, "author") && source.author is string ? (string)source.author : string.Empty;
|
|
||||||
var version = HasProperty(source, "version") && source.version is string ? (string)source.author : string.Empty;
|
|
||||||
|
|
||||||
return new ScriptPluginDetails(name, author, version, commandDetails, interactionDetails);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool HasProperty(dynamic source, string name)
|
private static bool HasProperty(dynamic source, string name)
|
||||||
|
@ -295,6 +295,11 @@ BuildEventRequest( responseExpected, eventType, eventSubtype, entOrId, data )
|
|||||||
eventSubtype = "None";
|
eventSubtype = "None";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ( !IsDefined( entOrId ) )
|
||||||
|
{
|
||||||
|
entOrId = "-1";
|
||||||
|
}
|
||||||
|
|
||||||
if ( IsPlayer( entOrId ) )
|
if ( IsPlayer( entOrId ) )
|
||||||
{
|
{
|
||||||
entOrId = entOrId getEntityNumber();
|
entOrId = entOrId getEntityNumber();
|
||||||
@ -311,7 +316,7 @@ BuildEventRequest( responseExpected, eventType, eventSubtype, entOrId, data )
|
|||||||
groupSeparator = GetSubStr( GetDvar( "GroupSeparatorChar" ), 0, 1 );
|
groupSeparator = GetSubStr( GetDvar( "GroupSeparatorChar" ), 0, 1 );
|
||||||
request = request + groupSeparator + eventType + groupSeparator + eventSubtype + groupSeparator + entOrId + groupSeparator + data;
|
request = request + groupSeparator + eventType + groupSeparator + eventSubtype + groupSeparator + entOrId + groupSeparator + data;
|
||||||
|
|
||||||
eturn request;
|
return request;
|
||||||
}
|
}
|
||||||
|
|
||||||
MonitorBus()
|
MonitorBus()
|
||||||
@ -534,10 +539,17 @@ OnExecuteCommand( event )
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ( IsDefined( command ) )
|
if ( IsDefined( command ) )
|
||||||
|
{
|
||||||
|
if ( IsDefined( executionContextEntity ) )
|
||||||
{
|
{
|
||||||
response = executionContextEntity [[command]]( event, data );
|
response = executionContextEntity [[command]]( event, data );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
[[command]]( event );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
LogDebug( "Unknown Client command->" + event.subtype );
|
LogDebug( "Unknown Client command->" + event.subtype );
|
||||||
}
|
}
|
||||||
|
@ -48,6 +48,7 @@ Setup()
|
|||||||
|
|
||||||
level.eventTypes.urlRequested = "UrlRequested";
|
level.eventTypes.urlRequested = "UrlRequested";
|
||||||
level.eventTypes.urlRequestCompleted = "UrlRequestCompleted";
|
level.eventTypes.urlRequestCompleted = "UrlRequestCompleted";
|
||||||
|
level.eventTypes.registerCommandRequested = "RegisterCommandRequested";
|
||||||
|
|
||||||
level.eventCallbacks[level.eventTypes.urlRequestCompleted] = ::OnUrlRequestCompletedCallback;
|
level.eventCallbacks[level.eventTypes.urlRequestCompleted] = ::OnUrlRequestCompletedCallback;
|
||||||
|
|
||||||
@ -191,6 +192,78 @@ SaveTrackingMetrics()
|
|||||||
scripts\_integration_base::IncrementClientMeta( "TotalShotsFired", change, self.persistentClientId );
|
scripts\_integration_base::IncrementClientMeta( "TotalShotsFired", change, self.persistentClientId );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #region register script command
|
||||||
|
|
||||||
|
RegisterScriptCommandObject( command )
|
||||||
|
{
|
||||||
|
RegisterScriptCommand( command.eventKey, command.name, command.alias, command.description, command.minPermission, command.supportedGames, command.requiresTarget, command.handler );
|
||||||
|
}
|
||||||
|
|
||||||
|
RegisterScriptCommand( eventKey, name, alias, description, minPermission, supportedGames, requiresTarget, handler )
|
||||||
|
{
|
||||||
|
if ( !IsDefined( eventKey ) )
|
||||||
|
{
|
||||||
|
scripts\_integration_base::LogError( "eventKey must be provided for script command" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = [];
|
||||||
|
|
||||||
|
data["eventKey"] = eventKey;
|
||||||
|
|
||||||
|
if ( IsDefined( name ) )
|
||||||
|
{
|
||||||
|
data["name"] = name;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
scripts\_integration_base::LogError( "name must be provided for script command" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( IsDefined( alias ) )
|
||||||
|
{
|
||||||
|
data["alias"] = alias;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( IsDefined( description ) )
|
||||||
|
{
|
||||||
|
data["description"] = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( IsDefined( minPermission ) )
|
||||||
|
{
|
||||||
|
data["minPermission"] = minPermission;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( IsDefined( supportedGames ) )
|
||||||
|
{
|
||||||
|
data["supportedGames"] = supportedGames;
|
||||||
|
}
|
||||||
|
|
||||||
|
data["requiresTarget"] = false;
|
||||||
|
|
||||||
|
if ( IsDefined( requiresTarget ) )
|
||||||
|
{
|
||||||
|
data["requiresTarget"] = requiresTarget;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( IsDefined( handler ) )
|
||||||
|
{
|
||||||
|
level.clientCommandCallbacks[eventKey + "Execute"] = handler;
|
||||||
|
level.clientCommandRusAsTarget[eventKey + "Execute"] = data["requiresTarget"];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
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 );
|
||||||
|
}
|
||||||
|
|
||||||
|
// #end region
|
||||||
|
|
||||||
// #region web requests
|
// #region web requests
|
||||||
|
|
||||||
RequestUrlObject( request )
|
RequestUrlObject( request )
|
||||||
@ -262,7 +335,6 @@ WaitForUrlRequestComplete()
|
|||||||
|
|
||||||
scripts\_integration_base::LogDebug( "Request to " + self.url + " completed" );
|
scripts\_integration_base::LogDebug( "Request to " + self.url + " completed" );
|
||||||
|
|
||||||
//self delete();
|
|
||||||
level.notifyEntities[self.index] = undefined;
|
level.notifyEntities[self.index] = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -315,6 +387,8 @@ GetNextNotifyEntity()
|
|||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -321,6 +321,10 @@ const plugin = {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (event.eventType === 'RegisterCommandRequested') {
|
||||||
|
this.registerDynamicCommand(event);
|
||||||
|
}
|
||||||
|
|
||||||
tokenSource.dispose();
|
tokenSource.dispose();
|
||||||
return messageQueued;
|
return messageQueued;
|
||||||
},
|
},
|
||||||
@ -434,6 +438,30 @@ const plugin = {
|
|||||||
|
|
||||||
const script = importNamespace('IW4MAdmin.Application.Plugin.Script');
|
const script = importNamespace('IW4MAdmin.Application.Plugin.Script');
|
||||||
return new script.ScriptPluginWebRequest(url, body, method, contentType, headerDict);
|
return new script.ScriptPluginWebRequest(url, body, method, contentType, headerDict);
|
||||||
|
},
|
||||||
|
|
||||||
|
registerDynamicCommand: function(event) {
|
||||||
|
const commandWrapper = {
|
||||||
|
commands: [{
|
||||||
|
name: event.data['name'] || 'DEFAULT',
|
||||||
|
description: event.data['description'] || 'DEFAULT',
|
||||||
|
alias: event.data['alias'] || 'DEFAULT',
|
||||||
|
permission: event.data['minPermission'] || 'DEFAULT',
|
||||||
|
targetRequired: (event.data['targetRequired'] || '0') === '1',
|
||||||
|
supportedGames: (event.data['supportedGames'] || '').split(','),
|
||||||
|
|
||||||
|
execute: (gameEvent) => {
|
||||||
|
if (!validateEnabled(gameEvent.owner, gameEvent.origin)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
sendScriptCommand(gameEvent.owner, `${event.data['eventKey']}Execute`, gameEvent.origin, gameEvent.target, {
|
||||||
|
args: gameEvent.data
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}
|
||||||
|
|
||||||
|
this.scriptHelper.registerDynamicCommand(commandWrapper);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user