more work on skill based team balance.
added on player disconnect to custom callbacks
This commit is contained in:
parent
d50e6c8030
commit
1779bf821d
@ -37,7 +37,7 @@ namespace IW4MAdmin.Application.IO
|
|||||||
Server = server;
|
Server = server;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PollForChanges()
|
public async Task PollForChanges()
|
||||||
{
|
{
|
||||||
while (!Server.Manager.ShutdownRequested())
|
while (!Server.Manager.ShutdownRequested())
|
||||||
{
|
{
|
||||||
@ -45,7 +45,7 @@ namespace IW4MAdmin.Application.IO
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
UpdateLogEvents();
|
await UpdateLogEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -59,7 +59,7 @@ namespace IW4MAdmin.Application.IO
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateLogEvents()
|
private async Task UpdateLogEvents()
|
||||||
{
|
{
|
||||||
long fileSize = Reader.Length;
|
long fileSize = Reader.Length;
|
||||||
|
|
||||||
@ -74,7 +74,7 @@ namespace IW4MAdmin.Application.IO
|
|||||||
|
|
||||||
PreviousFileSize = fileSize;
|
PreviousFileSize = fileSize;
|
||||||
|
|
||||||
var events = Reader.ReadEventsFromLog(Server, fileDiff, 0);
|
var events = await Reader.ReadEventsFromLog(Server, fileDiff, 0);
|
||||||
|
|
||||||
foreach (var ev in events)
|
foreach (var ev in events)
|
||||||
{
|
{
|
||||||
|
@ -4,6 +4,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.IO
|
namespace IW4MAdmin.Application.IO
|
||||||
{
|
{
|
||||||
@ -22,7 +23,7 @@ namespace IW4MAdmin.Application.IO
|
|||||||
Parser = parser;
|
Parser = parser;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ICollection<GameEvent> ReadEventsFromLog(Server server, long fileSizeDiff, long startPosition)
|
public async Task<ICollection<GameEvent>> ReadEventsFromLog(Server server, long fileSizeDiff, long startPosition)
|
||||||
{
|
{
|
||||||
// allocate the bytes for the new log lines
|
// allocate the bytes for the new log lines
|
||||||
List<string> logLines = new List<string>();
|
List<string> logLines = new List<string>();
|
||||||
@ -30,6 +31,7 @@ namespace IW4MAdmin.Application.IO
|
|||||||
// open the file as a stream
|
// open the file as a stream
|
||||||
using (var rd = new StreamReader(new FileStream(LogFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), Utilities.EncodingType))
|
using (var rd = new StreamReader(new FileStream(LogFile, FileMode.Open, FileAccess.Read, FileShare.ReadWrite), Utilities.EncodingType))
|
||||||
{
|
{
|
||||||
|
// todo: max async
|
||||||
// take the old start position and go back the number of new characters
|
// take the old start position and go back the number of new characters
|
||||||
rd.BaseStream.Seek(-fileSizeDiff, SeekOrigin.End);
|
rd.BaseStream.Seek(-fileSizeDiff, SeekOrigin.End);
|
||||||
// the difference should be in the range of a int :P
|
// the difference should be in the range of a int :P
|
||||||
|
@ -5,6 +5,7 @@ using SharedLibraryCore.Interfaces;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using static SharedLibraryCore.Utilities;
|
using static SharedLibraryCore.Utilities;
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.IO
|
namespace IW4MAdmin.Application.IO
|
||||||
@ -29,18 +30,19 @@ namespace IW4MAdmin.Application.IO
|
|||||||
|
|
||||||
public int UpdateInterval => 1000;
|
public int UpdateInterval => 1000;
|
||||||
|
|
||||||
public ICollection<GameEvent> ReadEventsFromLog(Server server, long fileSizeDiff, long startPosition)
|
public async Task<ICollection<GameEvent>> ReadEventsFromLog(Server server, long fileSizeDiff, long startPosition)
|
||||||
{
|
{
|
||||||
#if DEBUG == true
|
#if DEBUG == true
|
||||||
server.Logger.WriteDebug($"Begin reading {fileSizeDiff} from http log");
|
server.Logger.WriteDebug($"Begin reading {fileSizeDiff} from http log");
|
||||||
#endif
|
#endif
|
||||||
var events = new List<GameEvent>();
|
var events = new List<GameEvent>();
|
||||||
string b64Path = server.LogPath.ToBase64UrlSafeString();
|
string b64Path = server.LogPath.ToBase64UrlSafeString();
|
||||||
var response = Api.Log(b64Path).Result;
|
var response = await Api.Log(b64Path);
|
||||||
|
|
||||||
if (!response.Success)
|
if (!response.Success)
|
||||||
{
|
{
|
||||||
server.Logger.WriteError($"Could not get log server info of {LogFile}/{b64Path} ({server.LogPath})");
|
server.Logger.WriteError($"Could not get log server info of {LogFile}/{b64Path} ({server.LogPath})");
|
||||||
|
return events;
|
||||||
}
|
}
|
||||||
|
|
||||||
// parse each line
|
// parse each line
|
||||||
|
@ -151,7 +151,9 @@ namespace IW4MAdmin.Application
|
|||||||
{
|
{
|
||||||
Logger.WriteWarning($"Delayed event for {e.Origin} was ignored because the target has left");
|
Logger.WriteWarning($"Delayed event for {e.Origin} was ignored because the target has left");
|
||||||
// hack: don't do anything with the event because the target is invalid
|
// hack: don't do anything with the event because the target is invalid
|
||||||
|
e.Origin = null;
|
||||||
e.Type = GameEvent.EventType.Unknown;
|
e.Type = GameEvent.EventType.Unknown;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Logger.WriteDebug($"Adding delayed event of type {e.Type} for {e.Origin} back for processing");
|
Logger.WriteDebug($"Adding delayed event of type {e.Type} for {e.Origin} back for processing");
|
||||||
@ -265,11 +267,7 @@ namespace IW4MAdmin.Application
|
|||||||
ThreadPool.GetAvailableThreads(out int availableThreads, out int m);
|
ThreadPool.GetAvailableThreads(out int availableThreads, out int m);
|
||||||
Logger.WriteDebug($"There are {workerThreads - availableThreads} active threading tasks");
|
Logger.WriteDebug($"There are {workerThreads - availableThreads} active threading tasks");
|
||||||
#endif
|
#endif
|
||||||
#if DEBUG
|
|
||||||
await Task.Delay(10000);
|
|
||||||
#else
|
|
||||||
await Task.Delay(ConfigHandler.Configuration().RConPollRate);
|
await Task.Delay(ConfigHandler.Configuration().RConPollRate);
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// trigger the event processing loop to end
|
// trigger the event processing loop to end
|
||||||
|
@ -26,6 +26,7 @@ namespace IW4MAdmin
|
|||||||
{
|
{
|
||||||
private static readonly Index loc = Utilities.CurrentLocalization.LocalizationIndex;
|
private static readonly Index loc = Utilities.CurrentLocalization.LocalizationIndex;
|
||||||
private GameLogEventDetection LogEvent;
|
private GameLogEventDetection LogEvent;
|
||||||
|
public int Id { get; private set; }
|
||||||
|
|
||||||
public IW4MServer(IManager mgr, ServerConfiguration cfg) : base(mgr, cfg)
|
public IW4MServer(IManager mgr, ServerConfiguration cfg) : base(mgr, cfg)
|
||||||
{
|
{
|
||||||
@ -33,30 +34,28 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
if (GameName == Game.IW4)
|
if ($"{IP}:{Port.ToString()}" == "66.150.121.184:28965")
|
||||||
{
|
{
|
||||||
// todo: make this better with collisions
|
|
||||||
int id = Math.Abs($"{IP}:{Port.ToString()}".Select(a => (int)a).Sum());
|
|
||||||
|
|
||||||
// hack: this is a nasty fix for get hashcode being changed
|
|
||||||
switch (id)
|
|
||||||
{
|
|
||||||
case 765:
|
|
||||||
return 886229536;
|
return 886229536;
|
||||||
case 760:
|
}
|
||||||
|
|
||||||
|
if ($"{IP}:{Port.ToString()}" == "66.150.121.184:28960")
|
||||||
|
{
|
||||||
return 1645744423;
|
return 1645744423;
|
||||||
case 761:
|
}
|
||||||
|
|
||||||
|
if ($"{IP}:{Port.ToString()}" == "66.150.121.184:28970")
|
||||||
|
{
|
||||||
return 1645809959;
|
return 1645809959;
|
||||||
}
|
}
|
||||||
|
|
||||||
return id;
|
if (Id == 0)
|
||||||
|
{
|
||||||
|
Id = HashCode.Combine(IP, Port);
|
||||||
|
Id = Id < 0 ? Math.Abs(Id) : Id;
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
return Id;
|
||||||
{
|
|
||||||
int id = HashCode.Combine(IP, Port);
|
|
||||||
return id < 0 ? Math.Abs(id) : id;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task OnPlayerJoined(Player logClient)
|
public async Task OnPlayerJoined(Player logClient)
|
||||||
@ -560,11 +559,13 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
if (E.Type == GameEvent.EventType.Broadcast)
|
if (E.Type == GameEvent.EventType.Broadcast)
|
||||||
{
|
{
|
||||||
|
#if DEBUG == false
|
||||||
// this is a little ugly but I don't want to change the abstract class
|
// this is a little ugly but I don't want to change the abstract class
|
||||||
if (E.Data != null)
|
if (E.Data != null)
|
||||||
{
|
{
|
||||||
await E.Owner.ExecuteCommandAsync(E.Data);
|
await E.Owner.ExecuteCommandAsync(E.Data);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
while (ChatHistory.Count > Math.Ceiling((double)ClientNum / 2))
|
while (ChatHistory.Count > Math.Ceiling((double)ClientNum / 2))
|
||||||
@ -661,7 +662,7 @@ namespace IW4MAdmin
|
|||||||
waiterList.Add(e);
|
waiterList.Add(e);
|
||||||
}
|
}
|
||||||
// wait for all the disconnect tasks to finish
|
// wait for all the disconnect tasks to finish
|
||||||
await Task.WhenAll(waiterList.Select(e => e.WaitAsync()));
|
await Task.WhenAll(waiterList.Select(e => e.WaitAsync(10 * 1000)));
|
||||||
|
|
||||||
waiterList.Clear();
|
waiterList.Clear();
|
||||||
// this are our new connecting clients
|
// this are our new connecting clients
|
||||||
@ -686,7 +687,7 @@ namespace IW4MAdmin
|
|||||||
}
|
}
|
||||||
|
|
||||||
// wait for all the connect tasks to finish
|
// wait for all the connect tasks to finish
|
||||||
await Task.WhenAll(waiterList.Select(e => e.WaitAsync()));
|
await Task.WhenAll(waiterList.Select(e => e.WaitAsync(10 * 1000)));
|
||||||
|
|
||||||
if (ConnectionErrors > 0)
|
if (ConnectionErrors > 0)
|
||||||
{
|
{
|
||||||
@ -700,7 +701,7 @@ namespace IW4MAdmin
|
|||||||
catch (NetworkException e)
|
catch (NetworkException e)
|
||||||
{
|
{
|
||||||
ConnectionErrors++;
|
ConnectionErrors++;
|
||||||
if (ConnectionErrors == 1)
|
if (ConnectionErrors == 3)
|
||||||
{
|
{
|
||||||
Logger.WriteError($"{e.Message} {IP}:{Port}, {loc["SERVER_ERROR_POLLING"]}");
|
Logger.WriteError($"{e.Message} {IP}:{Port}, {loc["SERVER_ERROR_POLLING"]}");
|
||||||
Logger.WriteDebug($"Internal Exception: {e.Data["internal_exception"]}");
|
Logger.WriteDebug($"Internal Exception: {e.Data["internal_exception"]}");
|
||||||
|
31
Application/SharedGUIDKick.js
Normal file
31
Application/SharedGUIDKick.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
var plugin = {
|
||||||
|
author: 'RaidMax',
|
||||||
|
version: 1.1,
|
||||||
|
name: 'Shared GUID Kicker Plugin',
|
||||||
|
|
||||||
|
onEventAsync: function (gameEvent, server) {
|
||||||
|
// make sure we only check for IW4(x)
|
||||||
|
if (server.GameName !== 2) {
|
||||||
|
return false;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// connect or join event
|
||||||
|
if (gameEvent.Type === 3) {
|
||||||
|
// this GUID seems to have been packed in a IW4 torrent and results in an unreasonable amount of people using the same GUID
|
||||||
|
if (gameEvent.Origin.NetworkId === -805366929435212061) {
|
||||||
|
gameEvent.Origin.Kick('Your GUID is generic. Delete players/guids.dat and rejoin', _IW4MAdminClient);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onLoadAsync: function (manager) {
|
||||||
|
},
|
||||||
|
|
||||||
|
onUnloadAsync: function () {
|
||||||
|
},
|
||||||
|
|
||||||
|
onTickAsync: function (server) {
|
||||||
|
}
|
||||||
|
};
|
62
Application/VPNDetection.js
Normal file
62
Application/VPNDetection.js
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
var plugin = {
|
||||||
|
author: 'RaidMax',
|
||||||
|
version: 1.0,
|
||||||
|
name: 'VPN Detection Plugin',
|
||||||
|
|
||||||
|
manager: null,
|
||||||
|
logger: null,
|
||||||
|
vpnExceptionIds: [],
|
||||||
|
|
||||||
|
checkForVpn: function (origin) {
|
||||||
|
var exempt = false;
|
||||||
|
// prevent players that are exempt from being kicked
|
||||||
|
this.vpnExceptionIds.forEach(function (id) {
|
||||||
|
if (id === origin.ClientId) {
|
||||||
|
exempt = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (exempt) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var usingVPN = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
var cl = new System.Net.Http.HttpClient();
|
||||||
|
var re = cl.GetAsync('https://api.xdefcon.com/proxy/check/?ip=' + origin.IPAddressString).Result;
|
||||||
|
var co = re.Content;
|
||||||
|
var parsedJSON = JSON.parse(co.ReadAsStringAsync().Result);
|
||||||
|
co.Dispose();
|
||||||
|
re.Dispose();
|
||||||
|
cl.Dispose();
|
||||||
|
usingVPN = parsedJSON.success && parsedJSON.proxy;
|
||||||
|
} catch (e) {
|
||||||
|
this.logger.WriteError(e.message);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (usingVPN) {
|
||||||
|
this.logger.WriteInfo(origin + ' is using a VPN (' + origin.IPAddressString + ')');
|
||||||
|
origin.Kick(_localization.LocalizationIndex["SERVER_KICK_VPNS_NOTALLOWED"], _IW4MAdminClient);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onEventAsync: function (gameEvent, server) {
|
||||||
|
// connect event
|
||||||
|
if (gameEvent.Type === 3) {
|
||||||
|
this.checkForVpn(gameEvent.Origin);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
onLoadAsync: function (manager) {
|
||||||
|
this.manager = manager;
|
||||||
|
this.logger = manager.GetLogger(0);
|
||||||
|
},
|
||||||
|
|
||||||
|
onUnloadAsync: function () {
|
||||||
|
},
|
||||||
|
|
||||||
|
onTickAsync: function (server) {
|
||||||
|
}
|
||||||
|
};
|
@ -17,21 +17,21 @@ namespace IW4ScriptCommands.Commands
|
|||||||
public IW4MAdmin.Plugins.Stats.Models.EFClientStatistics Stats { get; set; }
|
public IW4MAdmin.Plugins.Stats.Models.EFClientStatistics Stats { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetTeamAssignments(Player client, string teamsString = "")
|
public static string GetTeamAssignments(Player client, bool isDisconnect, Server server, string teamsString = "")
|
||||||
{
|
{
|
||||||
var scriptClientTeams = teamsString.Split(';', StringSplitOptions.RemoveEmptyEntries)
|
var scriptClientTeams = teamsString.Split(';', StringSplitOptions.RemoveEmptyEntries)
|
||||||
.Select(c => c.Split(','))
|
.Select(c => c.Split(','))
|
||||||
.Select(c => new TeamAssignment()
|
.Select(c => new TeamAssignment()
|
||||||
{
|
{
|
||||||
CurrentTeam = (IW4MAdmin.Plugins.Stats.IW4Info.Team)Enum.Parse(typeof(IW4MAdmin.Plugins.Stats.IW4Info.Team), c[1]),
|
CurrentTeam = (IW4MAdmin.Plugins.Stats.IW4Info.Team)Enum.Parse(typeof(IW4MAdmin.Plugins.Stats.IW4Info.Team), c[1]),
|
||||||
Num = client.CurrentServer.GetPlayersAsList().FirstOrDefault(p => p.ClientNumber== Int32.Parse(c[0]))?.ClientNumber ?? -1,
|
Num = server.GetPlayersAsList().FirstOrDefault(p => p.ClientNumber == Int32.Parse(c[0]))?.ClientNumber ?? -1,
|
||||||
Stats = IW4MAdmin.Plugins.Stats.Plugin.Manager.GetClientStats(client.CurrentServer.Players.FirstOrDefault(p => p.ClientNumber == Int32.Parse(c[0])).ClientId, client.CurrentServer.GetHashCode())
|
Stats = IW4MAdmin.Plugins.Stats.Plugin.Manager.GetClientStats(server.Players.FirstOrDefault(p => p.ClientNumber == Int32.Parse(c[0])).ClientId, server.GetHashCode())
|
||||||
})
|
})
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
// at least one team is full so we can't balance
|
// at least one team is full so we can't balance
|
||||||
if (scriptClientTeams.Count(ct => ct.CurrentTeam == IW4MAdmin.Plugins.Stats.IW4Info.Team.Axis) >= Math.Floor(client.CurrentServer.MaxClients / 2.0)
|
if (scriptClientTeams.Count(ct => ct.CurrentTeam == IW4MAdmin.Plugins.Stats.IW4Info.Team.Axis) >= Math.Floor(server.MaxClients / 2.0)
|
||||||
|| scriptClientTeams.Count(ct => ct.CurrentTeam == IW4MAdmin.Plugins.Stats.IW4Info.Team.Allies) >= Math.Floor(client.CurrentServer.MaxClients / 2.0))
|
|| scriptClientTeams.Count(ct => ct.CurrentTeam == IW4MAdmin.Plugins.Stats.IW4Info.Team.Allies) >= Math.Floor(server.MaxClients / 2.0))
|
||||||
{
|
{
|
||||||
// E.Origin?.Tell(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_BALANCE_FAIL"]);
|
// E.Origin?.Tell(Utilities.CurrentLocalization.LocalizationIndex["COMMANDS_BALANCE_FAIL"]);
|
||||||
return string.Empty;
|
return string.Empty;
|
||||||
@ -39,11 +39,17 @@ namespace IW4ScriptCommands.Commands
|
|||||||
|
|
||||||
List<string> teamAssignments = new List<string>();
|
List<string> teamAssignments = new List<string>();
|
||||||
|
|
||||||
var activeClients = client.CurrentServer.GetPlayersAsList().Select(c => new TeamAssignment()
|
var _c = server.GetPlayersAsList();
|
||||||
|
if (isDisconnect && client != null)
|
||||||
|
{
|
||||||
|
_c = _c.Where(c => c.ClientNumber != client.ClientNumber).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
var activeClients = _c.Select(c => new TeamAssignment()
|
||||||
{
|
{
|
||||||
Num = c.ClientNumber,
|
Num = c.ClientNumber,
|
||||||
Stats = IW4MAdmin.Plugins.Stats.Plugin.Manager.GetClientStats(c.ClientId, client.CurrentServer.GetHashCode()),
|
Stats = IW4MAdmin.Plugins.Stats.Plugin.Manager.GetClientStats(c.ClientId, server.GetHashCode()),
|
||||||
CurrentTeam = IW4MAdmin.Plugins.Stats.Plugin.Manager.GetClientStats(c.ClientId, client.CurrentServer.GetHashCode()).Team
|
CurrentTeam = IW4MAdmin.Plugins.Stats.Plugin.Manager.GetClientStats(c.ClientId, server.GetHashCode()).Team
|
||||||
})
|
})
|
||||||
.Where(c => scriptClientTeams.FirstOrDefault(sc => sc.Num == c.Num)?.CurrentTeam != IW4MAdmin.Plugins.Stats.IW4Info.Team.Spectator)
|
.Where(c => scriptClientTeams.FirstOrDefault(sc => sc.Num == c.Num)?.CurrentTeam != IW4MAdmin.Plugins.Stats.IW4Info.Team.Spectator)
|
||||||
.Where(c => c.CurrentTeam != scriptClientTeams.FirstOrDefault(p => p.Num == c.Num)?.CurrentTeam)
|
.Where(c => c.CurrentTeam != scriptClientTeams.FirstOrDefault(p => p.Num == c.Num)?.CurrentTeam)
|
||||||
|
@ -35,14 +35,18 @@ namespace WebfrontCore.Controllers.API
|
|||||||
}
|
}
|
||||||
|
|
||||||
[HttpGet("{networkId}")]
|
[HttpGet("{networkId}")]
|
||||||
public IActionResult GetTeamAssignments(string networkId, string teams = "")
|
public IActionResult GetTeamAssignments(string networkId, int serverId, string teams = "", bool isDisconnect = false)
|
||||||
{
|
{
|
||||||
|
return Unauthorized();
|
||||||
|
|
||||||
var client = Manager.GetActiveClients()
|
var client = Manager.GetActiveClients()
|
||||||
.First(c => c.NetworkId == networkId.ConvertLong());
|
.FirstOrDefault(c => c.NetworkId == networkId.ConvertLong());
|
||||||
|
|
||||||
|
var server = Manager.GetServers().First(c => c.GetHashCode() == serverId);
|
||||||
|
|
||||||
teams = teams ?? string.Empty;
|
teams = teams ?? string.Empty;
|
||||||
|
|
||||||
string assignments = Balance.GetTeamAssignments(client, teams);
|
string assignments = Balance.GetTeamAssignments(client, isDisconnect, server, teams);
|
||||||
|
|
||||||
return Content(assignments);
|
return Content(assignments);
|
||||||
}
|
}
|
||||||
|
@ -17,15 +17,10 @@ namespace IW4ScriptCommands
|
|||||||
|
|
||||||
public Task OnEventAsync(GameEvent E, Server S)
|
public Task OnEventAsync(GameEvent E, Server S)
|
||||||
{
|
{
|
||||||
//if (E.Type == GameEvent.EventType.JoinTeam || E.Type == GameEvent.EventType.Disconnect)
|
if (E.Type == GameEvent.EventType.Start)
|
||||||
//{
|
{
|
||||||
// E.Origin = new SharedLibraryCore.Objects.Player()
|
return S.SetDvarAsync("sv_iw4madmin_serverid", S.GetHashCode());
|
||||||
// {
|
}
|
||||||
// ClientId = 1,
|
|
||||||
// CurrentServer = E.Owner
|
|
||||||
// };
|
|
||||||
// return new Commands.Balance().ExecuteAsync(E);
|
|
||||||
//}
|
|
||||||
|
|
||||||
if (E.Type == GameEvent.EventType.Warn)
|
if (E.Type == GameEvent.EventType.Warn)
|
||||||
{
|
{
|
||||||
|
@ -265,7 +265,7 @@ namespace SharedLibraryCore.Commands
|
|||||||
|
|
||||||
public override Task ExecuteAsync(GameEvent E)
|
public override Task ExecuteAsync(GameEvent E)
|
||||||
{
|
{
|
||||||
String You = String.Format("{0} [^3#{1}^7] {2} [^3@{3}^7] [{4}^7] IP: {5}", E.Origin.Name, E.Origin.ClientNumber, E.Origin.NetworkId, E.Origin.ClientId, Utilities.ConvertLevelToColor(E.Origin.Level, E.Origin.ClientPermission.Name), E.Origin.IPAddressString);
|
String You = String.Format("{0} [^3#{1}^7] {2} ^7[^3@{3}^7] ^7[{4}^7] IP: {5}", E.Origin.Name, E.Origin.ClientNumber, E.Origin.NetworkId, E.Origin.ClientId, Utilities.ConvertLevelToColor(E.Origin.Level, E.Origin.ClientPermission.Name), E.Origin.IPAddressString);
|
||||||
E.Origin.Tell(You);
|
E.Origin.Tell(You);
|
||||||
|
|
||||||
return Task.CompletedTask;
|
return Task.CompletedTask;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
namespace SharedLibraryCore.Interfaces
|
namespace SharedLibraryCore.Interfaces
|
||||||
{
|
{
|
||||||
@ -16,7 +17,7 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
/// <param name="fileSizeDiff"></param>
|
/// <param name="fileSizeDiff"></param>
|
||||||
/// <param name="startPosition"></param>
|
/// <param name="startPosition"></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
ICollection<GameEvent> ReadEventsFromLog(Server server, long fileSizeDiff, long startPosition);
|
Task<ICollection<GameEvent>> ReadEventsFromLog(Server server, long fileSizeDiff, long startPosition);
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// how long the log file is
|
/// how long the log file is
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -89,13 +89,14 @@ namespace SharedLibraryCore.RCon
|
|||||||
byte[] response = null;
|
byte[] response = null;
|
||||||
|
|
||||||
retrySend:
|
retrySend:
|
||||||
connectionState.SendEventArgs.UserToken = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
|
using (var socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
|
||||||
{
|
{
|
||||||
DontFragment = true,
|
//DontFragment = true,
|
||||||
Ttl = 42,
|
Ttl = 100,
|
||||||
ExclusiveAddressUse = true,
|
ExclusiveAddressUse = true,
|
||||||
};
|
})
|
||||||
|
{
|
||||||
|
connectionState.SendEventArgs.UserToken = socket;
|
||||||
connectionState.OnSentData.Reset();
|
connectionState.OnSentData.Reset();
|
||||||
connectionState.OnReceivedData.Reset();
|
connectionState.OnReceivedData.Reset();
|
||||||
connectionState.ConnectionAttempts++;
|
connectionState.ConnectionAttempts++;
|
||||||
@ -122,8 +123,9 @@ namespace SharedLibraryCore.RCon
|
|||||||
//Log.WriteDebug(ex.GetExceptionInfo());
|
//Log.WriteDebug(ex.GetExceptionInfo());
|
||||||
throw new NetworkException($"{Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_COMMUNICATION"]} [{this.Endpoint}]");
|
throw new NetworkException($"{Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_COMMUNICATION"]} [{this.Endpoint}]");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
string responseString = Utilities.EncodingType.GetString(response, 0, response.Length).TrimEnd('\0') + '\n';
|
string responseString = Utilities.EncodingType.GetString(response, 0, response.Length) + '\n';
|
||||||
|
|
||||||
if (responseString.Contains("Invalid password"))
|
if (responseString.Contains("Invalid password"))
|
||||||
{
|
{
|
||||||
@ -135,9 +137,12 @@ namespace SharedLibraryCore.RCon
|
|||||||
throw new NetworkException(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_RCON_NOTSET"]);
|
throw new NetworkException(Utilities.CurrentLocalization.LocalizationIndex["SERVER_ERROR_RCON_NOTSET"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log.WriteInfo(responseString);
|
||||||
|
|
||||||
string[] splitResponse = responseString.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries)
|
string[] splitResponse = responseString.Split(new char[] { '\n' }, StringSplitOptions.RemoveEmptyEntries)
|
||||||
.Select(line => line.Trim()).ToArray();
|
.Select(line => line.Trim()).ToArray();
|
||||||
return splitResponse;
|
return splitResponse;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<byte[]> SendPayloadAsync(byte[] payload, bool waitForResponse)
|
private async Task<byte[]> SendPayloadAsync(byte[] payload, bool waitForResponse)
|
||||||
|
@ -117,19 +117,14 @@ namespace SharedLibraryCore
|
|||||||
/// <param name="message">Message to be sent to all players</param>
|
/// <param name="message">Message to be sent to all players</param>
|
||||||
public GameEvent Broadcast(string message, Player sender = null)
|
public GameEvent Broadcast(string message, Player sender = null)
|
||||||
{
|
{
|
||||||
#if DEBUG == false
|
|
||||||
string formattedMessage = String.Format(RconParser.GetCommandPrefixes().Say, $"{(CustomSayEnabled ? $"{CustomSayName}: " : "")}{message}");
|
string formattedMessage = String.Format(RconParser.GetCommandPrefixes().Say, $"{(CustomSayEnabled ? $"{CustomSayName}: " : "")}{message}");
|
||||||
#else
|
|
||||||
Logger.WriteVerbose(message.StripColors());
|
//Logger.WriteVerbose(message.StripColors());
|
||||||
#endif
|
|
||||||
var e = new GameEvent()
|
var e = new GameEvent()
|
||||||
{
|
{
|
||||||
Type = GameEvent.EventType.Broadcast,
|
Type = GameEvent.EventType.Broadcast,
|
||||||
#if DEBUG == true
|
|
||||||
Data = message,
|
|
||||||
#else
|
|
||||||
Data = formattedMessage,
|
Data = formattedMessage,
|
||||||
#endif
|
|
||||||
Owner = this,
|
Owner = this,
|
||||||
Origin = sender,
|
Origin = sender,
|
||||||
};
|
};
|
||||||
|
@ -145,7 +145,7 @@ namespace SharedLibraryCore.Services
|
|||||||
PunisherId = penalty.PunisherId,
|
PunisherId = penalty.PunisherId,
|
||||||
Offense = penalty.Offense,
|
Offense = penalty.Offense,
|
||||||
Type = penalty.Type.ToString(),
|
Type = penalty.Type.ToString(),
|
||||||
TimeRemaining = now > penalty.Expires ? "" : penalty.Expires.ToString(),
|
TimeRemaining = penalty.Expires.HasValue ? (now > penalty.Expires ? "" : penalty.Expires.ToString()) : DateTime.MaxValue.ToString(),
|
||||||
AutomatedOffense = penalty.AutomatedOffense
|
AutomatedOffense = penalty.AutomatedOffense
|
||||||
},
|
},
|
||||||
When = penalty.When,
|
When = penalty.When,
|
||||||
@ -160,7 +160,7 @@ namespace SharedLibraryCore.Services
|
|||||||
((PenaltyInfo)p.Value).Type = ((Penalty.PenaltyType)Convert.ToInt32(((PenaltyInfo)p.Value).Type)).ToString();
|
((PenaltyInfo)p.Value).Type = ((Penalty.PenaltyType)Convert.ToInt32(((PenaltyInfo)p.Value).Type)).ToString();
|
||||||
|
|
||||||
var pi = ((PenaltyInfo)p.Value);
|
var pi = ((PenaltyInfo)p.Value);
|
||||||
if (pi.TimeRemaining.Length > 0)
|
if (pi.TimeRemaining?.Length > 0)
|
||||||
pi.TimeRemaining = (DateTime.Parse(((PenaltyInfo)p.Value).TimeRemaining) - now).TimeSpanText();
|
pi.TimeRemaining = (DateTime.Parse(((PenaltyInfo)p.Value).TimeRemaining) - now).TimeSpanText();
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -52,7 +52,7 @@ namespace WebfrontCore.Controllers
|
|||||||
PunisherId = p.PunisherId,
|
PunisherId = p.PunisherId,
|
||||||
Type = p.Type.ToString(),
|
Type = p.Type.ToString(),
|
||||||
TimePunished = p.When.ToString(),
|
TimePunished = p.When.ToString(),
|
||||||
TimeRemaining = p.Expires.ToString(),
|
TimeRemaining = "",
|
||||||
AutomatedOffense = p.AutomatedOffense
|
AutomatedOffense = p.AutomatedOffense
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ namespace WebfrontCore.ViewComponents
|
|||||||
Type = p.Type.ToString(),
|
Type = p.Type.ToString(),
|
||||||
TimePunished = Utilities.GetTimePassed(p.When, false),
|
TimePunished = Utilities.GetTimePassed(p.When, false),
|
||||||
// show time passed if ban
|
// show time passed if ban
|
||||||
TimeRemaining = DateTime.UtcNow > p.Expires ? "" : $"{(p.Expires.Value.Year == DateTime.MaxValue.Year ? Utilities.GetTimePassed(p.When, true) : Utilities.TimeSpanText(p.Expires.Value - DateTime.UtcNow))}",
|
TimeRemaining = DateTime.UtcNow > p.Expires ? "" : $"{((p.Expires ?? DateTime.MaxValue).Year == DateTime.MaxValue.Year ? Utilities.GetTimePassed(p.When, true) : Utilities.TimeSpanText((p.Expires ?? DateTime.MaxValue) - DateTime.UtcNow))}",
|
||||||
Sensitive = p.Type == Penalty.PenaltyType.Flag,
|
Sensitive = p.Type == Penalty.PenaltyType.Flag,
|
||||||
AutomatedOffense = p.AutomatedOffense
|
AutomatedOffense = p.AutomatedOffense
|
||||||
});
|
});
|
||||||
|
117
_commands.gsc
117
_commands.gsc
@ -1,10 +1,65 @@
|
|||||||
|
#include common_scripts\utility;
|
||||||
#include maps\mp\_utility;
|
#include maps\mp\_utility;
|
||||||
#include maps\mp\gametypes\_hud_util;
|
#include maps\mp\gametypes\_hud_util;
|
||||||
#include common_scripts\utility;
|
#include maps\mp\gametypes\_playerlogic;
|
||||||
|
|
||||||
init()
|
init()
|
||||||
{
|
{
|
||||||
level thread WaitForCommand();
|
SetDvarIfUninitialized("sv_team_balance_assignments", "");
|
||||||
|
SetDvarIfUninitialized("sv_iw4madmin_serverid", 0);
|
||||||
|
SetDvarIfUninitialized("sv_iw4madmin_apiurl", "http://127.0.0.1:1624/api/gsc/");
|
||||||
|
level.apiUrl = GetDvar("sv_iw4madmin_apiurl");
|
||||||
|
//level thread WaitForCommand();
|
||||||
|
level thread onPlayerConnect();
|
||||||
|
level thread onPlayerDisconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
onPlayerConnect()
|
||||||
|
{
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
level waittill( "connected", player );
|
||||||
|
player thread onJoinedTeam();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onPlayerDisconnect()
|
||||||
|
{
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
level waittill( "disconnected", player );
|
||||||
|
logPrint("player disconnected\n");
|
||||||
|
level.players[0] SetTeamBalanceAssignments(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onJoinedTeam()
|
||||||
|
{
|
||||||
|
self endon("disconnect");
|
||||||
|
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
self waittill( "joined_team" );
|
||||||
|
self SetTeamBalanceAssignments(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SetTeamBalanceAssignments(isDisconnect)
|
||||||
|
{
|
||||||
|
assignments = GetDvar("sv_team_balance_assignments");
|
||||||
|
dc = "";
|
||||||
|
if (isDisconnect)
|
||||||
|
{
|
||||||
|
dc = "&isDisconnect=true";
|
||||||
|
}
|
||||||
|
url = level.apiUrl + "GetTeamAssignments/" + self.guid + "/?teams=" + assignments + dc + "&serverId=" + GetDvar("sv_iw4madmin_serverid");
|
||||||
|
newAssignments = GetHttpString(url);
|
||||||
|
SetDvar("sv_team_balance_assignments", newAssignments.data);
|
||||||
|
|
||||||
|
if (newAssignments.success)
|
||||||
|
{
|
||||||
|
BalanceTeams(strtok(newAssignments.data, ","));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
WaitForCommand()
|
WaitForCommand()
|
||||||
@ -33,41 +88,79 @@ WaitForCommand()
|
|||||||
|
|
||||||
SendAlert(clientId, alertType, sound, message)
|
SendAlert(clientId, alertType, sound, message)
|
||||||
{
|
{
|
||||||
client = playerForClientId(clientId);
|
client = getPlayerFromClientNum(clientId);
|
||||||
|
|
||||||
client thread playLeaderDialogOnPlayer(sound, client.team);
|
client thread playLeaderDialogOnPlayer(sound, client.team);
|
||||||
client playLocalSound(sound);
|
client playLocalSound(sound);
|
||||||
client iPrintLnBold("^1" + alertType + ": ^3" + message);
|
client iPrintLnBold("^1" + alertType + ": ^3" + message);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GetHttpString(url)
|
||||||
|
{
|
||||||
|
response = spawnStruct();
|
||||||
|
response.success = false;
|
||||||
|
response.data = undefined;
|
||||||
|
|
||||||
|
logPrint("Making request to " + url + "\n");
|
||||||
|
request = httpGet(url);
|
||||||
|
request waittill("done", success, data);
|
||||||
|
|
||||||
|
if(success != 0){
|
||||||
|
logPrint("Request succeeded\n");
|
||||||
|
response.success = true;
|
||||||
|
response.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
logPrint("Request failed\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
BalanceTeams(commandArgs)
|
BalanceTeams(commandArgs)
|
||||||
{
|
{
|
||||||
if (isRoundBased())
|
if (level.teamBased)
|
||||||
{
|
{
|
||||||
iPrintLnBold("Balancing Teams..");
|
printOnPlayers("^5Balancing Teams...");
|
||||||
|
|
||||||
for (i = 0; i < commandArgs.size; i+= 2)
|
for (i = 0; i < commandArgs.size; i+= 2)
|
||||||
{
|
{
|
||||||
teamNum = commandArgs[i+1];
|
teamNum = int(commandArgs[i+1]);
|
||||||
clientNum = commandArgs[i];
|
clientNum = int(commandArgs[i]);
|
||||||
if (teamNum == "0")
|
|
||||||
|
//printOnPlayers("[" + teamNum + "," + clientNum + "]");
|
||||||
|
|
||||||
|
if (teamNum == 2)
|
||||||
|
{
|
||||||
newTeam = "allies";
|
newTeam = "allies";
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
newTeam = "axis";
|
newTeam = "axis";
|
||||||
player = level.players[clientNum];
|
}
|
||||||
|
|
||||||
if (!isPlayer(player))
|
player = getPlayerFromClientNum(clientNum);
|
||||||
continue;
|
|
||||||
|
|
||||||
iPrintLnBold(player.name + " " + teamNum);
|
//if (!isPlayer(player))
|
||||||
|
// continue;
|
||||||
|
|
||||||
switch (newTeam)
|
switch (newTeam)
|
||||||
{
|
{
|
||||||
case "axis":
|
case "axis":
|
||||||
|
if (player.team != "axis")
|
||||||
|
{
|
||||||
|
//printOnPlayers("moving " + player.name + " to axis");
|
||||||
player[[level.axis]]();
|
player[[level.axis]]();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case "allies":
|
case "allies":
|
||||||
|
if (player.team != "allies")
|
||||||
|
{
|
||||||
|
//printOnPlayers("moving " + player.name + " to allies");
|
||||||
player[[level.allies]]();
|
player[[level.allies]]();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,10 +8,14 @@ init()
|
|||||||
SetDvarIfUninitialized("sv_framewaittime", 0.05);
|
SetDvarIfUninitialized("sv_framewaittime", 0.05);
|
||||||
SetDvarIfUninitialized("sv_additionalwaittime", 0.05);
|
SetDvarIfUninitialized("sv_additionalwaittime", 0.05);
|
||||||
SetDvarIfUninitialized("sv_maxstoredframes", 3);
|
SetDvarIfUninitialized("sv_maxstoredframes", 3);
|
||||||
|
|
||||||
level thread onPlayerConnect();
|
level thread onPlayerConnect();
|
||||||
|
|
||||||
level waittill("prematch_over");
|
level waittill("prematch_over");
|
||||||
level.callbackPlayerKilled = ::Callback_PlayerKilled;
|
level.callbackPlayerKilled = ::Callback_PlayerKilled;
|
||||||
level.callbackPlayerDamage = ::Callback_PlayerDamage;
|
level.callbackPlayerDamage = ::Callback_PlayerDamage;
|
||||||
|
level.callbackPlayerDisconnect = ::Callback_PlayerDisconnect;
|
||||||
|
|
||||||
level.playerTags = [];
|
level.playerTags = [];
|
||||||
level.playerTags[0] = "j_head";
|
level.playerTags[0] = "j_head";
|
||||||
level.playerTags[1] = "j_neck";
|
level.playerTags[1] = "j_neck";
|
||||||
@ -241,3 +245,9 @@ Callback_PlayerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vD
|
|||||||
Process_Hit("Kill", attacker, sHitLoc, sMeansOfDeath, iDamage, sWeapon);
|
Process_Hit("Kill", attacker, sHitLoc, sMeansOfDeath, iDamage, sWeapon);
|
||||||
self maps\mp\gametypes\_damage::Callback_PlayerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration );
|
self maps\mp\gametypes\_damage::Callback_PlayerKilled( eInflictor, attacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, psOffsetTime, deathAnimDuration );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Callback_PlayerDisconnect()
|
||||||
|
{
|
||||||
|
level notify("disconnected", self);
|
||||||
|
self maps\mp\gametypes\_playerlogic::Callback_PlayerDisconnect();
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user