refactor some game interface plugin approach

This commit is contained in:
RaidMax 2022-03-07 19:59:34 -06:00
parent acf66da4ca
commit 9f4d06c265
5 changed files with 384 additions and 279 deletions

View File

@ -276,6 +276,8 @@ namespace IW4MAdmin.Application.Misc
{ {
_logger.LogDebug("OnLoad executing for {Name}", Name); _logger.LogDebug("OnLoad executing for {Name}", Name);
_scriptEngine.SetValue("_manager", manager); _scriptEngine.SetValue("_manager", manager);
_scriptEngine.SetValue("getDvar", GetDvarAsync);
_scriptEngine.SetValue("setDvar", SetDvarAsync);
_scriptEngine.Evaluate("plugin.onLoadAsync(_manager)"); _scriptEngine.Evaluate("plugin.onLoadAsync(_manager)");
return Task.CompletedTask; return Task.CompletedTask;
@ -451,6 +453,85 @@ namespace IW4MAdmin.Application.Misc
return commandList; return commandList;
} }
private void GetDvarAsync(Server server, string dvarName, Delegate onCompleted)
{
Task.Run<Task>(async () =>
{
var tokenSource = new CancellationTokenSource();
tokenSource.CancelAfter(TimeSpan.FromSeconds(5));
string result = null;
var success = true;
try
{
result = (await server.GetDvarAsync<string>(dvarName, token: tokenSource.Token)).Value;
}
catch
{
success = false;
}
await _onProcessing.WaitAsync();
try
{
onCompleted.DynamicInvoke(JsValue.Undefined,
new[]
{
JsValue.FromObject(_scriptEngine, server),
JsValue.FromObject(_scriptEngine, dvarName),
JsValue.FromObject(_scriptEngine, result),
JsValue.FromObject(_scriptEngine, success),
});
}
finally
{
if (_onProcessing.CurrentCount == 0)
{
_onProcessing.Release();
}
}
});
}
private void SetDvarAsync(Server server, string dvarName, string dvarValue, Delegate onCompleted)
{
Task.Run<Task>(async () =>
{
var tokenSource = new CancellationTokenSource();
tokenSource.CancelAfter(TimeSpan.FromSeconds(5));
var success = true;
try
{
await server.SetDvarAsync(dvarName, dvarValue, tokenSource.Token);
}
catch
{
success = false;
}
await _onProcessing.WaitAsync();
try
{
onCompleted.DynamicInvoke(JsValue.Undefined,
new[]
{
JsValue.FromObject(_scriptEngine, server),
JsValue.FromObject(_scriptEngine, dvarName),
JsValue.FromObject(_scriptEngine, dvarValue),
JsValue.FromObject(_scriptEngine, success)
});
}
finally
{
if (_onProcessing.CurrentCount == 0)
{
_onProcessing.Release();
}
}
});
}
} }
public class PermissionLevelToStringConverter : IObjectConverter public class PermissionLevelToStringConverter : IObjectConverter

View File

@ -603,6 +603,7 @@ HideImpl()
if ( !IsDefined( self.savedHealth ) || self.health < 1000 ) if ( !IsDefined( self.savedHealth ) || self.health < 1000 )
{ {
self.savedHealth = self.health; self.savedHealth = self.health;
self.savedMaxHealth = self.maxhealth;
} }
self.maxhealth = 99999; self.maxhealth = 99999;
@ -621,12 +622,19 @@ UnhideImpl()
self IPrintLnBold( "You are not alive" ); self IPrintLnBold( "You are not alive" );
return; return;
} }
if ( IsDefined( self.isHidden ) && !self.isHidden )
{
self IPrintLnBold( "You are not hidden" );
return;
}
self SetClientDvar( "sv_cheats", 1 ); self SetClientDvar( "sv_cheats", 1 );
self SetClientDvar( "cg_thirdperson", 0 ); self SetClientDvar( "cg_thirdperson", 0 );
self SetClientDvar( "sv_cheats", 0 ); self SetClientDvar( "sv_cheats", 0 );
self.health = self.savedHealth; self.health = self.savedHealth;
self.maxhealth = self.savedMaxHealth;
self.isHidden = false; self.isHidden = false;
self Show(); self Show();

View File

@ -1,19 +1,14 @@
const eventTypes = { const servers = {};
1: 'start', // a server started being monitored
6: 'disconnect', // a client detected a leaving the game
9: 'preconnect', // client detected as joining via log or status
101: 'warn' // client was warned
};
const servers = {};
const inDvar = 'sv_iw4madmin_in'; const inDvar = 'sv_iw4madmin_in';
const outDvar = 'sv_iw4madmin_out'; const outDvar = 'sv_iw4madmin_out';
const pollRate = 750; const pollRate = 900;
const enableCheckTimeout = 10000;
let logger = {}; let logger = {};
const maxQueuedMessages = 25;
let plugin = { let plugin = {
author: 'RaidMax', author: 'RaidMax',
version: 1.0, version: 1.1,
name: 'Game Interface', name: 'Game Interface',
onEventAsync: (gameEvent, server) => { onEventAsync: (gameEvent, server) => {
@ -21,7 +16,7 @@ let plugin = {
return; return;
} }
const eventType = eventTypes[gameEvent.Type]; const eventType = String(gameEvent.TypeName).toLowerCase();
if (eventType === undefined) { if (eventType === undefined) {
return; return;
@ -86,10 +81,10 @@ let commands = [{
name: 'player', name: 'player',
required: true required: true
}, },
{ {
name: 'weapon name', name: 'weapon name',
required: true required: true
}], }],
supportedGames: ['IW4'], supportedGames: ['IW4'],
execute: (gameEvent) => { execute: (gameEvent) => {
if (!validateEnabled(gameEvent.Owner, gameEvent.Origin)) { if (!validateEnabled(gameEvent.Owner, gameEvent.Origin)) {
@ -98,198 +93,198 @@ let commands = [{
sendScriptCommand(gameEvent.Owner, 'GiveWeapon', gameEvent.Origin, gameEvent.Target, {weaponName: gameEvent.Data}); sendScriptCommand(gameEvent.Owner, 'GiveWeapon', gameEvent.Origin, gameEvent.Target, {weaponName: gameEvent.Data});
} }
}, },
{ {
name: 'takeweapons', name: 'takeweapons',
description: 'take all weapons from specified player', description: 'take all weapons from specified player',
alias: 'tw', alias: 'tw',
permission: 'SeniorAdmin', permission: 'SeniorAdmin',
targetRequired: true, targetRequired: true,
arguments: [{ arguments: [{
name: 'player', name: 'player',
required: true
}],
supportedGames: ['IW4'],
execute: (gameEvent) => {
if (!validateEnabled(gameEvent.Owner, gameEvent.Origin)) {
return;
}
sendScriptCommand(gameEvent.Owner, 'TakeWeapons', gameEvent.Origin, gameEvent.Target, undefined);
}
},
{
name: 'switchteam',
description: 'switches specified player to the opposite team',
alias: 'st',
permission: 'Administrator',
targetRequired: true,
arguments: [{
name: 'player',
required: true
}],
supportedGames: ['IW4'],
execute: (gameEvent) => {
if (!validateEnabled(gameEvent.Owner, gameEvent.Origin)) {
return;
}
sendScriptCommand(gameEvent.Owner, 'SwitchTeams', gameEvent.Origin, gameEvent.Target, undefined);
}
},
{
name: 'hide',
description: 'hide yourself ingame',
alias: 'hi',
permission: 'SeniorAdmin',
targetRequired: false,
arguments: [],
supportedGames: ['IW4'],
execute: (gameEvent) => {
if (!validateEnabled(gameEvent.Owner, gameEvent.Origin)) {
return;
}
sendScriptCommand(gameEvent.Owner, 'Hide', gameEvent.Origin, gameEvent.Origin, undefined);
}
},
{
name: 'unhide',
description: 'unhide yourself ingame',
alias: 'unh',
permission: 'SeniorAdmin',
targetRequired: false,
arguments: [],
supportedGames: ['IW4'],
execute: (gameEvent) => {
if (!validateEnabled(gameEvent.Owner, gameEvent.Origin)) {
return;
}
sendScriptCommand(gameEvent.Owner, 'Unhide', gameEvent.Origin, gameEvent.Origin, undefined);
}
},
{
name: 'alert',
description: 'alert a player',
alias: 'alr',
permission: 'SeniorAdmin',
targetRequired: true,
arguments: [{
name: 'player',
required: true
},
{
name: 'message',
required: true required: true
}], }],
supportedGames: ['IW4'], supportedGames: ['IW4'],
execute: (gameEvent) => { execute: (gameEvent) => {
if (!validateEnabled(gameEvent.Owner, gameEvent.Origin)) { if (!validateEnabled(gameEvent.Owner, gameEvent.Origin)) {
return; return;
}
sendScriptCommand(gameEvent.Owner, 'TakeWeapons', gameEvent.Origin, gameEvent.Target, undefined);
} }
sendScriptCommand(gameEvent.Owner, 'Alert', gameEvent.Origin, gameEvent.Target, {
alertType: 'Alert',
message: gameEvent.Data
});
}
},
{
name: 'gotoplayer',
description: 'teleport to a player',
alias: 'g2p',
permission: 'SeniorAdmin',
targetRequired: true,
arguments: [{
name: 'player',
required: true
}],
supportedGames: ['IW4'],
execute: (gameEvent) => {
if (!validateEnabled(gameEvent.Owner, gameEvent.Origin)) {
return;
}
sendScriptCommand(gameEvent.Owner, 'Goto', gameEvent.Origin, gameEvent.Target, undefined);
}
},
{
name: 'goto',
description: 'teleport to a position',
alias: 'g2',
permission: 'SeniorAdmin',
targetRequired: false,
arguments: [{
name: 'x',
required: true
}, },
{ {
name: 'y', name: 'switchteam',
required: true description: 'switches specified player to the opposite team',
alias: 'st',
permission: 'Administrator',
targetRequired: true,
arguments: [{
name: 'player',
required: true
}],
supportedGames: ['IW4'],
execute: (gameEvent) => {
if (!validateEnabled(gameEvent.Owner, gameEvent.Origin)) {
return;
}
sendScriptCommand(gameEvent.Owner, 'SwitchTeams', gameEvent.Origin, gameEvent.Target, undefined);
}
}, },
{ {
name: 'z', name: 'hide',
required: true description: 'hide yourself ingame',
}], alias: 'hi',
supportedGames: ['IW4'], permission: 'SeniorAdmin',
execute: (gameEvent) => { targetRequired: false,
if (!validateEnabled(gameEvent.Owner, gameEvent.Origin)) { arguments: [],
return; supportedGames: ['IW4'],
execute: (gameEvent) => {
if (!validateEnabled(gameEvent.Owner, gameEvent.Origin)) {
return;
}
sendScriptCommand(gameEvent.Owner, 'Hide', gameEvent.Origin, gameEvent.Origin, undefined);
} }
},
const args = String(gameEvent.Data).split(' '); {
sendScriptCommand(gameEvent.Owner, 'Goto', gameEvent.Origin, gameEvent.Target, { name: 'unhide',
x: args[0], description: 'unhide yourself ingame',
y: args[1], alias: 'unh',
z: args[2] permission: 'SeniorAdmin',
}); targetRequired: false,
} arguments: [],
}, supportedGames: ['IW4'],
{ execute: (gameEvent) => {
name: 'kill', if (!validateEnabled(gameEvent.Owner, gameEvent.Origin)) {
description: 'kill a player', return;
alias: 'kpl', }
permission: 'SeniorAdmin', sendScriptCommand(gameEvent.Owner, 'Unhide', gameEvent.Origin, gameEvent.Origin, undefined);
targetRequired: true,
arguments: [{
name: 'player',
required: true
}],
supportedGames: ['IW4'],
execute: (gameEvent) => {
if (!validateEnabled(gameEvent.Owner, gameEvent.Origin)) {
return;
} }
sendScriptCommand(gameEvent.Owner, 'Kill', gameEvent.Origin, gameEvent.Target, undefined); },
} {
}, name: 'alert',
{ description: 'alert a player',
name: 'nightmode', alias: 'alr',
description: 'sets server into nightmode', permission: 'SeniorAdmin',
alias: 'nitem', targetRequired: true,
permission: 'SeniorAdmin', arguments: [{
targetRequired: false, name: 'player',
arguments: [], required: true
supportedGames: ['IW4'], },
execute: (gameEvent) => { {
if (!validateEnabled(gameEvent.Owner, gameEvent.Origin)) { name: 'message',
return; required: true
}],
supportedGames: ['IW4'],
execute: (gameEvent) => {
if (!validateEnabled(gameEvent.Owner, gameEvent.Origin)) {
return;
}
sendScriptCommand(gameEvent.Owner, 'Alert', gameEvent.Origin, gameEvent.Target, {
alertType: 'Alert',
message: gameEvent.Data
});
} }
sendScriptCommand(gameEvent.Owner, 'NightMode', gameEvent.Origin, undefined, undefined); },
} {
}, name: 'gotoplayer',
{ description: 'teleport to a player',
name: 'setspectator', alias: 'g2p',
description: 'sets a player as spectator', permission: 'SeniorAdmin',
alias: 'spec', targetRequired: true,
permission: 'Administrator', arguments: [{
targetRequired: true, name: 'player',
arguments: [{ required: true
name: 'player', }],
required: true supportedGames: ['IW4'],
}], execute: (gameEvent) => {
supportedGames: ['IW4'], if (!validateEnabled(gameEvent.Owner, gameEvent.Origin)) {
execute: (gameEvent) => { return;
if (!validateEnabled(gameEvent.Owner, gameEvent.Origin)) { }
return; sendScriptCommand(gameEvent.Owner, 'Goto', gameEvent.Origin, gameEvent.Target, undefined);
} }
sendScriptCommand(gameEvent.Owner, 'SetSpectator', gameEvent.Origin, gameEvent.Target, undefined); },
} {
}]; name: 'goto',
description: 'teleport to a position',
alias: 'g2',
permission: 'SeniorAdmin',
targetRequired: false,
arguments: [{
name: 'x',
required: true
},
{
name: 'y',
required: true
},
{
name: 'z',
required: true
}],
supportedGames: ['IW4'],
execute: (gameEvent) => {
if (!validateEnabled(gameEvent.Owner, gameEvent.Origin)) {
return;
}
const args = String(gameEvent.Data).split(' ');
sendScriptCommand(gameEvent.Owner, 'Goto', gameEvent.Origin, gameEvent.Target, {
x: args[0],
y: args[1],
z: args[2]
});
}
},
{
name: 'kill',
description: 'kill a player',
alias: 'kpl',
permission: 'SeniorAdmin',
targetRequired: true,
arguments: [{
name: 'player',
required: true
}],
supportedGames: ['IW4'],
execute: (gameEvent) => {
if (!validateEnabled(gameEvent.Owner, gameEvent.Origin)) {
return;
}
sendScriptCommand(gameEvent.Owner, 'Kill', gameEvent.Origin, gameEvent.Target, undefined);
}
},
{
name: 'nightmode',
description: 'sets server into nightmode',
alias: 'nitem',
permission: 'SeniorAdmin',
targetRequired: false,
arguments: [],
supportedGames: ['IW4'],
execute: (gameEvent) => {
if (!validateEnabled(gameEvent.Owner, gameEvent.Origin)) {
return;
}
sendScriptCommand(gameEvent.Owner, 'NightMode', gameEvent.Origin, undefined, undefined);
}
},
{
name: 'setspectator',
description: 'sets a player as spectator',
alias: 'spec',
permission: 'Administrator',
targetRequired: true,
arguments: [{
name: 'player',
required: true
}],
supportedGames: ['IW4'],
execute: (gameEvent) => {
if (!validateEnabled(gameEvent.Owner, gameEvent.Origin)) {
return;
}
sendScriptCommand(gameEvent.Owner, 'SetSpectator', gameEvent.Origin, gameEvent.Target, undefined);
}
}];
const sendScriptCommand = (server, command, origin, target, data) => { const sendScriptCommand = (server, command, origin, target, data) => {
const state = servers[server.EndPoint]; const state = servers[server.EndPoint];
@ -301,34 +296,11 @@ const sendScriptCommand = (server, command, origin, target, data) => {
const sendEvent = (server, responseExpected, event, subtype, origin, target, data) => { const sendEvent = (server, responseExpected, event, subtype, origin, target, data) => {
const logger = _serviceResolver.ResolveService('ILogger'); const logger = _serviceResolver.ResolveService('ILogger');
const state = servers[server.EndPoint];
let pendingOut = true; if (state.queuedMessages.length >= maxQueuedMessages) {
let pendingCheckCount = 0; logger.WriteWarning('Too many queued messages so we are skipping');
const start = new Date(); return;
while (pendingOut && pendingCheckCount <= 10) {
if (server.Throttled) {
logger.WriteWarning('Server is throttled, so we are not attempting to send data');
return;
}
try {
const out = server.GetServerDvar(outDvar);
pendingOut = !(out == null || out === '' || out === 'null');
} catch (error) {
logger.WriteError(`Could not check server output dvar for IO status ${error}`);
}
if (pendingOut) {
logger.WriteDebug('Waiting for event bus to be cleared');
System.Threading.Tasks.Task.Delay(1000).Wait();
}
pendingCheckCount++;
}
if (pendingOut) {
logger.WriteWarning(`Reached maximum attempts waiting for output to be available for ${server.EndPoint}`)
} }
let targetClientNumber = -1; let targetClientNumber = -1;
@ -337,31 +309,11 @@ const sendEvent = (server, responseExpected, event, subtype, origin, target, dat
} }
const output = `${responseExpected ? '1' : '0'};${event};${subtype};${origin.ClientNumber};${targetClientNumber};${buildDataString(data)}`; const output = `${responseExpected ? '1' : '0'};${event};${subtype};${origin.ClientNumber};${targetClientNumber};${buildDataString(data)}`;
logger.WriteDebug(`Sending output to server ${output}`); logger.WriteDebug(`Queuing output for server ${output}`);
try { state.queuedMessages.push(output);
server.SetServerDvar(outDvar, output);
logger.WriteDebug(`SendEvent took ${(new Date() - start) / 1000}ms`);
} catch (error) {
logger.WriteError(`Could not set server output dvar ${error}`);
}
}; };
const parseEvent = (input) => {
if (input === undefined) {
return {};
}
const eventInfo = input.split(';');
return {
eventType: eventInfo[1],
subType: eventInfo[2],
clientNumber: eventInfo[3],
data: eventInfo.length > 4 ? parseDataString(eventInfo[4]) : undefined
}
}
const initialize = (server) => { const initialize = (server) => {
const logger = _serviceResolver.ResolveService('ILogger'); const logger = _serviceResolver.ResolveService('ILogger');
@ -371,7 +323,7 @@ const initialize = (server) => {
let enabled = false; let enabled = false;
try { try {
enabled = server.GetServerDvar('sv_iw4madmin_integration_enabled') === '1'; enabled = server.GetServerDvar('sv_iw4madmin_integration_enabled', enableCheckTimeout) === '1';
} catch (error) { } catch (error) {
logger.WriteError(`Could not get integration status of ${server.EndPoint} - ${error}`); logger.WriteError(`Could not get integration status of ${server.EndPoint} - ${error}`);
} }
@ -391,33 +343,36 @@ const initialize = (server) => {
servers[server.EndPoint].timer = timer; servers[server.EndPoint].timer = timer;
servers[server.EndPoint].enabled = true; servers[server.EndPoint].enabled = true;
servers[server.EndPoint].waitingOnInput = false;
servers[server.EndPoint].waitingOnOutput = false;
servers[server.EndPoint].queuedMessages = [];
try { setDvar(server, inDvar, '', onSetDvar);
server.SetServerDvar(inDvar, ''); setDvar(server, outDvar, '', onSetDvar);
server.SetServerDvar(outDvar, '');
} catch (error) {
logger.WriteError(`Could set default values bus dvars for ${server.EndPoint} - ${error}`);
}
return true; return true;
}; }
const pollForEvents = server => { function onReceivedDvar(server, dvarName, dvarValue, success) {
if (server.Throttled) {
return;
}
const logger = _serviceResolver.ResolveService('ILogger'); const logger = _serviceResolver.ResolveService('ILogger');
logger.WriteDebug(`Received ${dvarName}=${dvarValue} success=${success}`);
let input; let input = dvarValue;
try { const state = servers[server.EndPoint];
input = server.GetServerDvar(inDvar);
} catch (error) { if (state.waitingOnOutput && dvarName === outDvar && isEmpty(dvarValue)) {
logger.WriteError(`Could not get input bus value for ${server.EndPoint} - ${error}`); logger.WriteDebug('Setting out bus to read to send');
return; // reset our flag letting use the out bus is open
state.waitingOnOutput = !success;
} }
if (input === undefined || input === null || input === 'null') { if (state.waitingOnInput && dvarName === inDvar) {
logger.WriteDebug('Setting in bus to ready to receive');
// we've received the data so now we can mark it as ready for more
state.waitingOnInput = false;
}
if (isEmpty(input)) {
input = ''; input = '';
} }
@ -481,24 +436,80 @@ const pollForEvents = server => {
} else { } else {
metaService.SetPersistentMeta(event.data['key'], event.data['value'], clientId).GetAwaiter().GetResult(); metaService.SetPersistentMeta(event.data['key'], event.data['value'], clientId).GetAwaiter().GetResult();
} }
sendEvent(server, false, 'SetClientDataCompleted', 'Meta', {ClientNumber: event.clientNumber}, undefined,{status: 'Complete'}); sendEvent(server, false, 'SetClientDataCompleted', 'Meta', {ClientNumber: event.clientNumber}, undefined, {status: 'Complete'});
} catch (error) { } catch (error) {
sendEvent(server, false, 'SetClientDataCompleted', 'Meta', {ClientNumber: event.clientNumber}, undefined,{status: 'Fail'}); sendEvent(server, false, 'SetClientDataCompleted', 'Meta', {ClientNumber: event.clientNumber}, undefined, {status: 'Fail'});
} }
} }
} }
} }
try { setDvar(server, inDvar, '', onSetDvar);
server.SetServerDvar(inDvar, '');
} catch (error) {
logger.WriteError(`Could not reset in bus value for ${server.EndPoint} - ${error}`);
}
} else if (server.ClientNum === 0) { } else if (server.ClientNum === 0) {
servers[server.EndPoint].timer.Stop(); servers[server.EndPoint].timer.Stop();
} }
} }
function onSetDvar(server, dvarName, dvarValue, success) {
const logger = _serviceResolver.ResolveService('ILogger');
logger.WriteDebug(`Completed set of dvar ${dvarName}=${dvarValue}, success=${success}`);
const state = servers[server.EndPoint];
if (dvarName === inDvar && success && isEmpty(dvarValue)) {
logger.WriteDebug('In bus is ready for new data');
// reset our flag letting use the in bus is ready for more data
state.waitingOnInput = false;
}
}
const pollForEvents = server => {
const state = servers[server.EndPoint];
if (state === null || !state.enabled) {
return;
}
if (server.Throttled) {
return;
}
if (!state.waitingOnInput) {
state.waitingOnInput = true;
getDvar(server, inDvar, onReceivedDvar);
}
if (!state.waitingOnOutput) {
if (state.queuedMessages.length === 0) {
logger.WriteDebug('No messages in queue');
return;``
}
state.waitingOnOutput = true;
const nextMessage = state.queuedMessages.splice(0, 1);
setDvar(server, outDvar, nextMessage, onSetDvar);
}
if (state.waitingOnOutput) {
getDvar(server, outDvar, onReceivedDvar);
}
}
const parseEvent = (input) => {
if (input === undefined) {
return {};
}
const eventInfo = input.split(';');
return {
eventType: eventInfo[1],
subType: eventInfo[2],
clientNumber: eventInfo[3],
data: eventInfo.length > 4 ? parseDataString(eventInfo[4]) : undefined
}
}
const buildDataString = data => { const buildDataString = data => {
if (data === undefined) { if (data === undefined) {
return ''; return '';
@ -534,7 +545,11 @@ const parseDataString = data => {
const validateEnabled = (server, origin) => { const validateEnabled = (server, origin) => {
const enabled = servers[server.EndPoint] != null && servers[server.EndPoint].enabled; const enabled = servers[server.EndPoint] != null && servers[server.EndPoint].enabled;
if (!enabled) { if (!enabled) {
origin.Tell("Game interface is not enabled on this server"); origin.Tell('Game interface is not enabled on this server');
} }
return enabled; return enabled;
} }
function isEmpty(value) {
return value == null || false || value === '' || value === 'null';
}

View File

@ -257,6 +257,7 @@ namespace SharedLibraryCore
public EFClient Target; public EFClient Target;
public EventType Type; public EventType Type;
public string TypeName => Type.ToString();
public GameEvent() public GameEvent()
{ {

View File

@ -388,10 +388,10 @@ namespace SharedLibraryCore
public abstract Task<long> GetIdForServer(Server server = null); public abstract Task<long> GetIdForServer(Server server = null);
public string[] ExecuteServerCommand(string command) public string[] ExecuteServerCommand(string command, int timeoutMs = 1000)
{ {
var tokenSource = new CancellationTokenSource(); var tokenSource = new CancellationTokenSource();
tokenSource.CancelAfter(TimeSpan.FromSeconds(0.5)); tokenSource.CancelAfter(TimeSpan.FromSeconds(timeoutMs));
try try
{ {
@ -403,10 +403,10 @@ namespace SharedLibraryCore
} }
} }
public string GetServerDvar(string dvarName) public string GetServerDvar(string dvarName, int timeoutMs = 1000)
{ {
var tokenSource = new CancellationTokenSource(); var tokenSource = new CancellationTokenSource();
tokenSource.CancelAfter(TimeSpan.FromSeconds(0.5)); tokenSource.CancelAfter(TimeSpan.FromSeconds(timeoutMs));
try try
{ {
return this.GetDvarAsync<string>(dvarName, token: tokenSource.Token).GetAwaiter().GetResult().Value; return this.GetDvarAsync<string>(dvarName, token: tokenSource.Token).GetAwaiter().GetResult().Value;
@ -417,10 +417,10 @@ namespace SharedLibraryCore
} }
} }
public bool SetServerDvar(string dvarName, string dvarValue) public bool SetServerDvar(string dvarName, string dvarValue, int timeoutMs = 1000)
{ {
var tokenSource = new CancellationTokenSource(); var tokenSource = new CancellationTokenSource();
tokenSource.CancelAfter(TimeSpan.FromSeconds(0.5)); tokenSource.CancelAfter(TimeSpan.FromSeconds(timeoutMs));
try try
{ {
this.SetDvarAsync(dvarName, dvarValue, tokenSource.Token).GetAwaiter().GetResult(); this.SetDvarAsync(dvarName, dvarValue, tokenSource.Token).GetAwaiter().GetResult();