Compare commits
29 Commits
2021.03.23
...
2021.06.07
Author | SHA1 | Date | |
---|---|---|---|
3a1e8359c2 | |||
c397fd5479 | |||
16e1bbb1b5 | |||
eff1fe237d | |||
b09ce46ff9 | |||
be08d49f0a | |||
b9fb274db6 | |||
9488f754d4 | |||
1595c1fa99 | |||
4d21680d59 | |||
127af98b00 | |||
21a9eb8716 | |||
f1593e2f99 | |||
74dbc3572f | |||
e6d149736a | |||
a034394610 | |||
34e7d69110 | |||
4b686e5fdd | |||
0428453426 | |||
e80e5d6a70 | |||
22cf3081e1 | |||
76a18d9797 | |||
fc13363c9c | |||
f916c51bc0 | |||
21087d6c25 | |||
c84e374274 | |||
e777a68105 | |||
1f9c80e23b | |||
33371a6d28 |
@ -48,6 +48,8 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\Integrations\Cod\Integrations.Cod.csproj" />
|
||||||
|
<ProjectReference Include="..\Integrations\Source\Integrations.Source.csproj" />
|
||||||
<ProjectReference Include="..\SharedLibraryCore\SharedLibraryCore.csproj">
|
<ProjectReference Include="..\SharedLibraryCore\SharedLibraryCore.csproj">
|
||||||
<Private>true</Private>
|
<Private>true</Private>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
using IW4MAdmin.Application.EventParsers;
|
using IW4MAdmin.Application.EventParsers;
|
||||||
using IW4MAdmin.Application.Extensions;
|
using IW4MAdmin.Application.Extensions;
|
||||||
using IW4MAdmin.Application.Misc;
|
using IW4MAdmin.Application.Misc;
|
||||||
using IW4MAdmin.Application.RconParsers;
|
using IW4MAdmin.Application.RConParsers;
|
||||||
using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Commands;
|
using SharedLibraryCore.Commands;
|
||||||
using SharedLibraryCore.Configuration;
|
using SharedLibraryCore.Configuration;
|
||||||
@ -220,15 +220,15 @@ namespace IW4MAdmin.Application
|
|||||||
public async Task UpdateServerStates()
|
public async Task UpdateServerStates()
|
||||||
{
|
{
|
||||||
// store the server hash code and task for it
|
// store the server hash code and task for it
|
||||||
var runningUpdateTasks = new Dictionary<long, Task>();
|
var runningUpdateTasks = new Dictionary<long, (Task task, CancellationTokenSource tokenSource, DateTime startTime)>();
|
||||||
|
|
||||||
while (!_tokenSource.IsCancellationRequested)
|
while (!_tokenSource.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
// select the server ids that have completed the update task
|
// select the server ids that have completed the update task
|
||||||
var serverTasksToRemove = runningUpdateTasks
|
var serverTasksToRemove = runningUpdateTasks
|
||||||
.Where(ut => ut.Value.Status == TaskStatus.RanToCompletion ||
|
.Where(ut => ut.Value.task.Status == TaskStatus.RanToCompletion ||
|
||||||
ut.Value.Status == TaskStatus.Canceled ||
|
ut.Value.task.Status == TaskStatus.Canceled || // we want to cancel if a task takes longer than 5 minutes
|
||||||
ut.Value.Status == TaskStatus.Faulted)
|
ut.Value.task.Status == TaskStatus.Faulted || DateTime.Now - ut.Value.startTime > TimeSpan.FromMinutes(5))
|
||||||
.Select(ut => ut.Key)
|
.Select(ut => ut.Key)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
@ -239,9 +239,14 @@ namespace IW4MAdmin.Application
|
|||||||
IsInitialized = true;
|
IsInitialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove the update tasks as they have completd
|
// remove the update tasks as they have completed
|
||||||
foreach (long serverId in serverTasksToRemove)
|
foreach (var serverId in serverTasksToRemove)
|
||||||
{
|
{
|
||||||
|
if (!runningUpdateTasks[serverId].tokenSource.Token.IsCancellationRequested)
|
||||||
|
{
|
||||||
|
runningUpdateTasks[serverId].tokenSource.Cancel();
|
||||||
|
}
|
||||||
|
|
||||||
runningUpdateTasks.Remove(serverId);
|
runningUpdateTasks.Remove(serverId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -249,11 +254,12 @@ namespace IW4MAdmin.Application
|
|||||||
var serverIds = Servers.Select(s => s.EndPoint).Except(runningUpdateTasks.Select(r => r.Key)).ToList();
|
var serverIds = Servers.Select(s => s.EndPoint).Except(runningUpdateTasks.Select(r => r.Key)).ToList();
|
||||||
foreach (var server in Servers.Where(s => serverIds.Contains(s.EndPoint)))
|
foreach (var server in Servers.Where(s => serverIds.Contains(s.EndPoint)))
|
||||||
{
|
{
|
||||||
runningUpdateTasks.Add(server.EndPoint, Task.Run(async () =>
|
var tokenSource = new CancellationTokenSource();
|
||||||
|
runningUpdateTasks.Add(server.EndPoint, (Task.Run(async () =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await server.ProcessUpdatesAsync(_tokenSource.Token);
|
await server.ProcessUpdatesAsync(_tokenSource.Token).WithWaitCancellation(runningUpdateTasks[server.EndPoint].tokenSource.Token);
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
@ -268,7 +274,7 @@ namespace IW4MAdmin.Application
|
|||||||
{
|
{
|
||||||
server.IsInitialized = true;
|
server.IsInitialized = true;
|
||||||
}
|
}
|
||||||
}));
|
}, tokenSource.Token), tokenSource, DateTime.Now));
|
||||||
}
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
|
15
Application/Configuration/ScriptPluginConfiguration.cs
Normal file
15
Application/Configuration/ScriptPluginConfiguration.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
|
||||||
|
namespace IW4MAdmin.Application.Configuration
|
||||||
|
{
|
||||||
|
public class ScriptPluginConfiguration : Dictionary<string, Dictionary<string, object>>, IBaseConfiguration
|
||||||
|
{
|
||||||
|
public string Name() => nameof(ScriptPluginConfiguration);
|
||||||
|
|
||||||
|
public IBaseConfiguration Generate()
|
||||||
|
{
|
||||||
|
return new ScriptPluginConfiguration();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
{
|
{
|
||||||
"AutoMessagePeriod": 60,
|
"AutoMessagePeriod": 60,
|
||||||
"AutoMessages": [
|
"AutoMessages": [
|
||||||
"This server uses ^5IW4M Admin v{{VERSION}} ^7get it at ^5raidmax.org/IW4MAdmin",
|
"This server uses ^5IW4M Admin v{{VERSION}} ^7get it at ^5raidmax.org/IW4MAdmin",
|
||||||
@ -169,6 +169,18 @@
|
|||||||
"Alias": "Asylum",
|
"Alias": "Asylum",
|
||||||
"Name": "mp_asylum"
|
"Name": "mp_asylum"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Banzai",
|
||||||
|
"Name": "mp_kwai"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Battery",
|
||||||
|
"Name": "mp_drum"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Breach",
|
||||||
|
"Name": "mp_bgate"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"Alias": "Castle",
|
"Alias": "Castle",
|
||||||
"Name": "mp_castle"
|
"Name": "mp_castle"
|
||||||
@ -177,6 +189,10 @@
|
|||||||
"Alias": "Cliffside",
|
"Alias": "Cliffside",
|
||||||
"Name": "mp_shrine"
|
"Name": "mp_shrine"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Corrosion",
|
||||||
|
"Name": "mp_stalingrad"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"Alias": "Courtyard",
|
"Alias": "Courtyard",
|
||||||
"Name": "mp_courtyard"
|
"Name": "mp_courtyard"
|
||||||
@ -190,60 +206,52 @@
|
|||||||
"Name": "mp_downfall"
|
"Name": "mp_downfall"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Alias": "Hanger",
|
"Alias": "Hangar",
|
||||||
"Name": "mp_hangar"
|
"Name": "mp_hangar"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"Alias": "Makin",
|
|
||||||
"Name": "mp_makin"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Alias": "Outskirts",
|
|
||||||
"Name": "mp_outskirts"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Alias": "Roundhouse",
|
|
||||||
"Name": "mp_roundhouse"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Alias": "Upheaval",
|
|
||||||
"Name": "mp_suburban"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"Alias": "Knee Deep",
|
"Alias": "Knee Deep",
|
||||||
"Name": "mp_kneedeep"
|
"Name": "mp_kneedeep"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Makin",
|
||||||
|
"Name": "mp_makin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Makin Day",
|
||||||
|
"Name": "mp_makin_day"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"Alias": "Nightfire",
|
"Alias": "Nightfire",
|
||||||
"Name": "mp_nachtfeuer"
|
"Name": "mp_nachtfeuer"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Outskirts",
|
||||||
|
"Name": "mp_outskirts"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Revolution",
|
||||||
|
"Name": "mp_vodka"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Roundhouse",
|
||||||
|
"Name": "mp_roundhouse"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Seelow",
|
||||||
|
"Name": "mp_seelow"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"Alias": "Station",
|
"Alias": "Station",
|
||||||
"Name": "mp_subway"
|
"Name": "mp_subway"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"Alias": "Banzai",
|
|
||||||
"Name": "mp_kwai"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Alias": "Corrosion",
|
|
||||||
"Name": "mp_stalingrad"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"Alias": "Sub Pens",
|
"Alias": "Sub Pens",
|
||||||
"Name": "mp_docks"
|
"Name": "mp_docks"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Alias": "Battery",
|
"Alias": "Upheaval",
|
||||||
"Name": "mp_drum"
|
"Name": "mp_suburban"
|
||||||
},
|
|
||||||
{
|
|
||||||
"Alias": "Breach",
|
|
||||||
"Name": "mp_bgate"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"Alias": "Revolution",
|
|
||||||
"Name": "mp_vodka"
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -687,6 +695,10 @@
|
|||||||
{
|
{
|
||||||
"Alias": "Terminal",
|
"Alias": "Terminal",
|
||||||
"Name": "mp_terminal_cls"
|
"Name": "mp_terminal_cls"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Rust",
|
||||||
|
"Name": "mp_rust"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@ -846,6 +858,280 @@
|
|||||||
"Name": "zm_transit"
|
"Name": "zm_transit"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Game": "IW6",
|
||||||
|
"Maps": [
|
||||||
|
{
|
||||||
|
"Alias": "Prision Break",
|
||||||
|
"Name": "mp_prisonbreak"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Octane",
|
||||||
|
"Name": "mp_dart"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Tremor",
|
||||||
|
"Name": "mp_lonestar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Freight",
|
||||||
|
"Name": "mp_frag"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Whiteout",
|
||||||
|
"Name": "mp_snow"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Stormfront",
|
||||||
|
"Name": "mp_fahrenheit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Siege",
|
||||||
|
"Name": "mp_hashima"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Warhawk",
|
||||||
|
"Name": "mp_warhawk"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Sovereign",
|
||||||
|
"Name": "mp_sovereign"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Overload",
|
||||||
|
"Name": "mp_zebra"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Stonehaven",
|
||||||
|
"Name": "mp_skeleton"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Chasm",
|
||||||
|
"Name": "mp_chasm"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Flooded",
|
||||||
|
"Name": "mp_flooded"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Strikezone",
|
||||||
|
"Name": "mp_strikezone"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Free Fall",
|
||||||
|
"Name": "mp_descent_new"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Unearthed",
|
||||||
|
"Name": "mp_dome_ns"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Collision",
|
||||||
|
"Name": "mp_ca_impact"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Behemoth",
|
||||||
|
"Name": "mp_ca_behemoth"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Ruins",
|
||||||
|
"Name": "mp_battery3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Pharaoh",
|
||||||
|
"Name": "mp_dig"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Favela",
|
||||||
|
"Name": "mp_favela_iw6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Mutiny",
|
||||||
|
"Name": "mp_pirate"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Departed",
|
||||||
|
"Name": "mp_zulu"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Dynasty",
|
||||||
|
"Name": "mp_conflict"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Goldrush",
|
||||||
|
"Name": "mp_mine"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Showtime",
|
||||||
|
"Name": "mp_shipment_ns"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Subzero",
|
||||||
|
"Name": "mp_zerosub"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Ignition",
|
||||||
|
"Name": "mp_boneyard_ns"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Containment",
|
||||||
|
"Name": "mp_ca_red_river"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Bayview",
|
||||||
|
"Name": "mp_ca_rumble"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Fog",
|
||||||
|
"Name": "mp_swamp"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Point of Contact",
|
||||||
|
"Name": "mp_alien_town"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Nightfall",
|
||||||
|
"Name": "mp_alien_armory"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Mayday",
|
||||||
|
"Name": "mp_alien_beacon"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Awakening",
|
||||||
|
"Name": "mp_alien_dlc3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Exodus",
|
||||||
|
"Name": "mp_alien_last"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Game": "SHG1",
|
||||||
|
"Maps": [
|
||||||
|
{
|
||||||
|
"Alias": "Ascend",
|
||||||
|
"Name": "mp_refraction"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Bio Lab",
|
||||||
|
"Name": "mp_lab2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Comeback",
|
||||||
|
"Name": "mp_comeback"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Defender",
|
||||||
|
"Name": "mp_laser2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Detroit",
|
||||||
|
"Name": "mp_detroit"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Greenband",
|
||||||
|
"Name": "mp_greenband"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Horizon",
|
||||||
|
"Name": "mp_levity"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Instinct",
|
||||||
|
"Name": "mp_instinct"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Recovery",
|
||||||
|
"Name": "mp_recovery"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Retreat",
|
||||||
|
"Name": "mp_venus"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Riot",
|
||||||
|
"Name": "mp_prison"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Solar",
|
||||||
|
"Name": "mp_solar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Terrace",
|
||||||
|
"Name": "mp_terrace"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Atlas Gorge",
|
||||||
|
"Name": "mp_dam"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Chop Shop",
|
||||||
|
"Name": "mp_spark"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Climate",
|
||||||
|
"Name": "mp_climate_3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Compound",
|
||||||
|
"Name": "mp_sector17"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Core",
|
||||||
|
"Name": "mp_lost"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Drift",
|
||||||
|
"Name": "mp_torqued"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Fracture",
|
||||||
|
"Name": "mp_fracture"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Kremlin",
|
||||||
|
"Name": "mp_kremlin"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Overload",
|
||||||
|
"Name": "mp_lair"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Parliament",
|
||||||
|
"Name": "mp_bigben2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Perplex",
|
||||||
|
"Name": "mp_perplex_1"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Quarantine",
|
||||||
|
"Name": "mp_liberty"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Sideshow",
|
||||||
|
"Name": "mp_clowntown3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Site 244",
|
||||||
|
"Name": "mp_blackbox"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Skyrise",
|
||||||
|
"Name": "mp_highrise2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Swarn",
|
||||||
|
"Name": "mp_seoul2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Alias": "Urban",
|
||||||
|
"Name": "mp_urban"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"GameStrings": {
|
"GameStrings": {
|
||||||
@ -920,6 +1206,103 @@
|
|||||||
"artillery": "Precision Airstrike",
|
"artillery": "Precision Airstrike",
|
||||||
"player": "",
|
"player": "",
|
||||||
"attach": ""
|
"attach": ""
|
||||||
}
|
},
|
||||||
|
"IW3": {
|
||||||
|
"torso_upper": "Upper Torso",
|
||||||
|
"torso_lower": "Lower Torso",
|
||||||
|
"right_leg_upper": "Upper Right Leg",
|
||||||
|
"right_leg_lower": "Lower Right Leg",
|
||||||
|
"right_hand": "Right Hand",
|
||||||
|
"right_foot": "Right Foot",
|
||||||
|
"right_arm_upper": "Upper Right Arm",
|
||||||
|
"right_arm_lower": "Lower Right Arm",
|
||||||
|
"left_leg_upper": "Upper Left Leg",
|
||||||
|
"left_leg_lower": "Lower Left Leg",
|
||||||
|
"left_hand": "Left Hand",
|
||||||
|
"left_foot": "Left Foot",
|
||||||
|
"left_arm_upper": "Upper Left Arm",
|
||||||
|
"left_arm_lower": "Lower Left Arm",
|
||||||
|
"acog": "ACOG Sight",
|
||||||
|
"gl": "Grenade Launcher",
|
||||||
|
"reflex": "Red Dot Sight",
|
||||||
|
"grip": "Grip",
|
||||||
|
"m4": "M4 Carbine",
|
||||||
|
"m40a3": "M40A3",
|
||||||
|
"ak47": "AK-47",
|
||||||
|
"ak74u": "AK-74u",
|
||||||
|
"rpg": "RPG-7",
|
||||||
|
"deserteagle": "Desert Eagle",
|
||||||
|
"deserteaglegold": "Desert Eagle Gold",
|
||||||
|
"m16": "M16A4",
|
||||||
|
"g36c": "G36C",
|
||||||
|
"uzi": "Mini-Uzi",
|
||||||
|
"m60e4": "M60E4",
|
||||||
|
"mp5": "MP5",
|
||||||
|
"barrett": "Barrett .50cal",
|
||||||
|
"mp44": "MP44",
|
||||||
|
"remington700": "R700",
|
||||||
|
"rpd": "RDP",
|
||||||
|
"saw": " M249 SAW",
|
||||||
|
"usp": "USP .45",
|
||||||
|
"winchester1200": "W1200",
|
||||||
|
"concussion": "Stun",
|
||||||
|
"melee": "Knife",
|
||||||
|
"Frag" : "Grenade",
|
||||||
|
"airstrike": "Airstrike",
|
||||||
|
"helicopter": "Attack Helicopter",
|
||||||
|
"player": "",
|
||||||
|
"attach": ""
|
||||||
|
},
|
||||||
|
"T4": {
|
||||||
|
"torso_upper": "Upper Torso",
|
||||||
|
"torso_lower": "Lower Torso",
|
||||||
|
"right_leg_upper": "Upper Right Leg",
|
||||||
|
"right_leg_lower": "Lower Right Leg",
|
||||||
|
"right_hand": "Right Hand",
|
||||||
|
"right_foot": "Right Foot",
|
||||||
|
"right_arm_upper": "Upper Right Arm",
|
||||||
|
"right_arm_lower": "Lower Right Arm",
|
||||||
|
"left_leg_upper": "Upper Left Leg",
|
||||||
|
"left_leg_lower": "Lower Left Leg",
|
||||||
|
"left_hand": "Left Hand",
|
||||||
|
"left_foot": "Left Foot",
|
||||||
|
"left_arm_upper": "Upper Left Arm",
|
||||||
|
"left_arm_lower": "Lower Left Arm",
|
||||||
|
"gl": "Rifle Grenade",
|
||||||
|
"bigammo": "Round Drum",
|
||||||
|
"scoped": "Sniper Scope",
|
||||||
|
"telescopic": "Telescopic Sight",
|
||||||
|
"aperture": "Aperture Sight",
|
||||||
|
"flash": "Flash Hider",
|
||||||
|
"silenced": "Silencer",
|
||||||
|
"molotov": "Molotov Cocktail",
|
||||||
|
"sticky": "N° 74 ST",
|
||||||
|
"m2": "M2 Flamethrower",
|
||||||
|
"artillery": "Artillery Strike",
|
||||||
|
"dog": "Attack Dogs",
|
||||||
|
"colt": "Colt M1911",
|
||||||
|
"357magnum": ".357 Magnum",
|
||||||
|
"walther": "Walther P38",
|
||||||
|
"tokarev": "Tokarev TT-33",
|
||||||
|
"shotgun": "M1897 Trench Gun",
|
||||||
|
"doublebarreledshotgun": "Double-Barreled Shotgun",
|
||||||
|
"mp40": "MP40",
|
||||||
|
"type100smg": "Type 100",
|
||||||
|
"ppsh": "PPSh-41",
|
||||||
|
"svt40": "SVT-40",
|
||||||
|
"gewehr43": "Gewehr 43",
|
||||||
|
"m1garand": "M1 Garand",
|
||||||
|
"stg44": "STG-44",
|
||||||
|
"m1carbine": "M1A1 Carbine",
|
||||||
|
"type99lmg": "Type 99",
|
||||||
|
"bar": "BAR",
|
||||||
|
"dp28": "DP-28",
|
||||||
|
"mg42": "MG42",
|
||||||
|
"fg42": "FG42",
|
||||||
|
"30cal": "Browning M1919",
|
||||||
|
"type99rifle": "Arisaka",
|
||||||
|
"mosinrifle": "Mosin-Nagant",
|
||||||
|
"ptrs41":"PTRS-41"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,6 +17,8 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
private readonly Dictionary<string, (string, Func<string, IEventParserConfiguration, GameEvent, GameEvent>)> _customEventRegistrations;
|
private readonly Dictionary<string, (string, Func<string, IEventParserConfiguration, GameEvent, GameEvent>)> _customEventRegistrations;
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly ApplicationConfiguration _appConfig;
|
private readonly ApplicationConfiguration _appConfig;
|
||||||
|
private readonly Dictionary<ParserRegex, GameEvent.EventType> _regexMap;
|
||||||
|
private readonly Dictionary<string, GameEvent.EventType> _eventTypeMap;
|
||||||
|
|
||||||
public BaseEventParser(IParserRegexFactory parserRegexFactory, ILogger logger, ApplicationConfiguration appConfig)
|
public BaseEventParser(IParserRegexFactory parserRegexFactory, ILogger logger, ApplicationConfiguration appConfig)
|
||||||
{
|
{
|
||||||
@ -78,7 +80,28 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
Configuration.Kill.AddMapping(ParserRegex.GroupType.MeansOfDeath, 12);
|
Configuration.Kill.AddMapping(ParserRegex.GroupType.MeansOfDeath, 12);
|
||||||
Configuration.Kill.AddMapping(ParserRegex.GroupType.HitLocation, 13);
|
Configuration.Kill.AddMapping(ParserRegex.GroupType.HitLocation, 13);
|
||||||
|
|
||||||
|
Configuration.MapChange.Pattern = @".*InitGame.*";
|
||||||
|
Configuration.MapEnd.Pattern = @".*(?:ExitLevel|ShutdownGame).*";
|
||||||
|
|
||||||
Configuration.Time.Pattern = @"^ *(([0-9]+):([0-9]+) |^[0-9]+ )";
|
Configuration.Time.Pattern = @"^ *(([0-9]+):([0-9]+) |^[0-9]+ )";
|
||||||
|
|
||||||
|
_regexMap = new Dictionary<ParserRegex, GameEvent.EventType>
|
||||||
|
{
|
||||||
|
{Configuration.Say, GameEvent.EventType.Say},
|
||||||
|
{Configuration.Kill, GameEvent.EventType.Kill},
|
||||||
|
{Configuration.MapChange, GameEvent.EventType.MapChange},
|
||||||
|
{Configuration.MapEnd, GameEvent.EventType.MapEnd}
|
||||||
|
};
|
||||||
|
|
||||||
|
_eventTypeMap = new Dictionary<string, GameEvent.EventType>
|
||||||
|
{
|
||||||
|
{"say", GameEvent.EventType.Say},
|
||||||
|
{"sayteam", GameEvent.EventType.Say},
|
||||||
|
{"K", GameEvent.EventType.Kill},
|
||||||
|
{"D", GameEvent.EventType.Damage},
|
||||||
|
{"J", GameEvent.EventType.PreConnect},
|
||||||
|
{"Q", GameEvent.EventType.PreDisconnect},
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEventParserConfiguration Configuration { get; set; }
|
public IEventParserConfiguration Configuration { get; set; }
|
||||||
@ -91,6 +114,28 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
|
|
||||||
public string Name { get; set; } = "Call of Duty";
|
public string Name { get; set; } = "Call of Duty";
|
||||||
|
|
||||||
|
private (GameEvent.EventType type, string eventKey) GetEventTypeFromLine(string logLine)
|
||||||
|
{
|
||||||
|
var lineSplit = logLine.Split(';');
|
||||||
|
if (lineSplit.Length > 1)
|
||||||
|
{
|
||||||
|
var type = lineSplit[0];
|
||||||
|
return _eventTypeMap.ContainsKey(type) ? (_eventTypeMap[type], type): (GameEvent.EventType.Unknown, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var (key, value) in _regexMap)
|
||||||
|
{
|
||||||
|
var result = key.PatternMatcher.Match(logLine);
|
||||||
|
if (result.Success)
|
||||||
|
{
|
||||||
|
return (value, null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (GameEvent.EventType.Unknown, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public virtual GameEvent GenerateGameEvent(string logLine)
|
public virtual GameEvent GenerateGameEvent(string logLine)
|
||||||
{
|
{
|
||||||
var timeMatch = Configuration.Time.PatternMatcher.Match(logLine);
|
var timeMatch = Configuration.Time.PatternMatcher.Match(logLine);
|
||||||
@ -104,7 +149,7 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
.Values
|
.Values
|
||||||
.Skip(2)
|
.Skip(2)
|
||||||
// this converts the timestamp into seconds passed
|
// this converts the timestamp into seconds passed
|
||||||
.Select((_value, index) => long.Parse(_value.ToString()) * (index == 0 ? 60 : 1))
|
.Select((value, index) => long.Parse(value.ToString()) * (index == 0 ? 60 : 1))
|
||||||
.Sum();
|
.Sum();
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -114,33 +159,34 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
}
|
}
|
||||||
|
|
||||||
// we want to strip the time from the log line
|
// we want to strip the time from the log line
|
||||||
logLine = logLine.Substring(timeMatch.Values.First().Length);
|
logLine = logLine.Substring(timeMatch.Values.First().Length).Trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
string[] lineSplit = logLine.Split(';');
|
var eventParseResult = GetEventTypeFromLine(logLine);
|
||||||
string eventType = lineSplit[0];
|
var eventType = eventParseResult.type;
|
||||||
|
|
||||||
if (eventType == "say" || eventType == "sayteam")
|
_logger.LogDebug(logLine);
|
||||||
|
|
||||||
|
if (eventType == GameEvent.EventType.Say)
|
||||||
{
|
{
|
||||||
var matchResult = Configuration.Say.PatternMatcher.Match(logLine);
|
var matchResult = Configuration.Say.PatternMatcher.Match(logLine);
|
||||||
|
|
||||||
if (matchResult.Success)
|
if (matchResult.Success)
|
||||||
{
|
{
|
||||||
string message = matchResult.Values[Configuration.Say.GroupMapping[ParserRegex.GroupType.Message]]
|
var message = matchResult.Values[Configuration.Say.GroupMapping[ParserRegex.GroupType.Message]]
|
||||||
.ToString()
|
|
||||||
.Replace("\x15", "")
|
.Replace("\x15", "")
|
||||||
.Trim();
|
.Trim();
|
||||||
|
|
||||||
if (message.Length > 0)
|
if (message.Length > 0)
|
||||||
{
|
{
|
||||||
string originIdString = matchResult.Values[Configuration.Say.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString();
|
var originIdString = matchResult.Values[Configuration.Say.GroupMapping[ParserRegex.GroupType.OriginNetworkId]];
|
||||||
string originName = matchResult.Values[Configuration.Say.GroupMapping[ParserRegex.GroupType.OriginName]].ToString();
|
var originName = matchResult.Values[Configuration.Say.GroupMapping[ParserRegex.GroupType.OriginName]];
|
||||||
|
|
||||||
long originId = originIdString.IsBotGuid() ?
|
var originId = originIdString.IsBotGuid() ?
|
||||||
originName.GenerateGuidFromString() :
|
originName.GenerateGuidFromString() :
|
||||||
originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle);
|
originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle);
|
||||||
|
|
||||||
int clientNumber = int.Parse(matchResult.Values[Configuration.Say.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]);
|
var clientNumber = int.Parse(matchResult.Values[Configuration.Say.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]);
|
||||||
|
|
||||||
if (message.StartsWith(_appConfig.CommandPrefix) || message.StartsWith(_appConfig.BroadcastCommandPrefix))
|
if (message.StartsWith(_appConfig.CommandPrefix) || message.StartsWith(_appConfig.BroadcastCommandPrefix))
|
||||||
{
|
{
|
||||||
@ -172,26 +218,26 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eventType == "K")
|
if (eventType == GameEvent.EventType.Kill)
|
||||||
{
|
{
|
||||||
var match = Configuration.Kill.PatternMatcher.Match(logLine);
|
var match = Configuration.Kill.PatternMatcher.Match(logLine);
|
||||||
|
|
||||||
if (match.Success)
|
if (match.Success)
|
||||||
{
|
{
|
||||||
string originIdString = match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString();
|
var originIdString = match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.OriginNetworkId]];
|
||||||
string targetIdString = match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.TargetNetworkId]].ToString();
|
var targetIdString = match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.TargetNetworkId]];
|
||||||
string originName = match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.OriginName]].ToString();
|
var originName = match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.OriginName]];
|
||||||
string targetName = match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.TargetName]].ToString();
|
var targetName = match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.TargetName]];
|
||||||
|
|
||||||
long originId = originIdString.IsBotGuid() ?
|
var originId = originIdString.IsBotGuid() ?
|
||||||
originName.GenerateGuidFromString() :
|
originName.GenerateGuidFromString() :
|
||||||
originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle, Utilities.WORLD_ID);
|
originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle, Utilities.WORLD_ID);
|
||||||
long targetId = targetIdString.IsBotGuid() ?
|
var targetId = targetIdString.IsBotGuid() ?
|
||||||
targetName.GenerateGuidFromString() :
|
targetName.GenerateGuidFromString() :
|
||||||
targetIdString.ConvertGuidToLong(Configuration.GuidNumberStyle, Utilities.WORLD_ID);
|
targetIdString.ConvertGuidToLong(Configuration.GuidNumberStyle, Utilities.WORLD_ID);
|
||||||
|
|
||||||
int originClientNumber = int.Parse(match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]);
|
var originClientNumber = int.Parse(match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]);
|
||||||
int targetClientNumber = int.Parse(match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.TargetClientNumber]]);
|
var targetClientNumber = int.Parse(match.Values[Configuration.Kill.GroupMapping[ParserRegex.GroupType.TargetClientNumber]]);
|
||||||
|
|
||||||
return new GameEvent()
|
return new GameEvent()
|
||||||
{
|
{
|
||||||
@ -206,26 +252,26 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eventType == "D")
|
if (eventType == GameEvent.EventType.Damage)
|
||||||
{
|
{
|
||||||
var match = Configuration.Damage.PatternMatcher.Match(logLine);
|
var match = Configuration.Damage.PatternMatcher.Match(logLine);
|
||||||
|
|
||||||
if (match.Success)
|
if (match.Success)
|
||||||
{
|
{
|
||||||
string originIdString = match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString();
|
var originIdString = match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.OriginNetworkId]];
|
||||||
string targetIdString = match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.TargetNetworkId]].ToString();
|
var targetIdString = match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.TargetNetworkId]];
|
||||||
string originName = match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.OriginName]].ToString();
|
var originName = match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.OriginName]];
|
||||||
string targetName = match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.TargetName]].ToString();
|
var targetName = match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.TargetName]];
|
||||||
|
|
||||||
long originId = originIdString.IsBotGuid() ?
|
var originId = originIdString.IsBotGuid() ?
|
||||||
originName.GenerateGuidFromString() :
|
originName.GenerateGuidFromString() :
|
||||||
originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle, Utilities.WORLD_ID);
|
originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle, Utilities.WORLD_ID);
|
||||||
long targetId = targetIdString.IsBotGuid() ?
|
var targetId = targetIdString.IsBotGuid() ?
|
||||||
targetName.GenerateGuidFromString() :
|
targetName.GenerateGuidFromString() :
|
||||||
targetIdString.ConvertGuidToLong(Configuration.GuidNumberStyle, Utilities.WORLD_ID);
|
targetIdString.ConvertGuidToLong(Configuration.GuidNumberStyle, Utilities.WORLD_ID);
|
||||||
|
|
||||||
int originClientNumber = int.Parse(match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]);
|
var originClientNumber = int.Parse(match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]);
|
||||||
int targetClientNumber = int.Parse(match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.TargetClientNumber]]);
|
var targetClientNumber = int.Parse(match.Values[Configuration.Damage.GroupMapping[ParserRegex.GroupType.TargetClientNumber]]);
|
||||||
|
|
||||||
return new GameEvent()
|
return new GameEvent()
|
||||||
{
|
{
|
||||||
@ -240,16 +286,16 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eventType == "J")
|
if (eventType == GameEvent.EventType.PreConnect)
|
||||||
{
|
{
|
||||||
var match = Configuration.Join.PatternMatcher.Match(logLine);
|
var match = Configuration.Join.PatternMatcher.Match(logLine);
|
||||||
|
|
||||||
if (match.Success)
|
if (match.Success)
|
||||||
{
|
{
|
||||||
string originIdString = match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString();
|
var originIdString = match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginNetworkId]];
|
||||||
string originName = match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginName]].ToString();
|
var originName = match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginName]];
|
||||||
|
|
||||||
long networkId = originIdString.IsBotGuid() ?
|
var networkId = originIdString.IsBotGuid() ?
|
||||||
originName.GenerateGuidFromString() :
|
originName.GenerateGuidFromString() :
|
||||||
originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle);
|
originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle);
|
||||||
|
|
||||||
@ -261,10 +307,10 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
{
|
{
|
||||||
CurrentAlias = new EFAlias()
|
CurrentAlias = new EFAlias()
|
||||||
{
|
{
|
||||||
Name = match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginName]].ToString().TrimNewLine(),
|
Name = match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginName]].TrimNewLine(),
|
||||||
},
|
},
|
||||||
NetworkId = networkId,
|
NetworkId = networkId,
|
||||||
ClientNumber = Convert.ToInt32(match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginClientNumber]].ToString()),
|
ClientNumber = Convert.ToInt32(match.Values[Configuration.Join.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]),
|
||||||
State = EFClient.ClientState.Connecting,
|
State = EFClient.ClientState.Connecting,
|
||||||
},
|
},
|
||||||
Extra = originIdString,
|
Extra = originIdString,
|
||||||
@ -276,16 +322,16 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eventType == "Q")
|
if (eventType == GameEvent.EventType.PreDisconnect)
|
||||||
{
|
{
|
||||||
var match = Configuration.Quit.PatternMatcher.Match(logLine);
|
var match = Configuration.Quit.PatternMatcher.Match(logLine);
|
||||||
|
|
||||||
if (match.Success)
|
if (match.Success)
|
||||||
{
|
{
|
||||||
string originIdString = match.Values[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginNetworkId]].ToString();
|
var originIdString = match.Values[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginNetworkId]];
|
||||||
string originName = match.Values[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginName]].ToString();
|
var originName = match.Values[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginName]];
|
||||||
|
|
||||||
long networkId = originIdString.IsBotGuid() ?
|
var networkId = originIdString.IsBotGuid() ?
|
||||||
originName.GenerateGuidFromString() :
|
originName.GenerateGuidFromString() :
|
||||||
originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle);
|
originIdString.ConvertGuidToLong(Configuration.GuidNumberStyle);
|
||||||
|
|
||||||
@ -297,10 +343,10 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
{
|
{
|
||||||
CurrentAlias = new EFAlias()
|
CurrentAlias = new EFAlias()
|
||||||
{
|
{
|
||||||
Name = match.Values[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginName]].ToString().TrimNewLine()
|
Name = match.Values[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginName]].TrimNewLine()
|
||||||
},
|
},
|
||||||
NetworkId = networkId,
|
NetworkId = networkId,
|
||||||
ClientNumber = Convert.ToInt32(match.Values[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginClientNumber]].ToString()),
|
ClientNumber = Convert.ToInt32(match.Values[Configuration.Quit.GroupMapping[ParserRegex.GroupType.OriginClientNumber]]),
|
||||||
State = EFClient.ClientState.Disconnecting
|
State = EFClient.ClientState.Disconnecting
|
||||||
},
|
},
|
||||||
RequiredEntity = GameEvent.EventRequiredEntity.None,
|
RequiredEntity = GameEvent.EventRequiredEntity.None,
|
||||||
@ -311,7 +357,7 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eventType.Contains("ExitLevel") || eventType.Contains("ShutdownGame"))
|
if (eventType == GameEvent.EventType.MapEnd)
|
||||||
{
|
{
|
||||||
return new GameEvent()
|
return new GameEvent()
|
||||||
{
|
{
|
||||||
@ -325,9 +371,9 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (eventType.Contains("InitGame"))
|
if (eventType == GameEvent.EventType.MapChange)
|
||||||
{
|
{
|
||||||
string dump = eventType.Replace("InitGame: ", "");
|
var dump = logLine.Replace("InitGame: ", "");
|
||||||
|
|
||||||
return new GameEvent()
|
return new GameEvent()
|
||||||
{
|
{
|
||||||
@ -342,26 +388,37 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_customEventRegistrations.ContainsKey(eventType))
|
if (eventParseResult.eventKey == null || !_customEventRegistrations.ContainsKey(eventParseResult.eventKey))
|
||||||
{
|
{
|
||||||
var eventModifier = _customEventRegistrations[eventType];
|
return new GameEvent()
|
||||||
|
|
||||||
try
|
|
||||||
{
|
{
|
||||||
return eventModifier.Item2(logLine, Configuration, new GameEvent()
|
Type = GameEvent.EventType.Unknown,
|
||||||
{
|
Data = logLine,
|
||||||
Type = GameEvent.EventType.Other,
|
Origin = Utilities.IW4MAdminClient(),
|
||||||
Data = logLine,
|
Target = Utilities.IW4MAdminClient(),
|
||||||
Subtype = eventModifier.Item1,
|
RequiredEntity = GameEvent.EventRequiredEntity.None,
|
||||||
GameTime = gameTime,
|
GameTime = gameTime,
|
||||||
Source = GameEvent.EventSource.Log
|
Source = GameEvent.EventSource.Log
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
catch (Exception e)
|
var eventModifier = _customEventRegistrations[eventParseResult.eventKey];
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
return eventModifier.Item2(logLine, Configuration, new GameEvent()
|
||||||
{
|
{
|
||||||
_logger.LogError(e, $"Could not handle custom event generation");
|
Type = GameEvent.EventType.Other,
|
||||||
}
|
Data = logLine,
|
||||||
|
Subtype = eventModifier.Item1,
|
||||||
|
GameTime = gameTime,
|
||||||
|
Source = GameEvent.EventSource.Log
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.LogError(e, "Could not handle custom event generation");
|
||||||
}
|
}
|
||||||
|
|
||||||
return new GameEvent()
|
return new GameEvent()
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using SharedLibraryCore;
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.EventParsers
|
namespace IW4MAdmin.Application.EventParsers
|
||||||
{
|
{
|
||||||
@ -17,6 +18,8 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
public ParserRegex Damage { get; set; }
|
public ParserRegex Damage { get; set; }
|
||||||
public ParserRegex Action { get; set; }
|
public ParserRegex Action { get; set; }
|
||||||
public ParserRegex Time { get; set; }
|
public ParserRegex Time { get; set; }
|
||||||
|
public ParserRegex MapChange { get; set; }
|
||||||
|
public ParserRegex MapEnd { get; set; }
|
||||||
public NumberStyles GuidNumberStyle { get; set; } = NumberStyles.HexNumber;
|
public NumberStyles GuidNumberStyle { get; set; } = NumberStyles.HexNumber;
|
||||||
|
|
||||||
public DynamicEventParserConfiguration(IParserRegexFactory parserRegexFactory)
|
public DynamicEventParserConfiguration(IParserRegexFactory parserRegexFactory)
|
||||||
@ -28,6 +31,8 @@ namespace IW4MAdmin.Application.EventParsers
|
|||||||
Damage = parserRegexFactory.CreateParserRegex();
|
Damage = parserRegexFactory.CreateParserRegex();
|
||||||
Action = parserRegexFactory.CreateParserRegex();
|
Action = parserRegexFactory.CreateParserRegex();
|
||||||
Time = parserRegexFactory.CreateParserRegex();
|
Time = parserRegexFactory.CreateParserRegex();
|
||||||
|
MapChange = parserRegexFactory.CreateParserRegex();
|
||||||
|
MapEnd = parserRegexFactory.CreateParserRegex();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,10 @@
|
|||||||
using IW4MAdmin.Application.RCon;
|
using System;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using Integrations.Cod;
|
||||||
|
using Integrations.Source;
|
||||||
|
using Integrations.Source.Interfaces;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.Factories
|
namespace IW4MAdmin.Application.Factories
|
||||||
@ -10,16 +14,16 @@ namespace IW4MAdmin.Application.Factories
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal class RConConnectionFactory : IRConConnectionFactory
|
internal class RConConnectionFactory : IRConConnectionFactory
|
||||||
{
|
{
|
||||||
private static readonly Encoding gameEncoding = Encoding.GetEncoding("windows-1252");
|
private static readonly Encoding GameEncoding = Encoding.GetEncoding("windows-1252");
|
||||||
private readonly ILogger<RConConnection> _logger;
|
private readonly IServiceProvider _serviceProvider;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Base constructor
|
/// Base constructor
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="logger"></param>
|
/// <param name="logger"></param>
|
||||||
public RConConnectionFactory(ILogger<RConConnection> logger)
|
public RConConnectionFactory(IServiceProvider serviceProvider)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_serviceProvider = serviceProvider;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -29,9 +33,16 @@ namespace IW4MAdmin.Application.Factories
|
|||||||
/// <param name="port">port of the server</param>
|
/// <param name="port">port of the server</param>
|
||||||
/// <param name="password">rcon password of the server</param>
|
/// <param name="password">rcon password of the server</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public IRConConnection CreateConnection(string ipAddress, int port, string password)
|
public IRConConnection CreateConnection(string ipAddress, int port, string password, string rconEngine)
|
||||||
{
|
{
|
||||||
return new RConConnection(ipAddress, port, password, _logger, gameEncoding);
|
return rconEngine switch
|
||||||
|
{
|
||||||
|
"COD" => new CodRConConnection(ipAddress, port, password,
|
||||||
|
_serviceProvider.GetRequiredService<ILogger<CodRConConnection>>(), GameEncoding),
|
||||||
|
"Source" => new SourceRConConnection(_serviceProvider.GetRequiredService<ILogger<SourceRConConnection>>(),
|
||||||
|
_serviceProvider.GetRequiredService<IRConClientFactory>(), ipAddress, port, password),
|
||||||
|
_ => throw new ArgumentException($"No supported RCon engine available for '{rconEngine}'")
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -74,6 +74,8 @@ namespace IW4MAdmin
|
|||||||
client = await Manager.GetClientService().Create(clientFromLog);
|
client = await Manager.GetClientService().Create(clientFromLog);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
client.CopyAdditionalProperties(clientFromLog);
|
||||||
|
|
||||||
// this is only a temporary version until the IPAddress is transmitted
|
// this is only a temporary version until the IPAddress is transmitted
|
||||||
client.CurrentAlias = new EFAlias()
|
client.CurrentAlias = new EFAlias()
|
||||||
{
|
{
|
||||||
@ -739,11 +741,11 @@ namespace IW4MAdmin
|
|||||||
/// array index 2 = updated clients
|
/// array index 2 = updated clients
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
async Task<IList<EFClient>[]> PollPlayersAsync()
|
async Task<List<EFClient>[]> PollPlayersAsync()
|
||||||
{
|
{
|
||||||
var currentClients = GetClientsAsList();
|
var currentClients = GetClientsAsList();
|
||||||
var statusResponse = (await this.GetStatusAsync());
|
var statusResponse = (await this.GetStatusAsync());
|
||||||
var polledClients = statusResponse.Item1.AsEnumerable();
|
var polledClients = statusResponse.Clients.AsEnumerable();
|
||||||
|
|
||||||
if (Manager.GetApplicationSettings().Configuration().IgnoreBots)
|
if (Manager.GetApplicationSettings().Configuration().IgnoreBots)
|
||||||
{
|
{
|
||||||
@ -753,10 +755,12 @@ namespace IW4MAdmin
|
|||||||
var connectingClients = polledClients.Except(currentClients);
|
var connectingClients = polledClients.Except(currentClients);
|
||||||
var updatedClients = polledClients.Except(connectingClients).Except(disconnectingClients);
|
var updatedClients = polledClients.Except(connectingClients).Except(disconnectingClients);
|
||||||
|
|
||||||
UpdateMap(statusResponse.Item2);
|
UpdateMap(statusResponse.Map);
|
||||||
UpdateGametype(statusResponse.Item3);
|
UpdateGametype(statusResponse.GameType);
|
||||||
|
UpdateHostname(statusResponse.Hostname);
|
||||||
|
UpdateMaxPlayers(statusResponse.MaxClients);
|
||||||
|
|
||||||
return new List<EFClient>[]
|
return new []
|
||||||
{
|
{
|
||||||
connectingClients.ToList(),
|
connectingClients.ToList(),
|
||||||
disconnectingClients.ToList(),
|
disconnectingClients.ToList(),
|
||||||
@ -803,6 +807,36 @@ namespace IW4MAdmin
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UpdateHostname(string hostname)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(hostname) || Hostname == hostname)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using(LogContext.PushProperty("Server", ToString()))
|
||||||
|
{
|
||||||
|
ServerLogger.LogDebug("Updating hostname to {HostName}", hostname);
|
||||||
|
}
|
||||||
|
|
||||||
|
Hostname = hostname;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateMaxPlayers(int? maxPlayers)
|
||||||
|
{
|
||||||
|
if (maxPlayers == null || maxPlayers == MaxClients)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
using(LogContext.PushProperty("Server", ToString()))
|
||||||
|
{
|
||||||
|
ServerLogger.LogDebug("Updating max clients to {MaxPlayers}", maxPlayers);
|
||||||
|
}
|
||||||
|
|
||||||
|
MaxClients = maxPlayers.Value;
|
||||||
|
}
|
||||||
|
|
||||||
private async Task ShutdownInternal()
|
private async Task ShutdownInternal()
|
||||||
{
|
{
|
||||||
foreach (var client in GetClientsAsList())
|
foreach (var client in GetClientsAsList())
|
||||||
@ -1011,11 +1045,12 @@ namespace IW4MAdmin
|
|||||||
RconParser = RconParser ?? Manager.AdditionalRConParsers[0];
|
RconParser = RconParser ?? Manager.AdditionalRConParsers[0];
|
||||||
EventParser = EventParser ?? Manager.AdditionalEventParsers[0];
|
EventParser = EventParser ?? Manager.AdditionalEventParsers[0];
|
||||||
|
|
||||||
|
RemoteConnection = RConConnectionFactory.CreateConnection(IP, Port, Password, RconParser.RConEngine);
|
||||||
RemoteConnection.SetConfiguration(RconParser);
|
RemoteConnection.SetConfiguration(RconParser);
|
||||||
|
|
||||||
var version = await this.GetMappedDvarValueOrDefaultAsync<string>("version");
|
var version = await this.GetMappedDvarValueOrDefaultAsync<string>("version");
|
||||||
Version = version.Value;
|
Version = version.Value;
|
||||||
GameName = Utilities.GetGame(version?.Value ?? RconParser.Version);
|
GameName = Utilities.GetGame(version.Value ?? RconParser.Version);
|
||||||
|
|
||||||
if (GameName == Game.UKN)
|
if (GameName == Game.UKN)
|
||||||
{
|
{
|
||||||
@ -1142,12 +1177,12 @@ namespace IW4MAdmin
|
|||||||
GameDirectory = EventParser.Configuration.GameDirectory ?? "",
|
GameDirectory = EventParser.Configuration.GameDirectory ?? "",
|
||||||
ModDirectory = game.Value ?? "",
|
ModDirectory = game.Value ?? "",
|
||||||
LogFile = logfile.Value,
|
LogFile = logfile.Value,
|
||||||
IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows)
|
IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows),
|
||||||
|
IsOneLog = RconParser.IsOneLog
|
||||||
};
|
};
|
||||||
LogPath = GenerateLogPath(logInfo);
|
LogPath = GenerateLogPath(logInfo);
|
||||||
ServerLogger.LogInformation("Game log information {@logInfo}", logInfo);
|
ServerLogger.LogInformation("Game log information {@logInfo}", logInfo);
|
||||||
|
|
||||||
|
|
||||||
if (!File.Exists(LogPath) && ServerConfig.GameLogServerUrl == null)
|
if (!File.Exists(LogPath) && ServerConfig.GameLogServerUrl == null)
|
||||||
{
|
{
|
||||||
Console.WriteLine(loc["SERVER_ERROR_DNE"].FormatExt(LogPath));
|
Console.WriteLine(loc["SERVER_ERROR_DNE"].FormatExt(LogPath));
|
||||||
@ -1172,7 +1207,7 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
public Uri[] GenerateUriForLog(string logPath, string gameLogServerUrl)
|
public Uri[] GenerateUriForLog(string logPath, string gameLogServerUrl)
|
||||||
{
|
{
|
||||||
var logUri = new Uri(logPath);
|
var logUri = new Uri(logPath, UriKind.Absolute);
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(gameLogServerUrl))
|
if (string.IsNullOrEmpty(gameLogServerUrl))
|
||||||
{
|
{
|
||||||
@ -1188,12 +1223,12 @@ namespace IW4MAdmin
|
|||||||
public static string GenerateLogPath(LogPathGeneratorInfo logInfo)
|
public static string GenerateLogPath(LogPathGeneratorInfo logInfo)
|
||||||
{
|
{
|
||||||
string logPath;
|
string logPath;
|
||||||
string workingDirectory = logInfo.BasePathDirectory;
|
var workingDirectory = logInfo.BasePathDirectory;
|
||||||
|
|
||||||
bool baseGameIsDirectory = !string.IsNullOrWhiteSpace(logInfo.BaseGameDirectory) &&
|
var baseGameIsDirectory = !string.IsNullOrWhiteSpace(logInfo.BaseGameDirectory) &&
|
||||||
logInfo.BaseGameDirectory.IndexOfAny(Utilities.DirectorySeparatorChars) != -1;
|
logInfo.BaseGameDirectory.IndexOfAny(Utilities.DirectorySeparatorChars) != -1;
|
||||||
|
|
||||||
bool baseGameIsRelative = logInfo.BaseGameDirectory.FixDirectoryCharacters()
|
var baseGameIsRelative = logInfo.BaseGameDirectory.FixDirectoryCharacters()
|
||||||
.Equals(logInfo.GameDirectory.FixDirectoryCharacters(), StringComparison.InvariantCultureIgnoreCase);
|
.Equals(logInfo.GameDirectory.FixDirectoryCharacters(), StringComparison.InvariantCultureIgnoreCase);
|
||||||
|
|
||||||
// we want to see if base game is provided and it 'looks' like a directory
|
// we want to see if base game is provided and it 'looks' like a directory
|
||||||
@ -1202,7 +1237,7 @@ namespace IW4MAdmin
|
|||||||
workingDirectory = logInfo.BaseGameDirectory;
|
workingDirectory = logInfo.BaseGameDirectory;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(logInfo.ModDirectory))
|
if (string.IsNullOrWhiteSpace(logInfo.ModDirectory) || logInfo.IsOneLog)
|
||||||
{
|
{
|
||||||
logPath = Path.Combine(workingDirectory, logInfo.GameDirectory, logInfo.LogFile);
|
logPath = Path.Combine(workingDirectory, logInfo.GameDirectory, logInfo.LogFile);
|
||||||
}
|
}
|
||||||
@ -1287,8 +1322,12 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
Manager.AddEvent(e);
|
Manager.AddEvent(e);
|
||||||
|
|
||||||
|
var temporalClientId = targetClient.GetAdditionalProperty<string>("ConnectionClientId");
|
||||||
|
var parsedClientId = string.IsNullOrEmpty(temporalClientId) ? (int?)null : int.Parse(temporalClientId);
|
||||||
|
var clientNumber = parsedClientId ?? targetClient.ClientNumber;
|
||||||
|
|
||||||
var formattedKick = string.Format(RconParser.Configuration.CommandPrefixes.Kick,
|
var formattedKick = string.Format(RconParser.Configuration.CommandPrefixes.Kick,
|
||||||
targetClient.ClientNumber,
|
clientNumber,
|
||||||
_messageFormatter.BuildFormattedMessage(RconParser.Configuration,
|
_messageFormatter.BuildFormattedMessage(RconParser.Configuration,
|
||||||
newPenalty,
|
newPenalty,
|
||||||
previousPenalty));
|
previousPenalty));
|
||||||
@ -1319,8 +1358,12 @@ namespace IW4MAdmin
|
|||||||
|
|
||||||
if (targetClient.IsIngame)
|
if (targetClient.IsIngame)
|
||||||
{
|
{
|
||||||
|
var temporalClientId = targetClient.GetAdditionalProperty<string>("ConnectionClientId");
|
||||||
|
var parsedClientId = string.IsNullOrEmpty(temporalClientId) ? (int?)null : int.Parse(temporalClientId);
|
||||||
|
var clientNumber = parsedClientId ?? targetClient.ClientNumber;
|
||||||
|
|
||||||
var formattedKick = string.Format(RconParser.Configuration.CommandPrefixes.Kick,
|
var formattedKick = string.Format(RconParser.Configuration.CommandPrefixes.Kick,
|
||||||
targetClient.ClientNumber,
|
clientNumber,
|
||||||
_messageFormatter.BuildFormattedMessage(RconParser.Configuration, newPenalty));
|
_messageFormatter.BuildFormattedMessage(RconParser.Configuration, newPenalty));
|
||||||
ServerLogger.LogDebug("Executing tempban kick command for {targetClient}", targetClient.ToString());
|
ServerLogger.LogDebug("Executing tempban kick command for {targetClient}", targetClient.ToString());
|
||||||
await targetClient.CurrentServer.ExecuteCommandAsync(formattedKick);
|
await targetClient.CurrentServer.ExecuteCommandAsync(formattedKick);
|
||||||
@ -1353,8 +1396,13 @@ namespace IW4MAdmin
|
|||||||
if (targetClient.IsIngame)
|
if (targetClient.IsIngame)
|
||||||
{
|
{
|
||||||
ServerLogger.LogDebug("Attempting to kicking newly banned client {targetClient}", targetClient.ToString());
|
ServerLogger.LogDebug("Attempting to kicking newly banned client {targetClient}", targetClient.ToString());
|
||||||
|
|
||||||
|
var temporalClientId = targetClient.GetAdditionalProperty<string>("ConnectionClientId");
|
||||||
|
var parsedClientId = string.IsNullOrEmpty(temporalClientId) ? (int?)null : int.Parse(temporalClientId);
|
||||||
|
var clientNumber = parsedClientId ?? targetClient.ClientNumber;
|
||||||
|
|
||||||
var formattedString = string.Format(RconParser.Configuration.CommandPrefixes.Kick,
|
var formattedString = string.Format(RconParser.Configuration.CommandPrefixes.Kick,
|
||||||
targetClient.ClientNumber,
|
clientNumber,
|
||||||
_messageFormatter.BuildFormattedMessage(RconParser.Configuration, newPenalty));
|
_messageFormatter.BuildFormattedMessage(RconParser.Configuration, newPenalty));
|
||||||
await targetClient.CurrentServer.ExecuteCommandAsync(formattedString);
|
await targetClient.CurrentServer.ExecuteCommandAsync(formattedString);
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Data.Abstractions;
|
using Data.Abstractions;
|
||||||
using Data.Helpers;
|
using Data.Helpers;
|
||||||
|
using Integrations.Source.Extensions;
|
||||||
using IW4MAdmin.Application.Extensions;
|
using IW4MAdmin.Application.Extensions;
|
||||||
using IW4MAdmin.Application.Localization;
|
using IW4MAdmin.Application.Localization;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
@ -417,6 +418,8 @@ namespace IW4MAdmin.Application
|
|||||||
serviceCollection.AddSingleton<IEventHandler, GameEventHandler>();
|
serviceCollection.AddSingleton<IEventHandler, GameEventHandler>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
serviceCollection.AddSource();
|
||||||
|
|
||||||
return serviceCollection;
|
return serviceCollection;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,5 +41,11 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
/// indicates if running on windows
|
/// indicates if running on windows
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsWindows { get; set; } = true;
|
public bool IsWindows { get; set; } = true;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// indicates that the game does not log to the mods folder (when mod is loaded),
|
||||||
|
/// but rather always to the fs_basegame directory
|
||||||
|
/// </summary>
|
||||||
|
public bool IsOneLog { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -168,6 +168,7 @@ namespace IW4MAdmin.Application.Misc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_scriptEngine.SetValue("_configHandler", new ScriptPluginConfigurationWrapper(Name, _scriptEngine));
|
||||||
await OnLoadAsync(manager);
|
await OnLoadAsync(manager);
|
||||||
|
|
||||||
try
|
try
|
||||||
|
90
Application/Misc/ScriptPluginConfigurationWrapper.cs
Normal file
90
Application/Misc/ScriptPluginConfigurationWrapper.cs
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using IW4MAdmin.Application.Configuration;
|
||||||
|
using Jint;
|
||||||
|
using Jint.Native;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace IW4MAdmin.Application.Misc
|
||||||
|
{
|
||||||
|
public class ScriptPluginConfigurationWrapper
|
||||||
|
{
|
||||||
|
private readonly BaseConfigurationHandler<ScriptPluginConfiguration> _handler;
|
||||||
|
private readonly ScriptPluginConfiguration _config;
|
||||||
|
private readonly string _pluginName;
|
||||||
|
private readonly Engine _scriptEngine;
|
||||||
|
|
||||||
|
public ScriptPluginConfigurationWrapper(string pluginName, Engine scriptEngine)
|
||||||
|
{
|
||||||
|
_handler = new BaseConfigurationHandler<ScriptPluginConfiguration>("ScriptPluginSettings");
|
||||||
|
_config = _handler.Configuration() ??
|
||||||
|
(ScriptPluginConfiguration) new ScriptPluginConfiguration().Generate();
|
||||||
|
_pluginName = pluginName;
|
||||||
|
_scriptEngine = scriptEngine;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int? AsInteger(double d)
|
||||||
|
{
|
||||||
|
return int.TryParse(d.ToString(CultureInfo.InvariantCulture), out var parsed) ? parsed : (int?) null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task SetValue(string key, object value)
|
||||||
|
{
|
||||||
|
var castValue = value;
|
||||||
|
|
||||||
|
if (value is double d)
|
||||||
|
{
|
||||||
|
castValue = AsInteger(d) ?? value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value is object[] array && array.All(item => item is double d && AsInteger(d) != null))
|
||||||
|
{
|
||||||
|
castValue = array.Select(item => AsInteger((double)item)).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_config.ContainsKey(_pluginName))
|
||||||
|
{
|
||||||
|
_config.Add(_pluginName, new Dictionary<string, object>());
|
||||||
|
}
|
||||||
|
|
||||||
|
var plugin = _config[_pluginName];
|
||||||
|
|
||||||
|
if (plugin.ContainsKey(key))
|
||||||
|
{
|
||||||
|
plugin[key] = castValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
plugin.Add(key, castValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
_handler.Set(_config);
|
||||||
|
await _handler.Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public JsValue GetValue(string key)
|
||||||
|
{
|
||||||
|
if (!_config.ContainsKey(_pluginName))
|
||||||
|
{
|
||||||
|
return JsValue.Undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_config[_pluginName].ContainsKey(key))
|
||||||
|
{
|
||||||
|
return JsValue.Undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
var item = _config[_pluginName][key];
|
||||||
|
|
||||||
|
if (item is JArray array)
|
||||||
|
{
|
||||||
|
item = array.ToObject<List<dynamic>>();
|
||||||
|
}
|
||||||
|
|
||||||
|
return JsValue.FromObject(_scriptEngine, item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -13,7 +13,7 @@ using Microsoft.Extensions.Logging;
|
|||||||
using static SharedLibraryCore.Server;
|
using static SharedLibraryCore.Server;
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.RconParsers
|
namespace IW4MAdmin.Application.RConParsers
|
||||||
{
|
{
|
||||||
public class BaseRConParser : IRConParser
|
public class BaseRConParser : IRConParser
|
||||||
{
|
{
|
||||||
@ -56,6 +56,7 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
Configuration.Dvar.AddMapping(ParserRegex.GroupType.RConDvarDefaultValue, 3);
|
Configuration.Dvar.AddMapping(ParserRegex.GroupType.RConDvarDefaultValue, 3);
|
||||||
Configuration.Dvar.AddMapping(ParserRegex.GroupType.RConDvarLatchedValue, 4);
|
Configuration.Dvar.AddMapping(ParserRegex.GroupType.RConDvarLatchedValue, 4);
|
||||||
Configuration.Dvar.AddMapping(ParserRegex.GroupType.RConDvarDomain, 5);
|
Configuration.Dvar.AddMapping(ParserRegex.GroupType.RConDvarDomain, 5);
|
||||||
|
Configuration.Dvar.AddMapping(ParserRegex.GroupType.AdditionalGroup, int.MaxValue);
|
||||||
|
|
||||||
Configuration.StatusHeader.Pattern = "num +score +ping +guid +name +lastmsg +address +qport +rate *";
|
Configuration.StatusHeader.Pattern = "num +score +ping +guid +name +lastmsg +address +qport +rate *";
|
||||||
Configuration.GametypeStatus.Pattern = "";
|
Configuration.GametypeStatus.Pattern = "";
|
||||||
@ -73,11 +74,13 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
public Game GameName { get; set; } = Game.COD;
|
public Game GameName { get; set; } = Game.COD;
|
||||||
public bool CanGenerateLogPath { get; set; } = true;
|
public bool CanGenerateLogPath { get; set; } = true;
|
||||||
public string Name { get; set; } = "Call of Duty";
|
public string Name { get; set; } = "Call of Duty";
|
||||||
|
public string RConEngine { get; set; } = "COD";
|
||||||
|
public bool IsOneLog { get; set; }
|
||||||
|
|
||||||
public async Task<string[]> ExecuteCommandAsync(IRConConnection connection, string command)
|
public async Task<string[]> ExecuteCommandAsync(IRConConnection connection, string command)
|
||||||
{
|
{
|
||||||
var response = await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND, command);
|
var response = await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND, command);
|
||||||
return response.Skip(1).ToArray();
|
return response.Where(item => item != Configuration.CommandPrefixes.RConResponse).ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<Dvar<T>> GetDvarAsync<T>(IRConConnection connection, string dvarName, T fallbackValue = default)
|
public async Task<Dvar<T>> GetDvarAsync<T>(IRConConnection connection, string dvarName, T fallbackValue = default)
|
||||||
@ -128,7 +131,7 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
|
|
||||||
return new Dvar<T>()
|
return new Dvar<T>()
|
||||||
{
|
{
|
||||||
Name = match.Groups[Configuration.Dvar.GroupMapping[ParserRegex.GroupType.RConDvarName]].Value,
|
Name = dvarName,
|
||||||
Value = string.IsNullOrEmpty(value) ? default : (T)Convert.ChangeType(value, typeof(T)),
|
Value = string.IsNullOrEmpty(value) ? default : (T)Convert.ChangeType(value, typeof(T)),
|
||||||
DefaultValue = string.IsNullOrEmpty(defaultValue) ? default : (T)Convert.ChangeType(defaultValue, typeof(T)),
|
DefaultValue = string.IsNullOrEmpty(defaultValue) ? default : (T)Convert.ChangeType(defaultValue, typeof(T)),
|
||||||
LatchedValue = string.IsNullOrEmpty(latchedValue) ? default : (T)Convert.ChangeType(latchedValue, typeof(T)),
|
LatchedValue = string.IsNullOrEmpty(latchedValue) ? default : (T)Convert.ChangeType(latchedValue, typeof(T)),
|
||||||
@ -136,53 +139,55 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual async Task<(List<EFClient>, string, string)> GetStatusAsync(IRConConnection connection)
|
public virtual async Task<IStatusResponse> GetStatusAsync(IRConConnection connection)
|
||||||
{
|
{
|
||||||
string[] response = await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND_STATUS);
|
var response = await connection.SendQueryAsync(StaticHelpers.QueryType.COMMAND_STATUS);
|
||||||
_logger.LogDebug("Status Response {response}", string.Join(Environment.NewLine, response));
|
_logger.LogDebug("Status Response {response}", string.Join(Environment.NewLine, response));
|
||||||
return (ClientsFromStatus(response), MapFromStatus(response), GameTypeFromStatus(response));
|
return new StatusResponse
|
||||||
|
{
|
||||||
|
Clients = ClientsFromStatus(response).ToArray(),
|
||||||
|
Map = GetValueFromStatus<string>(response, ParserRegex.GroupType.RConStatusMap, Configuration.MapStatus.Pattern),
|
||||||
|
GameType = GetValueFromStatus<string>(response, ParserRegex.GroupType.RConStatusGametype, Configuration.GametypeStatus.Pattern),
|
||||||
|
Hostname = GetValueFromStatus<string>(response, ParserRegex.GroupType.RConStatusHostname, Configuration.HostnameStatus.Pattern),
|
||||||
|
MaxClients = GetValueFromStatus<int?>(response, ParserRegex.GroupType.RConStatusMaxPlayers, Configuration.MaxPlayersStatus.Pattern)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private string MapFromStatus(string[] response)
|
private T GetValueFromStatus<T>(IEnumerable<string> response, ParserRegex.GroupType groupType, string groupPattern)
|
||||||
{
|
{
|
||||||
string map = null;
|
if (string.IsNullOrEmpty(groupPattern))
|
||||||
|
{
|
||||||
|
return default;
|
||||||
|
}
|
||||||
|
|
||||||
|
string value = null;
|
||||||
foreach (var line in response)
|
foreach (var line in response)
|
||||||
{
|
{
|
||||||
var regex = Regex.Match(line, Configuration.MapStatus.Pattern);
|
var regex = Regex.Match(line, groupPattern);
|
||||||
if (regex.Success)
|
if (regex.Success)
|
||||||
{
|
{
|
||||||
map = regex.Groups[Configuration.MapStatus.GroupMapping[ParserRegex.GroupType.RConStatusMap]].ToString();
|
value = regex.Groups[Configuration.MapStatus.GroupMapping[groupType]].ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return map;
|
if (value == null)
|
||||||
}
|
|
||||||
|
|
||||||
private string GameTypeFromStatus(string[] response)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(Configuration.GametypeStatus.Pattern))
|
|
||||||
{
|
{
|
||||||
return null;
|
return default;
|
||||||
}
|
}
|
||||||
|
|
||||||
string gametype = null;
|
if (typeof(T) == typeof(int?))
|
||||||
foreach (var line in response)
|
|
||||||
{
|
{
|
||||||
var regex = Regex.Match(line, Configuration.GametypeStatus.Pattern);
|
return (T)Convert.ChangeType(int.Parse(value), Nullable.GetUnderlyingType(typeof(T)));
|
||||||
if (regex.Success)
|
|
||||||
{
|
|
||||||
gametype = regex.Groups[Configuration.GametypeStatus.GroupMapping[ParserRegex.GroupType.RConStatusGametype]].ToString();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return gametype;
|
return (T)Convert.ChangeType(value, typeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> SetDvarAsync(IRConConnection connection, string dvarName, object dvarValue)
|
public async Task<bool> SetDvarAsync(IRConConnection connection, string dvarName, object dvarValue)
|
||||||
{
|
{
|
||||||
string dvarString = (dvarValue is string str)
|
string dvarString = (dvarValue is string str)
|
||||||
? $"{dvarName} \"{str}\""
|
? $"{dvarName} \"{str}\""
|
||||||
: $"{dvarName} {dvarValue.ToString()}";
|
: $"{dvarName} {dvarValue}";
|
||||||
|
|
||||||
return (await connection.SendQueryAsync(StaticHelpers.QueryType.SET_DVAR, dvarString)).Length > 0;
|
return (await connection.SendQueryAsync(StaticHelpers.QueryType.SET_DVAR, dvarString)).Length > 0;
|
||||||
}
|
}
|
||||||
@ -258,6 +263,17 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
|
|
||||||
client.SetAdditionalProperty("BotGuid", networkIdString);
|
client.SetAdditionalProperty("BotGuid", networkIdString);
|
||||||
|
|
||||||
|
if (Configuration.Status.GroupMapping.ContainsKey(ParserRegex.GroupType.AdditionalGroup))
|
||||||
|
{
|
||||||
|
var additionalGroupIndex =
|
||||||
|
Configuration.Status.GroupMapping[ParserRegex.GroupType.AdditionalGroup];
|
||||||
|
|
||||||
|
if (match.Values.Length > additionalGroupIndex)
|
||||||
|
{
|
||||||
|
client.SetAdditionalProperty("ConnectionClientId", match.Values[additionalGroupIndex]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
StatusPlayers.Add(client);
|
StatusPlayers.Add(client);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,13 +1,13 @@
|
|||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.RconParsers
|
namespace IW4MAdmin.Application.RConParsers
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// empty implementation of the IW4RConParser
|
/// empty implementation of the IW4RConParser
|
||||||
/// allows script plugins to generate dynamic RCon parsers
|
/// allows script plugins to generate dynamic RCon parsers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
sealed internal class DynamicRConParser : BaseRConParser
|
internal sealed class DynamicRConParser : BaseRConParser
|
||||||
{
|
{
|
||||||
public DynamicRConParser(ILogger<BaseRConParser> logger, IParserRegexFactory parserRegexFactory) : base(logger, parserRegexFactory)
|
public DynamicRConParser(ILogger<BaseRConParser> logger, IParserRegexFactory parserRegexFactory) : base(logger, parserRegexFactory)
|
||||||
{
|
{
|
@ -4,7 +4,7 @@ using SharedLibraryCore.RCon;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.RconParsers
|
namespace IW4MAdmin.Application.RConParsers
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// generic implementation of the IRConParserConfiguration
|
/// generic implementation of the IRConParserConfiguration
|
||||||
@ -16,6 +16,8 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
public ParserRegex Status { get; set; }
|
public ParserRegex Status { get; set; }
|
||||||
public ParserRegex MapStatus { get; set; }
|
public ParserRegex MapStatus { get; set; }
|
||||||
public ParserRegex GametypeStatus { get; set; }
|
public ParserRegex GametypeStatus { get; set; }
|
||||||
|
public ParserRegex HostnameStatus { get; set; }
|
||||||
|
public ParserRegex MaxPlayersStatus { get; set; }
|
||||||
public ParserRegex Dvar { get; set; }
|
public ParserRegex Dvar { get; set; }
|
||||||
public ParserRegex StatusHeader { get; set; }
|
public ParserRegex StatusHeader { get; set; }
|
||||||
public string ServerNotRunningResponse { get; set; }
|
public string ServerNotRunningResponse { get; set; }
|
||||||
@ -34,6 +36,8 @@ namespace IW4MAdmin.Application.RconParsers
|
|||||||
GametypeStatus = parserRegexFactory.CreateParserRegex();
|
GametypeStatus = parserRegexFactory.CreateParserRegex();
|
||||||
Dvar = parserRegexFactory.CreateParserRegex();
|
Dvar = parserRegexFactory.CreateParserRegex();
|
||||||
StatusHeader = parserRegexFactory.CreateParserRegex();
|
StatusHeader = parserRegexFactory.CreateParserRegex();
|
||||||
|
HostnameStatus = parserRegexFactory.CreateParserRegex();
|
||||||
|
MaxPlayersStatus = parserRegexFactory.CreateParserRegex();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
15
Application/RConParsers/StatusResponse.cs
Normal file
15
Application/RConParsers/StatusResponse.cs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
using SharedLibraryCore.Database.Models;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
|
||||||
|
namespace IW4MAdmin.Application.RConParsers
|
||||||
|
{
|
||||||
|
/// <inheritdoc cref="IStatusResponse"/>
|
||||||
|
public class StatusResponse : IStatusResponse
|
||||||
|
{
|
||||||
|
public string Map { get; set; }
|
||||||
|
public string GameType { get; set; }
|
||||||
|
public string Hostname { get; set; }
|
||||||
|
public int? MaxClients { get; set; }
|
||||||
|
public EFClient[] Clients { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,7 @@
|
|||||||
<PackageId>RaidMax.IW4MAdmin.Data</PackageId>
|
<PackageId>RaidMax.IW4MAdmin.Data</PackageId>
|
||||||
<Title>RaidMax.IW4MAdmin.Data</Title>
|
<Title>RaidMax.IW4MAdmin.Data</Title>
|
||||||
<Authors />
|
<Authors />
|
||||||
|
<PackageVersion>1.0.1</PackageVersion>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -13,7 +13,9 @@
|
|||||||
T4 = 5,
|
T4 = 5,
|
||||||
T5 = 6,
|
T5 = 6,
|
||||||
T6 = 7,
|
T6 = 7,
|
||||||
T7 = 8
|
T7 = 8,
|
||||||
|
SHG1 = 9,
|
||||||
|
CSGO = 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,7 +5,7 @@ namespace Data.Models
|
|||||||
{
|
{
|
||||||
public class SharedEntity : IPropertyExtender
|
public class SharedEntity : IPropertyExtender
|
||||||
{
|
{
|
||||||
private readonly ConcurrentDictionary<string, object> _additionalProperties;
|
private ConcurrentDictionary<string, object> _additionalProperties;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// indicates if the entity is active
|
/// indicates if the entity is active
|
||||||
@ -33,5 +33,10 @@ namespace Data.Models
|
|||||||
_additionalProperties.TryAdd(name, value);
|
_additionalProperties.TryAdd(name, value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void CopyAdditionalProperties(SharedEntity source)
|
||||||
|
{
|
||||||
|
_additionalProperties = source._additionalProperties;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -45,6 +45,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ScriptPlugins", "ScriptPlug
|
|||||||
Plugins\ScriptPlugins\SampleScriptPluginCommand.js = Plugins\ScriptPlugins\SampleScriptPluginCommand.js
|
Plugins\ScriptPlugins\SampleScriptPluginCommand.js = Plugins\ScriptPlugins\SampleScriptPluginCommand.js
|
||||||
Plugins\ScriptPlugins\SharedGUIDKick.js = Plugins\ScriptPlugins\SharedGUIDKick.js
|
Plugins\ScriptPlugins\SharedGUIDKick.js = Plugins\ScriptPlugins\SharedGUIDKick.js
|
||||||
Plugins\ScriptPlugins\VPNDetection.js = Plugins\ScriptPlugins\VPNDetection.js
|
Plugins\ScriptPlugins\VPNDetection.js = Plugins\ScriptPlugins\VPNDetection.js
|
||||||
|
Plugins\ScriptPlugins\ParserPlutoniumT4.js = Plugins\ScriptPlugins\ParserPlutoniumT4.js
|
||||||
|
Plugins\ScriptPlugins\ParserS1x.js = Plugins\ScriptPlugins\ParserS1x.js
|
||||||
|
Plugins\ScriptPlugins\ParserCSGO.js = Plugins\ScriptPlugins\ParserCSGO.js
|
||||||
|
Plugins\ScriptPlugins\ParserCSGOSM.js = Plugins\ScriptPlugins\ParserCSGOSM.js
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutomessageFeed", "Plugins\AutomessageFeed\AutomessageFeed.csproj", "{F5815359-CFC7-44B4-9A3B-C04BACAD5836}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AutomessageFeed", "Plugins\AutomessageFeed\AutomessageFeed.csproj", "{F5815359-CFC7-44B4-9A3B-C04BACAD5836}"
|
||||||
@ -57,6 +61,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApplicationTests", "Tests\A
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Data", "Data\Data.csproj", "{81689023-E55E-48ED-B7A8-53F4E21BBF2D}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Data", "Data\Data.csproj", "{81689023-E55E-48ED-B7A8-53F4E21BBF2D}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Integrations", "Integrations", "{A2AE33B4-0830-426A-9E11-951DAB12BE5B}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Integrations.Cod", "Integrations\Cod\Integrations.Cod.csproj", "{A9348433-58C1-4B9C-8BB7-088B02529D9D}"
|
||||||
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Integrations.Source", "Integrations\Source\Integrations.Source.csproj", "{9512295B-3045-40E0-9B7E-2409F2173E9D}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@ -360,6 +370,54 @@ Global
|
|||||||
{81689023-E55E-48ED-B7A8-53F4E21BBF2D}.Release|x86.Build.0 = Release|Any CPU
|
{81689023-E55E-48ED-B7A8-53F4E21BBF2D}.Release|x86.Build.0 = Release|Any CPU
|
||||||
{81689023-E55E-48ED-B7A8-53F4E21BBF2D}.Prerelease|Any CPU.ActiveCfg = Prerelease|Any CPU
|
{81689023-E55E-48ED-B7A8-53F4E21BBF2D}.Prerelease|Any CPU.ActiveCfg = Prerelease|Any CPU
|
||||||
{81689023-E55E-48ED-B7A8-53F4E21BBF2D}.Prerelease|Any CPU.Build.0 = Prerelease|Any CPU
|
{81689023-E55E-48ED-B7A8-53F4E21BBF2D}.Prerelease|Any CPU.Build.0 = Prerelease|Any CPU
|
||||||
|
{A9348433-58C1-4B9C-8BB7-088B02529D9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A9348433-58C1-4B9C-8BB7-088B02529D9D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A9348433-58C1-4B9C-8BB7-088B02529D9D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{A9348433-58C1-4B9C-8BB7-088B02529D9D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{A9348433-58C1-4B9C-8BB7-088B02529D9D}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{A9348433-58C1-4B9C-8BB7-088B02529D9D}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{A9348433-58C1-4B9C-8BB7-088B02529D9D}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{A9348433-58C1-4B9C-8BB7-088B02529D9D}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{A9348433-58C1-4B9C-8BB7-088B02529D9D}.Prerelease|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{A9348433-58C1-4B9C-8BB7-088B02529D9D}.Prerelease|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{A9348433-58C1-4B9C-8BB7-088B02529D9D}.Prerelease|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{A9348433-58C1-4B9C-8BB7-088B02529D9D}.Prerelease|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{A9348433-58C1-4B9C-8BB7-088B02529D9D}.Prerelease|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{A9348433-58C1-4B9C-8BB7-088B02529D9D}.Prerelease|x64.Build.0 = Debug|Any CPU
|
||||||
|
{A9348433-58C1-4B9C-8BB7-088B02529D9D}.Prerelease|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{A9348433-58C1-4B9C-8BB7-088B02529D9D}.Prerelease|x86.Build.0 = Debug|Any CPU
|
||||||
|
{A9348433-58C1-4B9C-8BB7-088B02529D9D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{A9348433-58C1-4B9C-8BB7-088B02529D9D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{A9348433-58C1-4B9C-8BB7-088B02529D9D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{A9348433-58C1-4B9C-8BB7-088B02529D9D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{A9348433-58C1-4B9C-8BB7-088B02529D9D}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{A9348433-58C1-4B9C-8BB7-088B02529D9D}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{A9348433-58C1-4B9C-8BB7-088B02529D9D}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{A9348433-58C1-4B9C-8BB7-088B02529D9D}.Release|x86.Build.0 = Release|Any CPU
|
||||||
|
{9512295B-3045-40E0-9B7E-2409F2173E9D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{9512295B-3045-40E0-9B7E-2409F2173E9D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{9512295B-3045-40E0-9B7E-2409F2173E9D}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{9512295B-3045-40E0-9B7E-2409F2173E9D}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{9512295B-3045-40E0-9B7E-2409F2173E9D}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{9512295B-3045-40E0-9B7E-2409F2173E9D}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{9512295B-3045-40E0-9B7E-2409F2173E9D}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{9512295B-3045-40E0-9B7E-2409F2173E9D}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{9512295B-3045-40E0-9B7E-2409F2173E9D}.Prerelease|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{9512295B-3045-40E0-9B7E-2409F2173E9D}.Prerelease|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{9512295B-3045-40E0-9B7E-2409F2173E9D}.Prerelease|Mixed Platforms.ActiveCfg = Debug|Any CPU
|
||||||
|
{9512295B-3045-40E0-9B7E-2409F2173E9D}.Prerelease|Mixed Platforms.Build.0 = Debug|Any CPU
|
||||||
|
{9512295B-3045-40E0-9B7E-2409F2173E9D}.Prerelease|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{9512295B-3045-40E0-9B7E-2409F2173E9D}.Prerelease|x64.Build.0 = Debug|Any CPU
|
||||||
|
{9512295B-3045-40E0-9B7E-2409F2173E9D}.Prerelease|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{9512295B-3045-40E0-9B7E-2409F2173E9D}.Prerelease|x86.Build.0 = Debug|Any CPU
|
||||||
|
{9512295B-3045-40E0-9B7E-2409F2173E9D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{9512295B-3045-40E0-9B7E-2409F2173E9D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{9512295B-3045-40E0-9B7E-2409F2173E9D}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU
|
||||||
|
{9512295B-3045-40E0-9B7E-2409F2173E9D}.Release|Mixed Platforms.Build.0 = Release|Any CPU
|
||||||
|
{9512295B-3045-40E0-9B7E-2409F2173E9D}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{9512295B-3045-40E0-9B7E-2409F2173E9D}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{9512295B-3045-40E0-9B7E-2409F2173E9D}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{9512295B-3045-40E0-9B7E-2409F2173E9D}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
@ -374,6 +432,8 @@ Global
|
|||||||
{F5815359-CFC7-44B4-9A3B-C04BACAD5836} = {26E8B310-269E-46D4-A612-24601F16065F}
|
{F5815359-CFC7-44B4-9A3B-C04BACAD5836} = {26E8B310-269E-46D4-A612-24601F16065F}
|
||||||
{00A1FED2-2254-4AF7-A5DB-2357FA7C88CD} = {26E8B310-269E-46D4-A612-24601F16065F}
|
{00A1FED2-2254-4AF7-A5DB-2357FA7C88CD} = {26E8B310-269E-46D4-A612-24601F16065F}
|
||||||
{581FA7AF-FEF6-483C-A7D0-2D13EF50801B} = {3065279E-17F0-4CE0-AF5B-014E04263D77}
|
{581FA7AF-FEF6-483C-A7D0-2D13EF50801B} = {3065279E-17F0-4CE0-AF5B-014E04263D77}
|
||||||
|
{A9348433-58C1-4B9C-8BB7-088B02529D9D} = {A2AE33B4-0830-426A-9E11-951DAB12BE5B}
|
||||||
|
{9512295B-3045-40E0-9B7E-2409F2173E9D} = {A2AE33B4-0830-426A-9E11-951DAB12BE5B}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {84F8F8E0-1F73-41E0-BD8D-BB6676E2EE87}
|
SolutionGuid = {84F8F8E0-1F73-41E0-BD8D-BB6676E2EE87}
|
||||||
|
@ -1,8 +1,4 @@
|
|||||||
using SharedLibraryCore;
|
using System;
|
||||||
using SharedLibraryCore.Exceptions;
|
|
||||||
using SharedLibraryCore.Interfaces;
|
|
||||||
using SharedLibraryCore.RCon;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -14,25 +10,29 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.Extensions.Logging;
|
using Microsoft.Extensions.Logging;
|
||||||
using Serilog.Context;
|
using Serilog.Context;
|
||||||
|
using SharedLibraryCore;
|
||||||
|
using SharedLibraryCore.Exceptions;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using SharedLibraryCore.RCon;
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.RCon
|
namespace Integrations.Cod
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// implementation of IRConConnection
|
/// implementation of IRConConnection
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class RConConnection : IRConConnection
|
public class CodRConConnection : IRConConnection
|
||||||
{
|
{
|
||||||
static readonly ConcurrentDictionary<EndPoint, ConnectionState> ActiveQueries = new ConcurrentDictionary<EndPoint, ConnectionState>();
|
static readonly ConcurrentDictionary<EndPoint, ConnectionState> ActiveQueries = new ConcurrentDictionary<EndPoint, ConnectionState>();
|
||||||
public IPEndPoint Endpoint { get; private set; }
|
public IPEndPoint Endpoint { get; }
|
||||||
public string RConPassword { get; private set; }
|
public string RConPassword { get; }
|
||||||
|
|
||||||
private IRConParser parser;
|
private IRConParser parser;
|
||||||
private IRConParserConfiguration config;
|
private IRConParserConfiguration config;
|
||||||
private readonly ILogger _log;
|
private readonly ILogger _log;
|
||||||
private readonly Encoding _gameEncoding;
|
private readonly Encoding _gameEncoding;
|
||||||
|
|
||||||
public RConConnection(string ipAddress, int port, string password, ILogger<RConConnection> log, Encoding gameEncoding)
|
public CodRConConnection(string ipAddress, int port, string password, ILogger<CodRConConnection> log, Encoding gameEncoding)
|
||||||
{
|
{
|
||||||
Endpoint = new IPEndPoint(IPAddress.Parse(ipAddress), port);
|
Endpoint = new IPEndPoint(IPAddress.Parse(ipAddress), port);
|
||||||
_gameEncoding = gameEncoding;
|
_gameEncoding = gameEncoding;
|
@ -3,7 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
|
|
||||||
namespace IW4MAdmin.Application.RCon
|
namespace Integrations.Cod
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// used to keep track of the udp connection state
|
/// used to keep track of the udp connection state
|
13
Integrations/Cod/Integrations.Cod.csproj
Normal file
13
Integrations/Cod/Integrations.Cod.csproj
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
<AssemblyName>Integrations.Cod</AssemblyName>
|
||||||
|
<RootNamespace>Integrations.Cod</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\SharedLibraryCore\SharedLibraryCore.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
@ -0,0 +1,15 @@
|
|||||||
|
using Integrations.Source.Interfaces;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
|
||||||
|
namespace Integrations.Source.Extensions
|
||||||
|
{
|
||||||
|
public static class IntegrationServicesExtensions
|
||||||
|
{
|
||||||
|
public static IServiceCollection AddSource(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
services.AddSingleton<IRConClientFactory, RConClientFactory>();
|
||||||
|
|
||||||
|
return services;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
17
Integrations/Source/Integrations.Source.csproj
Normal file
17
Integrations/Source/Integrations.Source.csproj
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
|
<AssemblyName>Integrations.Source</AssemblyName>
|
||||||
|
<RootNamespace>Integrations.Source</RootNamespace>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="RconSharp" Version="2.0.1" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\SharedLibraryCore\SharedLibraryCore.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
9
Integrations/Source/Interfaces/IRConClientFactory.cs
Normal file
9
Integrations/Source/Interfaces/IRConClientFactory.cs
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
using RconSharp;
|
||||||
|
|
||||||
|
namespace Integrations.Source.Interfaces
|
||||||
|
{
|
||||||
|
public interface IRConClientFactory
|
||||||
|
{
|
||||||
|
RconClient CreateClient(string hostname, int port);
|
||||||
|
}
|
||||||
|
}
|
13
Integrations/Source/RConClientFactory.cs
Normal file
13
Integrations/Source/RConClientFactory.cs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
using Integrations.Source.Interfaces;
|
||||||
|
using RconSharp;
|
||||||
|
|
||||||
|
namespace Integrations.Source
|
||||||
|
{
|
||||||
|
public class RConClientFactory : IRConClientFactory
|
||||||
|
{
|
||||||
|
public RconClient CreateClient(string hostname, int port)
|
||||||
|
{
|
||||||
|
return RconClient.Create(hostname, port);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
105
Integrations/Source/SourceRConConnection.cs
Normal file
105
Integrations/Source/SourceRConConnection.cs
Normal file
@ -0,0 +1,105 @@
|
|||||||
|
using System.Linq;
|
||||||
|
using System.Net.Sockets;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Integrations.Source.Interfaces;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
using RconSharp;
|
||||||
|
using Serilog.Context;
|
||||||
|
using SharedLibraryCore;
|
||||||
|
using SharedLibraryCore.Exceptions;
|
||||||
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using SharedLibraryCore.RCon;
|
||||||
|
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
||||||
|
|
||||||
|
namespace Integrations.Source
|
||||||
|
{
|
||||||
|
public class SourceRConConnection : IRConConnection
|
||||||
|
{
|
||||||
|
private readonly ILogger _logger;
|
||||||
|
private readonly string _password;
|
||||||
|
private readonly string _hostname;
|
||||||
|
private readonly int _port;
|
||||||
|
private readonly IRConClientFactory _rconClientFactory;
|
||||||
|
|
||||||
|
private RconClient _rconClient;
|
||||||
|
|
||||||
|
public SourceRConConnection(ILogger<SourceRConConnection> logger, IRConClientFactory rconClientFactory,
|
||||||
|
string hostname, int port, string password)
|
||||||
|
{
|
||||||
|
_rconClient = rconClientFactory.CreateClient(hostname, port);
|
||||||
|
_rconClientFactory = rconClientFactory;
|
||||||
|
_password = password;
|
||||||
|
_hostname = hostname;
|
||||||
|
_port = port;
|
||||||
|
_logger = logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<string[]> SendQueryAsync(StaticHelpers.QueryType type, string parameters = "")
|
||||||
|
{
|
||||||
|
await _rconClient.ConnectAsync();
|
||||||
|
|
||||||
|
bool authenticated;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
authenticated = await _rconClient.AuthenticateAsync(_password);
|
||||||
|
}
|
||||||
|
catch (SocketException ex)
|
||||||
|
{
|
||||||
|
// occurs when the server comes back from hibernation
|
||||||
|
// this is probably a bug in the library
|
||||||
|
if (ex.ErrorCode == 10053 || ex.ErrorCode == 10054)
|
||||||
|
{
|
||||||
|
using (LogContext.PushProperty("Server", $"{_hostname}:{_port}"))
|
||||||
|
{
|
||||||
|
_logger.LogWarning(ex,
|
||||||
|
"Server appears to resumed from hibernation, so we are using a new socket");
|
||||||
|
}
|
||||||
|
|
||||||
|
_rconClient = _rconClientFactory.CreateClient(_hostname, _port);
|
||||||
|
}
|
||||||
|
|
||||||
|
using (LogContext.PushProperty("Server", $"{_hostname}:{_port}"))
|
||||||
|
{
|
||||||
|
_logger.LogError("Could not login to server");
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NetworkException("Could not authenticate with server");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!authenticated)
|
||||||
|
{
|
||||||
|
using (LogContext.PushProperty("Server", $"{_hostname}:{_port}"))
|
||||||
|
{
|
||||||
|
_logger.LogError("Could not login to server");
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new ServerException("Could not authenticate to server with provided password");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == StaticHelpers.QueryType.COMMAND_STATUS)
|
||||||
|
{
|
||||||
|
parameters = "status";
|
||||||
|
}
|
||||||
|
|
||||||
|
using (LogContext.PushProperty("Server", $"{_hostname}:{_port}"))
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Sending query {Type} with parameters {Parameters}", type, parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
var response = await _rconClient.ExecuteCommandAsync(parameters.StripColors(), true);
|
||||||
|
|
||||||
|
using (LogContext.PushProperty("Server", $"{_rconClient.Host}:{_rconClient.Port}"))
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Received RCon response {Response}", response);
|
||||||
|
}
|
||||||
|
|
||||||
|
var split = response.TrimEnd('\n').Split('\n');
|
||||||
|
return split.Take(split.Length - 1).ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetConfiguration(IRConParser config)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
100
Plugins/ScriptPlugins/ParserCSGO.js
Normal file
100
Plugins/ScriptPlugins/ParserCSGO.js
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
let rconParser;
|
||||||
|
let eventParser;
|
||||||
|
|
||||||
|
const plugin = {
|
||||||
|
author: 'RaidMax',
|
||||||
|
version: 0.1,
|
||||||
|
name: 'CS:GO Parser',
|
||||||
|
engine: 'Source',
|
||||||
|
isParser: true,
|
||||||
|
|
||||||
|
onEventAsync: function (gameEvent, server) {
|
||||||
|
},
|
||||||
|
|
||||||
|
onLoadAsync: function (manager) {
|
||||||
|
rconParser = manager.GenerateDynamicRConParser(this.engine);
|
||||||
|
eventParser = manager.GenerateDynamicEventParser(this.engine);
|
||||||
|
rconParser.RConEngine = this.engine;
|
||||||
|
|
||||||
|
rconParser.Configuration.StatusHeader.Pattern = 'userid +name +uniqueid +connected +ping +loss +state +rate +adr';
|
||||||
|
|
||||||
|
rconParser.Configuration.MapStatus.Pattern = '^map *: +(.+)$';
|
||||||
|
rconParser.Configuration.MapStatus.AddMapping(111, 1);
|
||||||
|
|
||||||
|
rconParser.Configuration.HostnameStatus.Pattern = '^hostname: +(.+)$';
|
||||||
|
rconParser.Configuration.MapStatus.AddMapping(113, 1);
|
||||||
|
|
||||||
|
rconParser.Configuration.MaxPlayersStatus.Pattern = '^players *: +\\d humans, \\d bots \\((\\d+).+';
|
||||||
|
rconParser.Configuration.MapStatus.AddMapping(114, 1);
|
||||||
|
|
||||||
|
rconParser.Configuration.Dvar.Pattern = '^"(.+)" = (?:"(.+)" (?:\\( def\\. "(.*)" \\))|"(.+)" +(.+)) +- (.*)$';
|
||||||
|
rconParser.Configuration.Dvar.AddMapping(106, 1);
|
||||||
|
rconParser.Configuration.Dvar.AddMapping(107, 2);
|
||||||
|
rconParser.Configuration.Dvar.AddMapping(108, 3);
|
||||||
|
rconParser.Configuration.Dvar.AddMapping(109, 3);
|
||||||
|
|
||||||
|
rconParser.Configuration.Status.Pattern = '^#\\s*(\\d+) (\\d+) "(.+)" (\\S+) (\\d+:\\d+) (\\d+) (\\S+) (\\S+) (\\d+) (\\d+\\.\\d+\\.\\d+\\.\\d+:\\d+)$';
|
||||||
|
rconParser.Configuration.Status.AddMapping(100, 2);
|
||||||
|
rconParser.Configuration.Status.AddMapping(101, 7);
|
||||||
|
rconParser.Configuration.Status.AddMapping(102, 6);
|
||||||
|
rconParser.Configuration.Status.AddMapping(103, 4)
|
||||||
|
rconParser.Configuration.Status.AddMapping(104, 3);
|
||||||
|
rconParser.Configuration.Status.AddMapping(105, 10);
|
||||||
|
rconParser.Configuration.Status.AddMapping(200, 1);
|
||||||
|
|
||||||
|
rconParser.Configuration.DefaultDvarValues.Add('sv_running', '1');
|
||||||
|
rconParser.Configuration.DefaultDvarValues.Add('version', this.engine);
|
||||||
|
rconParser.Configuration.DefaultDvarValues.Add('fs_basepath', '');
|
||||||
|
rconParser.Configuration.DefaultDvarValues.Add('fs_basegame', '');
|
||||||
|
rconParser.Configuration.DefaultDvarValues.Add('g_log', '');
|
||||||
|
rconParser.Configuration.DefaultDvarValues.Add('net_ip', 'localhost');
|
||||||
|
|
||||||
|
rconParser.Configuration.OverrideDvarNameMapping.Add('sv_hostname', 'hostname');
|
||||||
|
rconParser.Configuration.OverrideDvarNameMapping.Add('mapname', 'host_map');
|
||||||
|
rconParser.Configuration.OverrideDvarNameMapping.Add('sv_maxclients', 'maxplayers');
|
||||||
|
rconParser.Configuration.OverrideDvarNameMapping.Add('g_gametype', 'game_type'); // todo: will need gamemode too
|
||||||
|
rconParser.Configuration.OverrideDvarNameMapping.Add('fs_game', 'game_mode');
|
||||||
|
rconParser.Configuration.OverrideDvarNameMapping.Add('g_password', 'sv_password');
|
||||||
|
|
||||||
|
rconParser.Configuration.NoticeLineSeparator = '. ';
|
||||||
|
rconParser.CanGenerateLogPath = false;
|
||||||
|
|
||||||
|
rconParser.Configuration.CommandPrefixes.RConGetInfo = undefined;
|
||||||
|
rconParser.Configuration.CommandPrefixes.Kick = 'kickid {0} "{1}"';
|
||||||
|
rconParser.Configuration.CommandPrefixes.Ban = 'kickid {0} "{1}"';
|
||||||
|
rconParser.Configuration.CommandPrefixes.TempBan = 'kickid {0} "{1}"';
|
||||||
|
rconParser.Configuration.CommandPrefixes.Say = 'say {0}';
|
||||||
|
rconParser.Configuration.CommandPrefixes.Tell = 'say [{0}] {1}'; // no tell exists in vanilla
|
||||||
|
|
||||||
|
eventParser.Configuration.Say.Pattern = '^"(.+)<(\\d+)><(.+)><(.*?)>" say "(.*)"$';
|
||||||
|
eventParser.Configuration.Say.AddMapping(5, 1);
|
||||||
|
eventParser.Configuration.Say.AddMapping(3, 2);
|
||||||
|
eventParser.Configuration.Say.AddMapping(1, 3);
|
||||||
|
eventParser.Configuration.Say.AddMapping(7, 4);
|
||||||
|
eventParser.Configuration.Say.AddMapping(13, 5);
|
||||||
|
|
||||||
|
eventParser.Configuration.Kill.Pattern = '"(.+)<(\\d+)><(.+)><(.*)>" \\[-?\\d+ -?\\d+ -?\\d+\\] killed "(.+)<(\\d+)><(.+)><(.*)>" \\[-?\\d+ -?\\d+ -?\\d+\\] with "(\\S*)"(.*)$';
|
||||||
|
eventParser.Configuration.Kill.AddMapping(5, 1);
|
||||||
|
eventParser.Configuration.Kill.AddMapping(3, 2);
|
||||||
|
eventParser.Configuration.Kill.AddMapping(1, 3);
|
||||||
|
eventParser.Configuration.Kill.AddMapping(7, 4);
|
||||||
|
eventParser.Configuration.Kill.AddMapping(6, 5);
|
||||||
|
eventParser.Configuration.Kill.AddMapping(4, 6);
|
||||||
|
eventParser.Configuration.Kill.AddMapping(2, 7);
|
||||||
|
eventParser.Configuration.Kill.AddMapping(8, 8);
|
||||||
|
eventParser.Configuration.Kill.AddMapping(9, 9);
|
||||||
|
|
||||||
|
eventParser.Configuration.Time.Pattern = '^L [01]\\d/[0-3]\\d/\\d+ - [0-2]\\d:[0-5]\\d:[0-5]\\d:';
|
||||||
|
|
||||||
|
rconParser.Version = 'CSGO';
|
||||||
|
rconParser.GameName = 10; // CSGO
|
||||||
|
eventParser.Version = 'CSGO';
|
||||||
|
eventParser.GameName = 10; // CSGO
|
||||||
|
},
|
||||||
|
|
||||||
|
onUnloadAsync: function () {
|
||||||
|
},
|
||||||
|
|
||||||
|
onTickAsync: function (server) {
|
||||||
|
}
|
||||||
|
};
|
100
Plugins/ScriptPlugins/ParserCSGOSM.js
Normal file
100
Plugins/ScriptPlugins/ParserCSGOSM.js
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
let rconParser;
|
||||||
|
let eventParser;
|
||||||
|
|
||||||
|
const plugin = {
|
||||||
|
author: 'RaidMax',
|
||||||
|
version: 0.1,
|
||||||
|
name: 'CS:GO (SourceMod) Parser',
|
||||||
|
engine: 'Source',
|
||||||
|
isParser: true,
|
||||||
|
|
||||||
|
onEventAsync: function (gameEvent, server) {
|
||||||
|
},
|
||||||
|
|
||||||
|
onLoadAsync: function (manager) {
|
||||||
|
rconParser = manager.GenerateDynamicRConParser(this.engine);
|
||||||
|
eventParser = manager.GenerateDynamicEventParser(this.engine);
|
||||||
|
rconParser.RConEngine = this.engine;
|
||||||
|
|
||||||
|
rconParser.Configuration.StatusHeader.Pattern = 'userid +name +uniqueid +connected +ping +loss +state +rate +adr';
|
||||||
|
|
||||||
|
rconParser.Configuration.MapStatus.Pattern = '^map *: +(.+)$';
|
||||||
|
rconParser.Configuration.MapStatus.AddMapping(111, 1);
|
||||||
|
|
||||||
|
rconParser.Configuration.HostnameStatus.Pattern = '^hostname: +(.+)$';
|
||||||
|
rconParser.Configuration.MapStatus.AddMapping(113, 1);
|
||||||
|
|
||||||
|
rconParser.Configuration.MaxPlayersStatus.Pattern = '^players *: +\\d humans, \\d bots \\((\\d+).+';
|
||||||
|
rconParser.Configuration.MapStatus.AddMapping(114, 1);
|
||||||
|
|
||||||
|
rconParser.Configuration.Dvar.Pattern = '^"(.+)" = (?:"(.+)" (?:\\( def\\. "(.*)" \\))|"(.+)" +(.+)) +- (.*)$';
|
||||||
|
rconParser.Configuration.Dvar.AddMapping(106, 1);
|
||||||
|
rconParser.Configuration.Dvar.AddMapping(107, 2);
|
||||||
|
rconParser.Configuration.Dvar.AddMapping(108, 3);
|
||||||
|
rconParser.Configuration.Dvar.AddMapping(109, 3);
|
||||||
|
|
||||||
|
rconParser.Configuration.Status.Pattern = '^#\\s*(\\d+) (\\d+) "(.+)" (\\S+) (\\d+:\\d+) (\\d+) (\\S+) (\\S+) (\\d+) (\\d+\\.\\d+\\.\\d+\\.\\d+:\\d+)$';
|
||||||
|
rconParser.Configuration.Status.AddMapping(100, 2);
|
||||||
|
rconParser.Configuration.Status.AddMapping(101, 7);
|
||||||
|
rconParser.Configuration.Status.AddMapping(102, 6);
|
||||||
|
rconParser.Configuration.Status.AddMapping(103, 4)
|
||||||
|
rconParser.Configuration.Status.AddMapping(104, 3);
|
||||||
|
rconParser.Configuration.Status.AddMapping(105, 10);
|
||||||
|
rconParser.Configuration.Status.AddMapping(200, 1);
|
||||||
|
|
||||||
|
rconParser.Configuration.DefaultDvarValues.Add('sv_running', '1');
|
||||||
|
rconParser.Configuration.DefaultDvarValues.Add('version', this.engine);
|
||||||
|
rconParser.Configuration.DefaultDvarValues.Add('fs_basepath', '');
|
||||||
|
rconParser.Configuration.DefaultDvarValues.Add('fs_basegame', '');
|
||||||
|
rconParser.Configuration.DefaultDvarValues.Add('g_log', '');
|
||||||
|
rconParser.Configuration.DefaultDvarValues.Add('net_ip', 'localhost');
|
||||||
|
|
||||||
|
rconParser.Configuration.OverrideDvarNameMapping.Add('sv_hostname', 'hostname');
|
||||||
|
rconParser.Configuration.OverrideDvarNameMapping.Add('mapname', 'host_map');
|
||||||
|
rconParser.Configuration.OverrideDvarNameMapping.Add('sv_maxclients', 'maxplayers');
|
||||||
|
rconParser.Configuration.OverrideDvarNameMapping.Add('g_gametype', 'game_type');
|
||||||
|
rconParser.Configuration.OverrideDvarNameMapping.Add('fs_game', 'game_mode');
|
||||||
|
rconParser.Configuration.OverrideDvarNameMapping.Add('g_password', 'sv_password');
|
||||||
|
|
||||||
|
rconParser.Configuration.NoticeLineSeparator = '. ';
|
||||||
|
rconParser.CanGenerateLogPath = false;
|
||||||
|
|
||||||
|
rconParser.Configuration.CommandPrefixes.RConGetInfo = undefined;
|
||||||
|
rconParser.Configuration.CommandPrefixes.Kick = 'sm_kick #{0} {1}';
|
||||||
|
rconParser.Configuration.CommandPrefixes.Ban = 'sm_kick #{0} {1}';
|
||||||
|
rconParser.Configuration.CommandPrefixes.TempBan = 'sm_kick #{0} {1}';
|
||||||
|
rconParser.Configuration.CommandPrefixes.Say = 'sm_say {0}';
|
||||||
|
rconParser.Configuration.CommandPrefixes.Tell = 'sm_psay #{0} {1}';
|
||||||
|
|
||||||
|
eventParser.Configuration.Say.Pattern = '^"(.+)<(\\d+)><(.+)><(.*?)>" say "(.*)"$';
|
||||||
|
eventParser.Configuration.Say.AddMapping(5, 1);
|
||||||
|
eventParser.Configuration.Say.AddMapping(3, 2);
|
||||||
|
eventParser.Configuration.Say.AddMapping(1, 3);
|
||||||
|
eventParser.Configuration.Say.AddMapping(7, 4);
|
||||||
|
eventParser.Configuration.Say.AddMapping(13, 5);
|
||||||
|
|
||||||
|
eventParser.Configuration.Kill.Pattern = '"(.+)<(\\d+)><(.+)><(.*)>" \\[-?\\d+ -?\\d+ -?\\d+\\] killed "(.+)<(\\d+)><(.+)><(.*)>" \\[-?\\d+ -?\\d+ -?\\d+\\] with "(\\S*)"(.*)$';
|
||||||
|
eventParser.Configuration.Kill.AddMapping(5, 1);
|
||||||
|
eventParser.Configuration.Kill.AddMapping(3, 2);
|
||||||
|
eventParser.Configuration.Kill.AddMapping(1, 3);
|
||||||
|
eventParser.Configuration.Kill.AddMapping(7, 4);
|
||||||
|
eventParser.Configuration.Kill.AddMapping(6, 5);
|
||||||
|
eventParser.Configuration.Kill.AddMapping(4, 6);
|
||||||
|
eventParser.Configuration.Kill.AddMapping(2, 7);
|
||||||
|
eventParser.Configuration.Kill.AddMapping(8, 8);
|
||||||
|
eventParser.Configuration.Kill.AddMapping(9, 9);
|
||||||
|
|
||||||
|
eventParser.Configuration.Time.Pattern = '^L [01]\\d/[0-3]\\d/\\d+ - [0-2]\\d:[0-5]\\d:[0-5]\\d:';
|
||||||
|
|
||||||
|
rconParser.Version = 'CSGOSM';
|
||||||
|
rconParser.GameName = 10; // CSGO
|
||||||
|
eventParser.Version = 'CSGOSM';
|
||||||
|
eventParser.GameName = 10; // CSGO
|
||||||
|
},
|
||||||
|
|
||||||
|
onUnloadAsync: function () {
|
||||||
|
},
|
||||||
|
|
||||||
|
onTickAsync: function (server) {
|
||||||
|
}
|
||||||
|
};
|
@ -3,7 +3,7 @@ var eventParser;
|
|||||||
|
|
||||||
var plugin = {
|
var plugin = {
|
||||||
author: 'RaidMax',
|
author: 'RaidMax',
|
||||||
version: 0.6,
|
version: 0.8,
|
||||||
name: 'Plutonium IW5 Parser',
|
name: 'Plutonium IW5 Parser',
|
||||||
isParser: true,
|
isParser: true,
|
||||||
|
|
||||||
@ -20,6 +20,7 @@ var plugin = {
|
|||||||
rconParser.Configuration.CommandPrefixes.Ban = 'clientkick {0} "{1}"';
|
rconParser.Configuration.CommandPrefixes.Ban = 'clientkick {0} "{1}"';
|
||||||
rconParser.Configuration.CommandPrefixes.TempBan = 'clientkick {0} "{1}"';
|
rconParser.Configuration.CommandPrefixes.TempBan = 'clientkick {0} "{1}"';
|
||||||
rconParser.Configuration.CommandPrefixes.RConGetDvar = '\xff\xff\xff\xffrcon {0} get {1}';
|
rconParser.Configuration.CommandPrefixes.RConGetDvar = '\xff\xff\xff\xffrcon {0} get {1}';
|
||||||
|
rconParser.Configuration.CommandPrefixes.RConResponse = '\xff\xff\xff\xffprint\n';
|
||||||
|
|
||||||
rconParser.Configuration.Dvar.Pattern = '^(.+) is "(.+)?"';
|
rconParser.Configuration.Dvar.Pattern = '^(.+) is "(.+)?"';
|
||||||
rconParser.Configuration.Dvar.AddMapping(106, 1);
|
rconParser.Configuration.Dvar.AddMapping(106, 1);
|
||||||
@ -28,15 +29,13 @@ var plugin = {
|
|||||||
rconParser.Configuration.CanGenerateLogPath = true;
|
rconParser.Configuration.CanGenerateLogPath = true;
|
||||||
rconParser.Configuration.NoticeLineSeparator = '. ';
|
rconParser.Configuration.NoticeLineSeparator = '. ';
|
||||||
|
|
||||||
rconParser.Configuration.StatusHeader.Pattern = 'num +score +bot +ping +guid +name +lastmsg +address +qport +rate *';
|
rconParser.Configuration.StatusHeader.Pattern = 'num +score +bot +ping +guid +name +address +qport *';
|
||||||
rconParser.Configuration.Status.Pattern = '^ *([0-9]+) +-?([0-9]+) +(?:[0-1]{1}) +([0-9]{1,4}|[A-Z]{4}) +([a-f|A-F|0-9]{16}) +(.+?) +(?:[0-9]+) +(\\d+\\.\\d+\\.\\d+\\.\\d+\\:-?\\d{1,5}|0+\\.0+:-?\\d{1,5}|loopback) +(?:-?[0-9]+) +(?:[0-9]+) *$';
|
rconParser.Configuration.Status.Pattern = '^ *([0-9]+) +-?([0-9]+) +(0|1) +((?:[A-Z]+|[0-9]+)) +((?:[a-z]|[0-9]){8,32}|(?:[a-z]|[0-9]){8,32}|bot[0-9]+|(?:[0-9]+)) *(.{0,32}) +(\\d+\\.\\d+\\.\\d+.\\d+\\:-*\\d{1,5}|0+.0+:-*\\d{1,5}|loopback|unknown|bot) +(-*[0-9]+) *$';
|
||||||
rconParser.Configuration.Status.AddMapping(100, 1);
|
rconParser.Configuration.Status.AddMapping(102, 4);
|
||||||
rconParser.Configuration.Status.AddMapping(101, 2);
|
rconParser.Configuration.Status.AddMapping(103, 5);
|
||||||
rconParser.Configuration.Status.AddMapping(102, 3);
|
rconParser.Configuration.Status.AddMapping(104, 6);
|
||||||
rconParser.Configuration.Status.AddMapping(103, 4);
|
|
||||||
rconParser.Configuration.Status.AddMapping(104, 5);
|
|
||||||
rconParser.Configuration.Status.AddMapping(105, 6);
|
|
||||||
|
|
||||||
|
rconParser.IsOneLog = true;
|
||||||
rconParser.Version = 'IW5 MP 1.9 build 388110 Fri Sep 14 00:04:28 2012 win-x86';
|
rconParser.Version = 'IW5 MP 1.9 build 388110 Fri Sep 14 00:04:28 2012 win-x86';
|
||||||
rconParser.GameName = 3; // IW5
|
rconParser.GameName = 3; // IW5
|
||||||
eventParser.Version = 'IW5 MP 1.9 build 388110 Fri Sep 14 00:04:28 2012 win-x86';
|
eventParser.Version = 'IW5 MP 1.9 build 388110 Fri Sep 14 00:04:28 2012 win-x86';
|
||||||
|
@ -3,7 +3,7 @@ var eventParser;
|
|||||||
|
|
||||||
var plugin = {
|
var plugin = {
|
||||||
author: 'RaidMax, Xerxes',
|
author: 'RaidMax, Xerxes',
|
||||||
version: 0.9,
|
version: 0.10,
|
||||||
name: 'Plutonium T6 Parser',
|
name: 'Plutonium T6 Parser',
|
||||||
isParser: true,
|
isParser: true,
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ var plugin = {
|
|||||||
rconParser.Configuration.Status.AddMapping(104, 5);
|
rconParser.Configuration.Status.AddMapping(104, 5);
|
||||||
rconParser.Configuration.Status.AddMapping(105, 6);
|
rconParser.Configuration.Status.AddMapping(105, 6);
|
||||||
|
|
||||||
eventParser.Configuration.GameDirectory = 't6r\\data';
|
eventParser.Configuration.GameDirectory = 't6';
|
||||||
eventParser.Configuration.GuidNumberStyle = 7; // Integer
|
eventParser.Configuration.GuidNumberStyle = 7; // Integer
|
||||||
|
|
||||||
rconParser.Version = 'Call of Duty Multiplayer - Ship COD_T6_S MP build 1.0.44 CL(1759941) CODPCAB2 CEG Fri May 9 19:19:19 2014 win-x86 813e66d5';
|
rconParser.Version = 'Call of Duty Multiplayer - Ship COD_T6_S MP build 1.0.44 CL(1759941) CODPCAB2 CEG Fri May 9 19:19:19 2014 win-x86 813e66d5';
|
||||||
|
37
Plugins/ScriptPlugins/ParserPlutoniumT4.js
Normal file
37
Plugins/ScriptPlugins/ParserPlutoniumT4.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
var rconParser;
|
||||||
|
var eventParser;
|
||||||
|
|
||||||
|
var plugin = {
|
||||||
|
author: 'RaidMax, Chase',
|
||||||
|
version: 0.2,
|
||||||
|
name: 'Plutonium T4 Parser',
|
||||||
|
isParser: true,
|
||||||
|
|
||||||
|
onEventAsync: function (gameEvent, server) {
|
||||||
|
},
|
||||||
|
|
||||||
|
onLoadAsync: function (manager) {
|
||||||
|
rconParser = manager.GenerateDynamicRConParser(this.name);
|
||||||
|
eventParser = manager.GenerateDynamicEventParser(this.name);
|
||||||
|
|
||||||
|
rconParser.Configuration.CommandPrefixes.Kick = 'clientkick {0}';
|
||||||
|
rconParser.Configuration.CommandPrefixes.Ban = 'clientkick {0}';
|
||||||
|
rconParser.Configuration.CommandPrefixes.TempBan = 'clientkick {0}';
|
||||||
|
rconParser.Configuration.CommandPrefixes.RConResponse = '\xff\xff\xff\xffprint\n';
|
||||||
|
rconParser.Configuration.GuidNumberStyle = 7; // Integer
|
||||||
|
|
||||||
|
rconParser.Version = 'Plutonium T4';
|
||||||
|
rconParser.GameName = 5; // T4
|
||||||
|
|
||||||
|
eventParser.Configuration.GuidNumberStyle = 7; // Integer
|
||||||
|
eventParser.Configuration.GameDirectory = 'raw';
|
||||||
|
|
||||||
|
eventParser.Version = 'Plutonium T4';
|
||||||
|
},
|
||||||
|
|
||||||
|
onUnloadAsync: function () {
|
||||||
|
},
|
||||||
|
|
||||||
|
onTickAsync: function (server) {
|
||||||
|
}
|
||||||
|
};
|
39
Plugins/ScriptPlugins/ParserS1x.js
Normal file
39
Plugins/ScriptPlugins/ParserS1x.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
var rconParser;
|
||||||
|
var eventParser;
|
||||||
|
|
||||||
|
var plugin = {
|
||||||
|
author: 'Diavolo, RaidMax',
|
||||||
|
version: 0.1,
|
||||||
|
name: 'S1x Parser',
|
||||||
|
isParser: true,
|
||||||
|
|
||||||
|
onEventAsync: function(gameEvent, server) {},
|
||||||
|
|
||||||
|
onLoadAsync: function(manager) {
|
||||||
|
rconParser = manager.GenerateDynamicRConParser(this.name);
|
||||||
|
eventParser = manager.GenerateDynamicEventParser(this.name);
|
||||||
|
|
||||||
|
rconParser.Configuration.CommandPrefixes.Kick = 'kickClient {0} "{1}"';
|
||||||
|
rconParser.Configuration.CommandPrefixes.Ban = 'kickClient {0} "{1}"';
|
||||||
|
rconParser.Configuration.CommandPrefixes.TempBan = 'kickClient {0} "{1}"';
|
||||||
|
rconParser.Configuration.CommandPrefixes.RConResponse = '\xff\xff\xff\xffprint';
|
||||||
|
rconParser.Configuration.Dvar.Pattern = '^ *\\"(.+)\\" is: \\"(.+)?\\" default: \\"(.+)?\\"\\n(?:latched: \\"(.+)?\\"\\n)? *(.+)$';
|
||||||
|
rconParser.Configuration.Status.Pattern = '^ *([0-9]+) +-?([0-9]+) +(Yes|No) +((?:[A-Z]+|[0-9]+)) +((?:[a-z]|[0-9]){8,32}|(?:[a-z]|[0-9]){8,32}|bot[0-9]+|(?:[0-9]+)) *(.{0,32}) +(\\d+\\.\\d+\\.\\d+.\\d+\\:-*\\d{1,5}|0+.0+:-*\\d{1,5}|loopback|unknown|bot) +(-*[0-9]+) *$';
|
||||||
|
rconParser.Configuration.StatusHeader.Pattern = 'num +score +bot +ping +guid +name +address +qport *';
|
||||||
|
rconParser.Configuration.Status.AddMapping(102, 4);
|
||||||
|
rconParser.Configuration.Status.AddMapping(103, 5);
|
||||||
|
rconParser.Configuration.Status.AddMapping(104, 6);
|
||||||
|
rconParser.Configuration.WaitForResponse = false;
|
||||||
|
|
||||||
|
eventParser.Configuration.GameDirectory = '';
|
||||||
|
|
||||||
|
rconParser.Version = 'S1 MP 1.22 build 2195988 Wed Apr 18 11:26:14 2018 win64';
|
||||||
|
rconParser.GameName = 9; // SHG1
|
||||||
|
eventParser.Version = 'S1 MP 1.22 build 2195988 Wed Apr 18 11:26:14 2018 win64';
|
||||||
|
eventParser.GameName = 9; // SHG1
|
||||||
|
},
|
||||||
|
|
||||||
|
onUnloadAsync: function() {},
|
||||||
|
|
||||||
|
onTickAsync: function(server) {}
|
||||||
|
};
|
@ -26,7 +26,7 @@ var plugin = {
|
|||||||
rconParser.Configuration.GametypeStatus.Pattern = 'Gametype: (.+)';
|
rconParser.Configuration.GametypeStatus.Pattern = 'Gametype: (.+)';
|
||||||
rconParser.Configuration.MapStatus.Pattern = 'Map: (.+)';
|
rconParser.Configuration.MapStatus.Pattern = 'Map: (.+)';
|
||||||
rconParser.Configuration.CommandPrefixes.RConGetInfo = undefined; // disables this, because it's useless on T7
|
rconParser.Configuration.CommandPrefixes.RConGetInfo = undefined; // disables this, because it's useless on T7
|
||||||
rconParser.Configuration.ServerNotRunningResponse = 'this is here to prevent a hiberating server from being detected as not running';
|
rconParser.Configuration.ServerNotRunningResponse = 'this is here to prevent a hibernating server from being detected as not running';
|
||||||
|
|
||||||
rconParser.Configuration.OverrideDvarNameMapping.Add('sv_hostname', 'live_steam_server_name');
|
rconParser.Configuration.OverrideDvarNameMapping.Add('sv_hostname', 'live_steam_server_name');
|
||||||
rconParser.Configuration.DefaultDvarValues.Add('sv_running', '1');
|
rconParser.Configuration.DefaultDvarValues.Add('sv_running', '1');
|
||||||
|
@ -39,7 +39,7 @@ let commands = [{
|
|||||||
|
|
||||||
let plugin = {
|
let plugin = {
|
||||||
author: 'RaidMax',
|
author: 'RaidMax',
|
||||||
version: 1.0,
|
version: 1.1,
|
||||||
name: 'Ping Pong Sample Command Plugin',
|
name: 'Ping Pong Sample Command Plugin',
|
||||||
|
|
||||||
onEventAsync: function (gameEvent, server) {
|
onEventAsync: function (gameEvent, server) {
|
||||||
@ -48,6 +48,38 @@ let plugin = {
|
|||||||
onLoadAsync: function (manager) {
|
onLoadAsync: function (manager) {
|
||||||
this.logger = _serviceResolver.ResolveService("ILogger");
|
this.logger = _serviceResolver.ResolveService("ILogger");
|
||||||
this.logger.WriteDebug("sample plugin loaded");
|
this.logger.WriteDebug("sample plugin loaded");
|
||||||
|
|
||||||
|
const intArray = [
|
||||||
|
1337,
|
||||||
|
1505,
|
||||||
|
999
|
||||||
|
];
|
||||||
|
|
||||||
|
const stringArray = [
|
||||||
|
"ping",
|
||||||
|
"pong",
|
||||||
|
"hello"
|
||||||
|
];
|
||||||
|
|
||||||
|
this.configHandler = _configHandler;
|
||||||
|
|
||||||
|
this.configHandler.SetValue("SampleIntegerValue", 123);
|
||||||
|
this.configHandler.SetValue("SampleStringValue", this.author);
|
||||||
|
this.configHandler.SetValue("SampleFloatValue", this.version);
|
||||||
|
this.configHandler.SetValue("SampleNumericalArray", intArray);
|
||||||
|
this.configHandler.SetValue("SampleStringArray", stringArray);
|
||||||
|
|
||||||
|
this.logger.WriteDebug(this.configHandler.GetValue("SampleIntegerValue"));
|
||||||
|
this.logger.WriteDebug(this.configHandler.GetValue("SampleStringValue"));
|
||||||
|
this.logger.WriteDebug(this.configHandler.GetValue("SampleFloatValue"));
|
||||||
|
|
||||||
|
this.configHandler.GetValue("SampleNumericalArray").forEach((element) => {
|
||||||
|
this.logger.WriteDebug(element);
|
||||||
|
});
|
||||||
|
|
||||||
|
this.configHandler.GetValue("SampleStringArray").forEach((element) => {
|
||||||
|
this.logger.WriteDebug(element);
|
||||||
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
onUnloadAsync: function () {
|
onUnloadAsync: function () {
|
||||||
|
@ -26,6 +26,8 @@ var plugin = {
|
|||||||
try {
|
try {
|
||||||
var cl = new System.Net.Http.HttpClient();
|
var cl = new System.Net.Http.HttpClient();
|
||||||
var re = cl.GetAsync('https://api.xdefcon.com/proxy/check/?ip=' + origin.IPAddressString).Result;
|
var re = cl.GetAsync('https://api.xdefcon.com/proxy/check/?ip=' + origin.IPAddressString).Result;
|
||||||
|
var userAgent = 'IW4MAdmin-' + this.manager.GetApplicationSettings().Configuration().Id;
|
||||||
|
cl.DefaultRequestHeaders.Add('User-Agent', userAgent);
|
||||||
var co = re.Content;
|
var co = re.Content;
|
||||||
var parsedJSON = JSON.parse(co.ReadAsStringAsync().Result);
|
var parsedJSON = JSON.parse(co.ReadAsStringAsync().Result);
|
||||||
co.Dispose();
|
co.Dispose();
|
||||||
@ -38,7 +40,12 @@ var plugin = {
|
|||||||
|
|
||||||
if (usingVPN) {
|
if (usingVPN) {
|
||||||
this.logger.WriteInfo(origin + ' is using a VPN (' + origin.IPAddressString + ')');
|
this.logger.WriteInfo(origin + ' is using a VPN (' + origin.IPAddressString + ')');
|
||||||
origin.Kick(_localization.LocalizationIndex["SERVER_KICK_VPNS_NOTALLOWED"], _IW4MAdminClient);
|
var contactUrl = this.manager.GetApplicationSettings().Configuration().ContactUri;
|
||||||
|
var additionalInfo = '';
|
||||||
|
if (contactUrl) {
|
||||||
|
additionalInfo = _localization.LocalizationIndex["SERVER_KICK_VPNS_NOTALLOWED_INFO"] + ' ' + contactUrl;
|
||||||
|
}
|
||||||
|
origin.Kick(_localization.LocalizationIndex["SERVER_KICK_VPNS_NOTALLOWED"] + ' ' + additionalInfo, _IW4MAdminClient);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -176,6 +176,12 @@ namespace IW4MAdmin.Plugins.Stats.Client
|
|||||||
|
|
||||||
foreach (var hitInfo in new[] {attackerHitInfo, victimHitInfo})
|
foreach (var hitInfo in new[] {attackerHitInfo, victimHitInfo})
|
||||||
{
|
{
|
||||||
|
if (hitInfo.MeansOfDeath == null || hitInfo.Location == null || hitInfo.Weapon == null)
|
||||||
|
{
|
||||||
|
_logger.LogDebug("Skipping hit because it does not contain the required data");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await _onTransaction.WaitAsync();
|
await _onTransaction.WaitAsync();
|
||||||
|
@ -50,11 +50,19 @@ namespace Stats.Client
|
|||||||
EntityId = entityId,
|
EntityId = entityId,
|
||||||
IsVictim = isVictim,
|
IsVictim = isVictim,
|
||||||
HitType = hitType,
|
HitType = hitType,
|
||||||
Damage = Math.Min(MaximumDamage, int.Parse(log[(uint) ParserRegex.GroupType.Damage])),
|
Damage = Math.Min(MaximumDamage,
|
||||||
Location = log[(uint) ParserRegex.GroupType.HitLocation],
|
log.Length > (uint) ParserRegex.GroupType.Damage
|
||||||
Weapon = _weaponNameParser.Parse(log[(uint) ParserRegex.GroupType.Weapon], gameName),
|
? int.Parse(log[(uint) ParserRegex.GroupType.Damage])
|
||||||
MeansOfDeath = log[(uint)ParserRegex.GroupType.MeansOfDeath],
|
: 0),
|
||||||
Game = (Reference.Game)gameName
|
Location = log.Length > (uint) ParserRegex.GroupType.HitLocation
|
||||||
|
? log[(uint) ParserRegex.GroupType.HitLocation]
|
||||||
|
: "Unknown",
|
||||||
|
Weapon = log.Length == 10 ? _weaponNameParser.Parse(log[8], gameName)
|
||||||
|
: _weaponNameParser.Parse(log[(uint) ParserRegex.GroupType.Weapon], gameName),
|
||||||
|
MeansOfDeath = log.Length > (uint) ParserRegex.GroupType.MeansOfDeath
|
||||||
|
? log[(uint) ParserRegex.GroupType.MeansOfDeath]
|
||||||
|
: "Unknown",
|
||||||
|
Game = (Reference.Game) gameName
|
||||||
};
|
};
|
||||||
|
|
||||||
//_logger.LogDebug("Generated new hitInfo {@hitInfo}", hitInfo);
|
//_logger.LogDebug("Generated new hitInfo {@hitInfo}", hitInfo);
|
||||||
|
@ -6,6 +6,7 @@ using System.Linq;
|
|||||||
using IW4MAdmin.Plugins.Stats.Config;
|
using IW4MAdmin.Plugins.Stats.Config;
|
||||||
using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
|
using Stats.Config;
|
||||||
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
using ILogger = Microsoft.Extensions.Logging.ILogger;
|
||||||
|
|
||||||
namespace Stats.Client
|
namespace Stats.Client
|
||||||
@ -24,22 +25,16 @@ namespace Stats.Client
|
|||||||
public WeaponInfo Parse(string weaponName, Server.Game gameName)
|
public WeaponInfo Parse(string weaponName, Server.Game gameName)
|
||||||
{
|
{
|
||||||
var configForGame = _config.WeaponNameParserConfigurations
|
var configForGame = _config.WeaponNameParserConfigurations
|
||||||
?.FirstOrDefault(config => config.Game == gameName);
|
?.FirstOrDefault(config => config.Game == gameName) ?? new WeaponNameParserConfiguration()
|
||||||
|
|
||||||
if (configForGame == null)
|
|
||||||
{
|
{
|
||||||
_logger.LogWarning("No weapon parser config available for game {game}", gameName);
|
Game = gameName
|
||||||
return new WeaponInfo()
|
};
|
||||||
{
|
|
||||||
Name = "Unknown"
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
var splitWeaponName = weaponName.Split(configForGame.Delimiters);
|
var splitWeaponName = weaponName.Split(configForGame.Delimiters);
|
||||||
|
|
||||||
if (!splitWeaponName.Any())
|
if (!splitWeaponName.Any())
|
||||||
{
|
{
|
||||||
_logger.LogError("Could not parse weapon name {weapon}", weaponName);
|
_logger.LogError("Could not parse weapon name {Weapon}", weaponName);
|
||||||
|
|
||||||
return new WeaponInfo()
|
return new WeaponInfo()
|
||||||
{
|
{
|
||||||
@ -48,8 +43,10 @@ namespace Stats.Client
|
|||||||
}
|
}
|
||||||
|
|
||||||
// remove the _mp suffix
|
// remove the _mp suffix
|
||||||
var filtered = splitWeaponName.Where(part => part != configForGame.WeaponSuffix);
|
var filtered = splitWeaponName
|
||||||
var baseName = splitWeaponName.First();
|
.Where(part => part != configForGame.WeaponSuffix && part != configForGame.WeaponPrefix)
|
||||||
|
.ToList();
|
||||||
|
var baseName = filtered.First();
|
||||||
var attachments = new List<string>();
|
var attachments = new List<string>();
|
||||||
|
|
||||||
if (filtered.Count() > 1)
|
if (filtered.Count() > 1)
|
||||||
@ -67,8 +64,6 @@ namespace Stats.Client
|
|||||||
}).ToList()
|
}).ToList()
|
||||||
};
|
};
|
||||||
|
|
||||||
// _logger.LogDebug("Parsed weapon info {@info}", weaponInfo);
|
|
||||||
|
|
||||||
return weaponInfo;
|
return weaponInfo;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,12 @@ namespace IW4MAdmin.Plugins.Stats.Config
|
|||||||
|
|
||||||
public WeaponNameParserConfiguration[] WeaponNameParserConfigurations { get; set; } = new[]
|
public WeaponNameParserConfiguration[] WeaponNameParserConfigurations { get; set; } = new[]
|
||||||
{
|
{
|
||||||
|
new WeaponNameParserConfiguration()
|
||||||
|
{
|
||||||
|
Game = Server.Game.IW3,
|
||||||
|
WeaponSuffix = "mp",
|
||||||
|
Delimiters = new[] {'_'}
|
||||||
|
},
|
||||||
new WeaponNameParserConfiguration()
|
new WeaponNameParserConfiguration()
|
||||||
{
|
{
|
||||||
Game = Server.Game.IW4,
|
Game = Server.Game.IW4,
|
||||||
@ -27,6 +33,13 @@ namespace IW4MAdmin.Plugins.Stats.Config
|
|||||||
Delimiters = new[] {'_'}
|
Delimiters = new[] {'_'}
|
||||||
},
|
},
|
||||||
new WeaponNameParserConfiguration()
|
new WeaponNameParserConfiguration()
|
||||||
|
{
|
||||||
|
Game = Server.Game.IW5,
|
||||||
|
WeaponSuffix = "mp",
|
||||||
|
WeaponPrefix = "iw5",
|
||||||
|
Delimiters = new[] {'_'}
|
||||||
|
},
|
||||||
|
new WeaponNameParserConfiguration()
|
||||||
{
|
{
|
||||||
Game = Server.Game.T6,
|
Game = Server.Game.T6,
|
||||||
WeaponSuffix = "mp",
|
WeaponSuffix = "mp",
|
||||||
|
@ -7,5 +7,6 @@ namespace Stats.Config
|
|||||||
public Server.Game Game { get; set; }
|
public Server.Game Game { get; set; }
|
||||||
public char[] Delimiters { get; set; }
|
public char[] Delimiters { get; set; }
|
||||||
public string WeaponSuffix { get; set; }
|
public string WeaponSuffix { get; set; }
|
||||||
|
public string WeaponPrefix { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
using SharedLibraryCore;
|
using SharedLibraryCore;
|
||||||
using SharedLibraryCore.Interfaces;
|
using SharedLibraryCore.Interfaces;
|
||||||
using SharedLibraryCore.Database.Models;
|
using SharedLibraryCore.Database.Models;
|
||||||
@ -28,7 +27,8 @@ namespace IW4MAdmin.Plugins.Welcome
|
|||||||
|
|
||||||
public Plugin(IConfigurationHandlerFactory configurationHandlerFactory, IDatabaseContextFactory contextFactory)
|
public Plugin(IConfigurationHandlerFactory configurationHandlerFactory, IDatabaseContextFactory contextFactory)
|
||||||
{
|
{
|
||||||
_configHandler = configurationHandlerFactory.GetConfigurationHandler<WelcomeConfiguration>("WelcomePluginSettings");
|
_configHandler =
|
||||||
|
configurationHandlerFactory.GetConfigurationHandler<WelcomeConfiguration>("WelcomePluginSettings");
|
||||||
_contextFactory = contextFactory;
|
_contextFactory = contextFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ namespace IW4MAdmin.Plugins.Welcome
|
|||||||
{
|
{
|
||||||
if (_configHandler.Configuration() == null)
|
if (_configHandler.Configuration() == null)
|
||||||
{
|
{
|
||||||
_configHandler.Set((WelcomeConfiguration)new WelcomeConfiguration().Generate());
|
_configHandler.Set((WelcomeConfiguration) new WelcomeConfiguration().Generate());
|
||||||
await _configHandler.Save();
|
await _configHandler.Save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,9 +49,14 @@ namespace IW4MAdmin.Plugins.Welcome
|
|||||||
{
|
{
|
||||||
if (E.Type == GameEvent.EventType.Join)
|
if (E.Type == GameEvent.EventType.Join)
|
||||||
{
|
{
|
||||||
EFClient newPlayer = E.Origin;
|
var newPlayer = E.Origin;
|
||||||
if (newPlayer.Level >= Permission.Trusted && !E.Origin.Masked || !string.IsNullOrEmpty(newPlayer.GetAdditionalProperty<string>("ClientTag")))
|
if ((newPlayer.Level >= Permission.Trusted && !E.Origin.Masked) ||
|
||||||
E.Owner.Broadcast(await ProcessAnnouncement(_configHandler.Configuration().PrivilegedAnnouncementMessage, newPlayer));
|
(!string.IsNullOrEmpty(newPlayer.GetAdditionalProperty<string>("ClientTag")) &&
|
||||||
|
newPlayer.Level != Permission.Flagged && newPlayer.Level != Permission.Banned &&
|
||||||
|
!newPlayer.Masked))
|
||||||
|
E.Owner.Broadcast(
|
||||||
|
await ProcessAnnouncement(_configHandler.Configuration().PrivilegedAnnouncementMessage,
|
||||||
|
newPlayer));
|
||||||
|
|
||||||
newPlayer.Tell(await ProcessAnnouncement(_configHandler.Configuration().UserWelcomeMessage, newPlayer));
|
newPlayer.Tell(await ProcessAnnouncement(_configHandler.Configuration().UserWelcomeMessage, newPlayer));
|
||||||
|
|
||||||
@ -71,19 +76,22 @@ namespace IW4MAdmin.Plugins.Welcome
|
|||||||
E.Owner.ToAdmins($"^1NOTICE: ^7Flagged player ^5{newPlayer.Name} ^7({penaltyReason}) has joined!");
|
E.Owner.ToAdmins($"^1NOTICE: ^7Flagged player ^5{newPlayer.Name} ^7({penaltyReason}) has joined!");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
E.Owner.Broadcast(await ProcessAnnouncement(_configHandler.Configuration().UserAnnouncementMessage, newPlayer));
|
E.Owner.Broadcast(await ProcessAnnouncement(_configHandler.Configuration().UserAnnouncementMessage,
|
||||||
|
newPlayer));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<string> ProcessAnnouncement(string msg, EFClient joining)
|
private async Task<string> ProcessAnnouncement(string msg, EFClient joining)
|
||||||
{
|
{
|
||||||
msg = msg.Replace("{{ClientName}}", joining.Name);
|
msg = msg.Replace("{{ClientName}}", joining.Name);
|
||||||
msg = msg.Replace("{{ClientLevel}}", $"{Utilities.ConvertLevelToColor(joining.Level, joining.ClientPermission.Name)}{(string.IsNullOrEmpty(joining.GetAdditionalProperty<string>("ClientTag")) ? "" : $" ^7({joining.GetAdditionalProperty<string>("ClientTag")}^7)")}");
|
msg = msg.Replace("{{ClientLevel}}",
|
||||||
|
$"{Utilities.ConvertLevelToColor(joining.Level, joining.ClientPermission.Name)}{(string.IsNullOrEmpty(joining.GetAdditionalProperty<string>("ClientTag")) ? "" : $" ^7({joining.GetAdditionalProperty<string>("ClientTag")}^7)")}");
|
||||||
// this prevents it from trying to evaluate it every message
|
// this prevents it from trying to evaluate it every message
|
||||||
if (msg.Contains("{{ClientLocation}}"))
|
if (msg.Contains("{{ClientLocation}}"))
|
||||||
{
|
{
|
||||||
msg = msg.Replace("{{ClientLocation}}", await GetCountryName(joining.IPAddressString));
|
msg = msg.Replace("{{ClientLocation}}", await GetCountryName(joining.IPAddressString));
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = msg.Replace("{{TimesConnected}}", joining.Connections.Ordinalize());
|
msg = msg.Replace("{{TimesConnected}}", joining.Connections.Ordinalize());
|
||||||
|
|
||||||
return msg;
|
return msg;
|
||||||
@ -100,11 +108,14 @@ namespace IW4MAdmin.Plugins.Welcome
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string response = await wc.DownloadStringTaskAsync(new Uri($"http://extreme-ip-lookup.com/json/{ip}"));
|
string response =
|
||||||
var responseObj = JObject.Parse(response);
|
await wc.DownloadStringTaskAsync(new Uri($"http://extreme-ip-lookup.com/json/{ip}"));
|
||||||
|
var responseObj = JObject.Parse(response);
|
||||||
response = responseObj["country"].ToString();
|
response = responseObj["country"].ToString();
|
||||||
|
|
||||||
return string.IsNullOrEmpty(response) ? Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_WELCOME_UNKNOWN_COUNTRY"] : response;
|
return string.IsNullOrEmpty(response)
|
||||||
|
? Utilities.CurrentLocalization.LocalizationIndex["PLUGINS_WELCOME_UNKNOWN_COUNTRY"]
|
||||||
|
: response;
|
||||||
}
|
}
|
||||||
|
|
||||||
catch
|
catch
|
||||||
|
@ -22,7 +22,8 @@ namespace SharedLibraryCore.Commands
|
|||||||
E.Message = E.Data;
|
E.Message = E.Data;
|
||||||
|
|
||||||
Command C = null;
|
Command C = null;
|
||||||
foreach (Command cmd in Manager.GetCommands())
|
foreach (Command cmd in Manager.GetCommands()
|
||||||
|
.Where(c => c.Name != null))
|
||||||
{
|
{
|
||||||
if (cmd.Name.Equals(CommandString, StringComparison.OrdinalIgnoreCase) ||
|
if (cmd.Name.Equals(CommandString, StringComparison.OrdinalIgnoreCase) ||
|
||||||
(cmd.Alias ?? "").Equals(CommandString, StringComparison.OrdinalIgnoreCase))
|
(cmd.Alias ?? "").Equals(CommandString, StringComparison.OrdinalIgnoreCase))
|
||||||
|
@ -1359,13 +1359,13 @@ namespace SharedLibraryCore.Commands
|
|||||||
|
|
||||||
public override async Task ExecuteAsync(GameEvent E)
|
public override async Task ExecuteAsync(GameEvent E)
|
||||||
{
|
{
|
||||||
var Response = await E.Owner.ExecuteCommandAsync(E.Data.Trim());
|
var response = await E.Owner.ExecuteCommandAsync(E.Data.Trim());
|
||||||
foreach (string S in Response)
|
foreach (var item in response)
|
||||||
{
|
{
|
||||||
E.Origin.Tell(S);
|
E.Origin.Tell(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Response.Length == 0)
|
if (response.Length == 0)
|
||||||
{
|
{
|
||||||
E.Origin.Tell(_translationLookup["COMMANDS_RCON_SUCCESS"]);
|
E.Origin.Tell(_translationLookup["COMMANDS_RCON_SUCCESS"]);
|
||||||
}
|
}
|
||||||
@ -1435,6 +1435,7 @@ namespace SharedLibraryCore.Commands
|
|||||||
Alias = "pa";
|
Alias = "pa";
|
||||||
Permission = Permission.Owner;
|
Permission = Permission.Owner;
|
||||||
RequiresTarget = false;
|
RequiresTarget = false;
|
||||||
|
_contextFactory = contextFactory;
|
||||||
Arguments = new[]
|
Arguments = new[]
|
||||||
{
|
{
|
||||||
new CommandArgument()
|
new CommandArgument()
|
||||||
|
@ -1,23 +1,24 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Data.Models;
|
||||||
using Humanizer;
|
using Humanizer;
|
||||||
|
|
||||||
namespace SharedLibraryCore.Configuration
|
namespace SharedLibraryCore.Configuration
|
||||||
{
|
{
|
||||||
public class GameStringConfiguration : Dictionary<Server.Game, Dictionary<string, string>>
|
public class GameStringConfiguration : Dictionary<Reference.Game, Dictionary<string, string>>
|
||||||
{
|
{
|
||||||
public string GetStringForGame(string key, Server.Game game = Server.Game.IW4)
|
public string GetStringForGame(string key, Reference.Game? game = Reference.Game.IW4)
|
||||||
{
|
{
|
||||||
if (key == null)
|
if (key == null)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!ContainsKey(game))
|
if (!ContainsKey(game.Value))
|
||||||
{
|
{
|
||||||
return key.Transform(To.TitleCase);
|
return key.Transform(To.TitleCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
var strings = this[game];
|
var strings = this[game.Value];
|
||||||
return !strings.ContainsKey(key) ? key.Transform(To.TitleCase) : strings[key];
|
return !strings.ContainsKey(key) ? key.Transform(To.TitleCase) : strings[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -11,20 +11,20 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public enum GroupType
|
public enum GroupType
|
||||||
{
|
{
|
||||||
EventType,
|
EventType = 0,
|
||||||
OriginNetworkId,
|
OriginNetworkId = 1,
|
||||||
TargetNetworkId,
|
TargetNetworkId = 2,
|
||||||
OriginClientNumber,
|
OriginClientNumber = 3,
|
||||||
TargetClientNumber,
|
TargetClientNumber = 4,
|
||||||
OriginName,
|
OriginName = 5,
|
||||||
TargetName,
|
TargetName = 6,
|
||||||
OriginTeam,
|
OriginTeam = 7,
|
||||||
TargetTeam,
|
TargetTeam = 8,
|
||||||
Weapon,
|
Weapon = 9,
|
||||||
Damage,
|
Damage = 10,
|
||||||
MeansOfDeath,
|
MeansOfDeath = 11,
|
||||||
HitLocation,
|
HitLocation = 12,
|
||||||
Message,
|
Message = 13,
|
||||||
RConClientNumber = 100,
|
RConClientNumber = 100,
|
||||||
RConScore = 101,
|
RConScore = 101,
|
||||||
RConPing = 102,
|
RConPing = 102,
|
||||||
@ -38,6 +38,8 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
RConDvarDomain = 110,
|
RConDvarDomain = 110,
|
||||||
RConStatusMap = 111,
|
RConStatusMap = 111,
|
||||||
RConStatusGametype = 112,
|
RConStatusGametype = 112,
|
||||||
|
RConStatusHostname = 113,
|
||||||
|
RConStatusMaxPlayers = 114,
|
||||||
AdditionalGroup = 200
|
AdditionalGroup = 200
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,6 +45,16 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
ParserRegex Time { get; set; }
|
ParserRegex Time { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// stores the regex information for the map change game log
|
||||||
|
/// </summary>
|
||||||
|
ParserRegex MapChange { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// stores the regex information for the map end game log
|
||||||
|
/// </summary>
|
||||||
|
ParserRegex MapEnd { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// indicates the format expected for parsed guids
|
/// indicates the format expected for parsed guids
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -11,7 +11,8 @@
|
|||||||
/// <param name="ipAddress">ip address of the server</param>
|
/// <param name="ipAddress">ip address of the server</param>
|
||||||
/// <param name="port">port of the server</param>
|
/// <param name="port">port of the server</param>
|
||||||
/// <param name="password"> password of the server</param>
|
/// <param name="password"> password of the server</param>
|
||||||
|
/// <param name="rconEngine">engine to create the rcon connection to</param>
|
||||||
/// <returns>instance of rcon connection</returns>
|
/// <returns>instance of rcon connection</returns>
|
||||||
IRConConnection CreateConnection(string ipAddress, int port, string password);
|
IRConConnection CreateConnection(string ipAddress, int port, string password, string rconEngine);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using SharedLibraryCore.Database.Models;
|
|
||||||
using static SharedLibraryCore.Server;
|
using static SharedLibraryCore.Server;
|
||||||
|
|
||||||
namespace SharedLibraryCore.Interfaces
|
namespace SharedLibraryCore.Interfaces
|
||||||
@ -39,8 +37,8 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
/// get the list of connected clients from status response
|
/// get the list of connected clients from status response
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="connection">RCon connection to use</param>
|
/// <param name="connection">RCon connection to use</param>
|
||||||
/// <returns>list of clients, current map, and current gametype</returns>
|
/// <returns><see cref="IStatusResponse"/></returns>
|
||||||
Task<(List<EFClient>, string, string)> GetStatusAsync(IRConConnection connection);
|
Task<IStatusResponse> GetStatusAsync(IRConConnection connection);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// stores the RCon configuration
|
/// stores the RCon configuration
|
||||||
@ -50,23 +48,35 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// stores the game/client specific version (usually the value of the "version" DVAR)
|
/// stores the game/client specific version (usually the value of the "version" DVAR)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string Version { get; set; }
|
string Version { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// specifies the game name (usually the internal studio iteration ie: IW4, T5 etc...)
|
/// specifies the game name (usually the internal studio iteration ie: IW4, T5 etc...)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Game GameName { get; set; }
|
Game GameName { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// indicates if the game supports generating a log path from DVAR retrieval
|
/// indicates if the game supports generating a log path from DVAR retrieval
|
||||||
/// of fs_game, fs_basepath, g_log
|
/// of fs_game, fs_basepath, g_log
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool CanGenerateLogPath { get; set; }
|
bool CanGenerateLogPath { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// specifies the name of the parser
|
/// specifies the name of the parser
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string Name { get; set; }
|
string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// specifies the type of rcon engine
|
||||||
|
/// eg: COD, Source
|
||||||
|
/// </summary>
|
||||||
|
string RConEngine { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// indicates that the game does not log to the mods folder (when mod is loaded),
|
||||||
|
/// but rather always to the fs_basegame directory
|
||||||
|
/// </summary>
|
||||||
|
bool IsOneLog { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// retrieves the value of given dvar key if it exists in the override dict
|
/// retrieves the value of given dvar key if it exists in the override dict
|
||||||
|
@ -9,59 +9,69 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// stores the command format for console commands
|
/// stores the command format for console commands
|
||||||
/// </summary>
|
/// </summary>
|
||||||
CommandPrefix CommandPrefixes { get; set; }
|
CommandPrefix CommandPrefixes { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// stores the regex info for parsing get status response
|
/// stores the regex info for parsing get status response
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ParserRegex Status { get; set; }
|
ParserRegex Status { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// stores regex info for parsing the map line from rcon status response
|
/// stores regex info for parsing the map line from rcon status response
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ParserRegex MapStatus { get; set; }
|
ParserRegex MapStatus { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// stores regex info for parsing the gametype line from rcon status response
|
/// stores regex info for parsing the gametype line from rcon status response
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ParserRegex GametypeStatus { get; set; }
|
ParserRegex GametypeStatus { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// stores regex info for parsing hostname line from rcon status response
|
||||||
|
/// </summary>
|
||||||
|
ParserRegex HostnameStatus { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// stores regex info for parsing max players line from rcon status response
|
||||||
|
/// </summary>
|
||||||
|
ParserRegex MaxPlayersStatus { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// stores the regex info for parsing get DVAR responses
|
/// stores the regex info for parsing get DVAR responses
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ParserRegex Dvar { get; set; }
|
ParserRegex Dvar { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// stores the regex info for parsing the header of a status response
|
/// stores the regex info for parsing the header of a status response
|
||||||
/// </summary>
|
/// </summary>
|
||||||
ParserRegex StatusHeader { get; set; }
|
ParserRegex StatusHeader { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Specifies the expected response message from rcon when the server is not running
|
/// Specifies the expected response message from rcon when the server is not running
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string ServerNotRunningResponse { get; set; }
|
string ServerNotRunningResponse { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// indicates if the application should wait for response from server
|
/// indicates if the application should wait for response from server
|
||||||
/// when executing a command
|
/// when executing a command
|
||||||
/// </summary>
|
/// </summary>
|
||||||
bool WaitForResponse { get; set; }
|
bool WaitForResponse { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// indicates the format expected for parsed guids
|
/// indicates the format expected for parsed guids
|
||||||
/// </summary>
|
/// </summary>
|
||||||
NumberStyles GuidNumberStyle { get; set; }
|
NumberStyles GuidNumberStyle { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// specifies simple mappings for dvar names in scenarios where the needed
|
/// specifies simple mappings for dvar names in scenarios where the needed
|
||||||
/// information is not stored in a traditional dvar name
|
/// information is not stored in a traditional dvar name
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IDictionary<string, string> OverrideDvarNameMapping { get; set; }
|
IDictionary<string, string> OverrideDvarNameMapping { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// specifies the default dvar values for games that don't support certain dvars
|
/// specifies the default dvar values for games that don't support certain dvars
|
||||||
/// </summary>
|
/// </summary>
|
||||||
IDictionary<string, string> DefaultDvarValues { get; set; }
|
IDictionary<string, string> DefaultDvarValues { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// specifies how many lines can be used for ingame notice
|
/// specifies how many lines can be used for ingame notice
|
||||||
@ -71,11 +81,11 @@ namespace SharedLibraryCore.Interfaces
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// specifies how many characters can be displayed per notice line
|
/// specifies how many characters can be displayed per notice line
|
||||||
/// </summary>
|
/// </summary>
|
||||||
int NoticeMaxCharactersPerLine { get; set; }
|
int NoticeMaxCharactersPerLine { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// specifies the characters used to split a line
|
/// specifies the characters used to split a line
|
||||||
/// </summary>
|
/// </summary>
|
||||||
string NoticeLineSeparator { get; set; }
|
string NoticeLineSeparator { get; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
35
SharedLibraryCore/Interfaces/IStatusResponse.cs
Normal file
35
SharedLibraryCore/Interfaces/IStatusResponse.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
using SharedLibraryCore.Database.Models;
|
||||||
|
|
||||||
|
namespace SharedLibraryCore.Interfaces
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// describes the collection of data returned from a status query
|
||||||
|
/// </summary>
|
||||||
|
public interface IStatusResponse
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// name of the map
|
||||||
|
/// </summary>
|
||||||
|
string Map { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// gametype/mode
|
||||||
|
/// </summary>
|
||||||
|
string GameType { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// server name
|
||||||
|
/// </summary>
|
||||||
|
string Hostname { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// max number of players
|
||||||
|
/// </summary>
|
||||||
|
int? MaxClients { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// active clients
|
||||||
|
/// </summary>
|
||||||
|
EFClient[] Clients { get; }
|
||||||
|
}
|
||||||
|
}
|
@ -28,7 +28,9 @@ namespace SharedLibraryCore
|
|||||||
T4 = 5,
|
T4 = 5,
|
||||||
T5 = 6,
|
T5 = 6,
|
||||||
T6 = 7,
|
T6 = 7,
|
||||||
T7 = 8
|
T7 = 8,
|
||||||
|
SHG1 = 9,
|
||||||
|
CSGO = 10
|
||||||
}
|
}
|
||||||
|
|
||||||
public Server(ILogger<Server> logger, SharedLibraryCore.Interfaces.ILogger deprecatedLogger,
|
public Server(ILogger<Server> logger, SharedLibraryCore.Interfaces.ILogger deprecatedLogger,
|
||||||
@ -41,7 +43,6 @@ namespace SharedLibraryCore
|
|||||||
Manager = mgr;
|
Manager = mgr;
|
||||||
Logger = deprecatedLogger;
|
Logger = deprecatedLogger;
|
||||||
ServerConfig = config;
|
ServerConfig = config;
|
||||||
RemoteConnection = rconConnectionFactory.CreateConnection(IP, Port, Password);
|
|
||||||
EventProcessing = new SemaphoreSlim(1, 1);
|
EventProcessing = new SemaphoreSlim(1, 1);
|
||||||
Clients = new List<EFClient>(new EFClient[64]);
|
Clients = new List<EFClient>(new EFClient[64]);
|
||||||
Reports = new List<Report>();
|
Reports = new List<Report>();
|
||||||
@ -51,6 +52,7 @@ namespace SharedLibraryCore
|
|||||||
CustomSayEnabled = Manager.GetApplicationSettings().Configuration().EnableCustomSayName;
|
CustomSayEnabled = Manager.GetApplicationSettings().Configuration().EnableCustomSayName;
|
||||||
CustomSayName = Manager.GetApplicationSettings().Configuration().CustomSayName;
|
CustomSayName = Manager.GetApplicationSettings().Configuration().CustomSayName;
|
||||||
this.gameLogReaderFactory = gameLogReaderFactory;
|
this.gameLogReaderFactory = gameLogReaderFactory;
|
||||||
|
RConConnectionFactory = rconConnectionFactory;
|
||||||
ServerLogger = logger;
|
ServerLogger = logger;
|
||||||
InitializeTokens();
|
InitializeTokens();
|
||||||
InitializeAutoMessages();
|
InitializeAutoMessages();
|
||||||
@ -105,10 +107,10 @@ namespace SharedLibraryCore
|
|||||||
}
|
}
|
||||||
if (literal)
|
if (literal)
|
||||||
{
|
{
|
||||||
return GetClientsAsList().Where(p => p.Name?.ToLower() == pName.ToLower()).ToList();
|
return GetClientsAsList().Where(p => p.Name?.StripColors()?.ToLower() == pName.ToLower()).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
return GetClientsAsList().Where(p => (p.Name?.ToLower() ?? "").Contains(pName.ToLower())).ToList();
|
return GetClientsAsList().Where(p => (p.Name?.StripColors()?.ToLower() ?? "").Contains(pName.ToLower())).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual public Task<bool> ProcessUpdatesAsync(CancellationToken cts) => (Task<bool>)Task.CompletedTask;
|
virtual public Task<bool> ProcessUpdatesAsync(CancellationToken cts) => (Task<bool>)Task.CompletedTask;
|
||||||
@ -157,24 +159,28 @@ namespace SharedLibraryCore
|
|||||||
/// Send a message to a particular players
|
/// Send a message to a particular players
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="message">Message to send</param>
|
/// <param name="message">Message to send</param>
|
||||||
/// <param name="target">EFClient to send message to</param>
|
/// <param name="targetClient">EFClient to send message to</param>
|
||||||
protected async Task Tell(string message, EFClient target)
|
protected async Task Tell(string message, EFClient targetClient)
|
||||||
{
|
{
|
||||||
if (!Utilities.IsDevelopment)
|
if (!Utilities.IsDevelopment)
|
||||||
{
|
{
|
||||||
|
var temporalClientId = targetClient.GetAdditionalProperty<string>("ConnectionClientId");
|
||||||
|
var parsedClientId = string.IsNullOrEmpty(temporalClientId) ? (int?)null : int.Parse(temporalClientId);
|
||||||
|
var clientNumber = parsedClientId ?? targetClient.ClientNumber;
|
||||||
|
|
||||||
var formattedMessage = string.Format(RconParser.Configuration.CommandPrefixes.Tell,
|
var formattedMessage = string.Format(RconParser.Configuration.CommandPrefixes.Tell,
|
||||||
target.ClientNumber,
|
clientNumber,
|
||||||
$"{(CustomSayEnabled && GameName == Game.IW4 ? $"{CustomSayName}: " : "")}{message.FixIW4ForwardSlash()}");
|
$"{(CustomSayEnabled && GameName == Game.IW4 ? $"{CustomSayName}: " : "")}{message.FixIW4ForwardSlash()}");
|
||||||
if (target.ClientNumber > -1 && message.Length > 0 && target.Level != EFClient.Permission.Console)
|
if (targetClient.ClientNumber > -1 && message.Length > 0 && targetClient.Level != EFClient.Permission.Console)
|
||||||
await this.ExecuteCommandAsync(formattedMessage);
|
await this.ExecuteCommandAsync(formattedMessage);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ServerLogger.LogDebug("Tell[{clientNumber}]->{message}", target.ClientNumber, message.StripColors());
|
ServerLogger.LogDebug("Tell[{clientNumber}]->{message}", targetClient.ClientNumber, message.StripColors());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (target.Level == EFClient.Permission.Console)
|
if (targetClient.Level == EFClient.Permission.Console)
|
||||||
{
|
{
|
||||||
Console.ForegroundColor = ConsoleColor.Green;
|
Console.ForegroundColor = ConsoleColor.Green;
|
||||||
using (LogContext.PushProperty("Server", ToString()))
|
using (LogContext.PushProperty("Server", ToString()))
|
||||||
@ -339,6 +345,7 @@ namespace SharedLibraryCore
|
|||||||
protected DateTime LastPoll;
|
protected DateTime LastPoll;
|
||||||
protected ManualResetEventSlim OnRemoteCommandResponse;
|
protected ManualResetEventSlim OnRemoteCommandResponse;
|
||||||
protected IGameLogReaderFactory gameLogReaderFactory;
|
protected IGameLogReaderFactory gameLogReaderFactory;
|
||||||
|
protected IRConConnectionFactory RConConnectionFactory;
|
||||||
|
|
||||||
// only here for performance
|
// only here for performance
|
||||||
private readonly bool CustomSayEnabled;
|
private readonly bool CustomSayEnabled;
|
||||||
|
@ -547,7 +547,8 @@ namespace SharedLibraryCore.Services
|
|||||||
|
|
||||||
public async Task<IList<PlayerInfo>> FindClientsByIdentifier(string identifier)
|
public async Task<IList<PlayerInfo>> FindClientsByIdentifier(string identifier)
|
||||||
{
|
{
|
||||||
if (identifier?.Length < 3)
|
var trimmedIdentifier = identifier?.Trim();
|
||||||
|
if (trimmedIdentifier?.Length < 3)
|
||||||
{
|
{
|
||||||
return new List<PlayerInfo>();
|
return new List<PlayerInfo>();
|
||||||
}
|
}
|
||||||
@ -556,11 +557,11 @@ namespace SharedLibraryCore.Services
|
|||||||
long? networkId = null;
|
long? networkId = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
networkId = identifier.ConvertGuidToLong(System.Globalization.NumberStyles.HexNumber);
|
networkId = trimmedIdentifier.ConvertGuidToLong(System.Globalization.NumberStyles.HexNumber);
|
||||||
}
|
}
|
||||||
catch { }
|
catch { }
|
||||||
|
|
||||||
int? ipAddress = identifier.ConvertToIP();
|
int? ipAddress = trimmedIdentifier.ConvertToIP();
|
||||||
|
|
||||||
IQueryable<EFAlias> iqLinkIds = context.Aliases.Where(_alias => _alias.Active);
|
IQueryable<EFAlias> iqLinkIds = context.Aliases.Where(_alias => _alias.Active);
|
||||||
|
|
||||||
@ -573,7 +574,7 @@ namespace SharedLibraryCore.Services
|
|||||||
// want to find them by name (wildcard)
|
// want to find them by name (wildcard)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
iqLinkIds = iqLinkIds.Where(_alias => EF.Functions.Like((_alias.SearchableName ?? _alias.Name.ToLower()), $"%{identifier.ToLower()}%"));
|
iqLinkIds = iqLinkIds.Where(_alias => EF.Functions.Like((_alias.SearchableName ?? _alias.Name.ToLower()), $"%{trimmedIdentifier.ToLower()}%"));
|
||||||
}
|
}
|
||||||
|
|
||||||
var linkIds = await iqLinkIds
|
var linkIds = await iqLinkIds
|
||||||
@ -728,21 +729,19 @@ namespace SharedLibraryCore.Services
|
|||||||
var result = new ResourceQueryHelperResult<FindClientResult>();
|
var result = new ResourceQueryHelperResult<FindClientResult>();
|
||||||
await using var context = _contextFactory.CreateContext(enableTracking: false);
|
await using var context = _contextFactory.CreateContext(enableTracking: false);
|
||||||
|
|
||||||
IQueryable<EFClient> iqClients = null;
|
IQueryable<Data.Models.Client.EFClient> iqClients = null;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(query.Xuid))
|
if (!string.IsNullOrEmpty(query.Xuid))
|
||||||
{
|
{
|
||||||
long networkId = query.Xuid.ConvertGuidToLong(System.Globalization.NumberStyles.HexNumber);
|
var networkId = query.Xuid.ConvertGuidToLong(System.Globalization.NumberStyles.HexNumber);
|
||||||
iqClients = context.Clients.
|
iqClients = context.Clients.Where(_client => _client.NetworkId == networkId);
|
||||||
Where(_client => _client.NetworkId == networkId)
|
|
||||||
.Select(client => client.ToPartialClient());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (!string.IsNullOrEmpty(query.Name))
|
else if (!string.IsNullOrEmpty(query.Name))
|
||||||
{
|
{
|
||||||
iqClients = context.Clients
|
iqClients = context.Clients
|
||||||
.Where(_client => EF.Functions.Like(_client.CurrentAlias.Name.ToLower(), $"%{query.Name.ToLower()}%"))
|
.Where(_client =>
|
||||||
.Select(client => client.ToPartialClient());
|
EF.Functions.Like(_client.CurrentAlias.Name.ToLower(), $"%{query.Name.ToLower()}%"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (query.Direction == SortDirection.Ascending)
|
if (query.Direction == SortDirection.Ascending)
|
||||||
|
@ -44,7 +44,7 @@
|
|||||||
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.1.10" />
|
<PackageReference Include="Microsoft.Extensions.Logging.Debug" Version="3.1.10" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="3.1.10" />
|
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="3.1.10" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
<PackageReference Include="RaidMax.IW4MAdmin.Data" Version="1.0.0" />
|
<PackageReference Include="RaidMax.IW4MAdmin.Data" Version="1.0.1" />
|
||||||
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
|
<PackageReference Include="Serilog.AspNetCore" Version="3.4.0" />
|
||||||
<PackageReference Include="SimpleCrypto.NetCore" Version="1.0.0" />
|
<PackageReference Include="SimpleCrypto.NetCore" Version="1.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
@ -322,6 +322,8 @@ namespace SharedLibraryCore
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static long ConvertGuidToLong(this string str, NumberStyles numberStyle, long? fallback = null)
|
public static long ConvertGuidToLong(this string str, NumberStyles numberStyle, long? fallback = null)
|
||||||
{
|
{
|
||||||
|
// added for source games that provide the steam ID
|
||||||
|
str = str.Replace("STEAM_1", "").Replace(":", "");
|
||||||
str = str.Substring(0, Math.Min(str.Length, 19));
|
str = str.Substring(0, Math.Min(str.Length, 19));
|
||||||
var parsableAsNumber = Regex.Match(str, @"([A-F]|[a-f]|[0-9])+").Value;
|
var parsableAsNumber = Regex.Match(str, @"([A-F]|[a-f]|[0-9])+").Value;
|
||||||
|
|
||||||
@ -365,12 +367,13 @@ namespace SharedLibraryCore
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// determines if the guid provided appears to be a bot guid
|
/// determines if the guid provided appears to be a bot guid
|
||||||
|
/// "1277538174" - (Pluto?)WaW (T4)
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="guid">value of the guid</param>
|
/// <param name="guid">value of the guid</param>
|
||||||
/// <returns>true if is bot guid, otherwise false</returns>
|
/// <returns>true if is bot guid, otherwise false</returns>
|
||||||
public static bool IsBotGuid(this string guid)
|
public static bool IsBotGuid(this string guid)
|
||||||
{
|
{
|
||||||
return guid.Contains("bot") || guid == "0";
|
return guid.Contains("bot") || guid == "0" || guid == "1277538174";
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -731,7 +734,7 @@ namespace SharedLibraryCore
|
|||||||
return await server.RconParser.ExecuteCommandAsync(server.RemoteConnection, commandName);
|
return await server.RconParser.ExecuteCommandAsync(server.RemoteConnection, commandName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Task<(List<EFClient>, string, string)> GetStatusAsync(this Server server)
|
public static Task<IStatusResponse> GetStatusAsync(this Server server)
|
||||||
{
|
{
|
||||||
return server.RconParser.GetStatusAsync(server.RemoteConnection);
|
return server.RconParser.GetStatusAsync(server.RemoteConnection);
|
||||||
}
|
}
|
||||||
|
@ -77,7 +77,8 @@ namespace WebfrontCore.Controllers.API
|
|||||||
Owner = foundServer,
|
Owner = foundServer,
|
||||||
Origin = Client,
|
Origin = Client,
|
||||||
Data = commandRequest.Command,
|
Data = commandRequest.Command,
|
||||||
Extra = commandRequest.Command
|
Extra = commandRequest.Command,
|
||||||
|
IsRemote = true
|
||||||
};
|
};
|
||||||
|
|
||||||
Manager.AddEvent(commandEvent);
|
Manager.AddEvent(commandEvent);
|
||||||
|
@ -94,7 +94,7 @@ namespace WebfrontCore.Controllers
|
|||||||
_type.Assembly != excludedAssembly && typeof(IPlugin).IsAssignableFrom(_type));
|
_type.Assembly != excludedAssembly && typeof(IPlugin).IsAssignableFrom(_type));
|
||||||
return pluginType == null ? _translationLookup["WEBFRONT_HELP_COMMAND_NATIVE"] :
|
return pluginType == null ? _translationLookup["WEBFRONT_HELP_COMMAND_NATIVE"] :
|
||||||
pluginType.Name == "ScriptPlugin" ? _translationLookup["WEBFRONT_HELP_SCRIPT_PLUGIN"] :
|
pluginType.Name == "ScriptPlugin" ? _translationLookup["WEBFRONT_HELP_SCRIPT_PLUGIN"] :
|
||||||
Manager.Plugins.First(_plugin => _plugin.GetType() == pluginType)
|
Manager.Plugins.First(_plugin => _plugin.GetType().FullName == pluginType.FullName)
|
||||||
.Name; // for now we're just returning the name of the plugin, maybe later we'll include more info
|
.Name; // for now we're just returning the name of the plugin, maybe later we'll include more info
|
||||||
})
|
})
|
||||||
.Select(_grp => (_grp.Key, _grp.AsEnumerable()));
|
.Select(_grp => (_grp.Key, _grp.AsEnumerable()));
|
||||||
|
@ -20,7 +20,7 @@ else
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody id="message_table_body" class="border-bottom bg-dark">
|
<tbody id="message_table_body" class="border-bottom bg-dark">
|
||||||
<partial name="Message/_Item" model="@Model.Results" />
|
<partial name="~/Views/Client/Message/_Item.cshtml" model="@Model.Results" />
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
@using SharedLibraryCore.Interfaces
|
@using SharedLibraryCore.Interfaces
|
||||||
@using Data.Models
|
@using Data.Models
|
||||||
|
@using Data.Models.Client
|
||||||
@model SharedLibraryCore.Dtos.PlayerInfo
|
@model SharedLibraryCore.Dtos.PlayerInfo
|
||||||
@{
|
@{
|
||||||
string match = System.Text.RegularExpressions.Regex.Match(Model.Name.ToUpper(), "[A-Z]").Value;
|
var match = System.Text.RegularExpressions.Regex.Match(Model.Name.ToUpper(), "[A-Z]").Value;
|
||||||
string shortCode = match == string.Empty ? "?" : match;
|
var shortCode = match == string.Empty ? "?" : match;
|
||||||
var loc = SharedLibraryCore.Utilities.CurrentLocalization.LocalizationIndex;
|
var gravatarUrl = Model.Meta.FirstOrDefault(m => m.Key == "GravatarEmail")?.Value;
|
||||||
string gravatarUrl = Model.Meta.FirstOrDefault(m => m.Key == "GravatarEmail")?.Value;
|
var isFlagged = Model.LevelInt == (int) EFClient.Permission.Flagged;
|
||||||
bool isFlagged = Model.LevelInt == (int) SharedLibraryCore.Database.Models.EFClient.Permission.Flagged;
|
var isPermBanned = Model.LevelInt == (int) EFClient.Permission.Banned;
|
||||||
bool isPermBanned = Model.LevelInt == (int) SharedLibraryCore.Database.Models.EFClient.Permission.Banned;
|
var isTempBanned = Model.ActivePenalty?.Type == EFPenalty.PenaltyType.TempBan;
|
||||||
bool isTempBanned = Model.ActivePenalty?.Type == EFPenalty.PenaltyType.TempBan;
|
var translationKey = $"WEBFRONT_PROFILE_{Model.ActivePenalty?.Type.ToString().ToUpper()}_INFO";
|
||||||
string translationKey = $"WEBFRONT_PROFILE_{Model.ActivePenalty?.Type.ToString().ToUpper()}_INFO";
|
|
||||||
var ignoredMetaTypes = new[] {MetaType.Information, MetaType.Other, MetaType.QuickMessage};
|
var ignoredMetaTypes = new[] {MetaType.Information, MetaType.Other, MetaType.QuickMessage};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -38,18 +38,22 @@
|
|||||||
<div id="profile_aliases" class="text-muted pt-0 pt-lg-2 pb-2">
|
<div id="profile_aliases" class="text-muted pt-0 pt-lg-2 pb-2">
|
||||||
@foreach (var linked in Model.LinkedAccounts)
|
@foreach (var linked in Model.LinkedAccounts)
|
||||||
{
|
{
|
||||||
@Html.ActionLink(linked.Value.ToString("X"), "ProfileAsync", "Client", new {id = linked.Key}, new {@class = "link-inverse"})<br/>
|
<div>
|
||||||
|
@Html.ActionLink(linked.Value.ToString("X"), "ProfileAsync", "Client", new {id = linked.Key}, new {@class = "link-inverse"})
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
@foreach (var alias in Model.Aliases)
|
@foreach (var alias in Model.Aliases)
|
||||||
{
|
{
|
||||||
<color-code value="@alias" allow="@ViewBag.EnableColorCodes"></color-code>
|
<div>
|
||||||
<br/>
|
<color-code value="@alias" allow="@ViewBag.EnableColorCodes"></color-code>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
@foreach (string ip in Model.IPs)
|
@foreach (var ip in Model.IPs)
|
||||||
{
|
{
|
||||||
<a class="ip-locate-link" href="#" data-ip="@ip">@ip</a>
|
<div>
|
||||||
<br/>
|
<a class="ip-locate-link" href="#" data-ip="@ip">@ip</a>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
@ -61,7 +65,7 @@
|
|||||||
switch (result.MatchValue)
|
switch (result.MatchValue)
|
||||||
{
|
{
|
||||||
case "reason":
|
case "reason":
|
||||||
<span class="text-white font-weight-lighter">@(ViewBag.Authorized ? !string.IsNullOrEmpty(Model.ActivePenalty.AutomatedOffense) && Model.ActivePenalty.Type != EFPenalty.PenaltyType.Warning ? Utilities.FormatExt(ViewBag.Localization["WEBFRONT_PROFILE_ANTICHEAT_DETECTION"], Model.ActivePenalty.AutomatedOffense) : Model.ActivePenalty.Offense : Model.ActivePenalty.Offense)</span>
|
<span class="text-white font-weight-lighter">@(ViewBag.Authorized ? !string.IsNullOrEmpty(Model.ActivePenalty.AutomatedOffense) && Model.ActivePenalty.Type != EFPenalty.PenaltyType.Warning ? Utilities.FormatExt(ViewBag.Localization["WEBFRONT_PROFILE_ANTICHEAT_DETECTION"], Model.ActivePenalty.AutomatedOffense) : Model.ActivePenalty.Offense.StripColors() : Model.ActivePenalty.Offense.StripColors())</span>
|
||||||
break;
|
break;
|
||||||
case "time":
|
case "time":
|
||||||
<span class="text-white font-weight-lighter">
|
<span class="text-white font-weight-lighter">
|
||||||
|
@ -32,10 +32,10 @@
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
var rebuiltName = stat.RebuildWeaponName();
|
var rebuiltName = stat.RebuildWeaponName();
|
||||||
var name = config.GetStringForGame(rebuiltName);
|
var name = config.GetStringForGame(rebuiltName, stat.Weapon?.Game);
|
||||||
return !rebuiltName.Equals(name, StringComparison.InvariantCultureIgnoreCase)
|
return !rebuiltName.Equals(name, StringComparison.InvariantCultureIgnoreCase)
|
||||||
? name
|
? name
|
||||||
: config.GetStringForGame(stat.Weapon.Name);
|
: config.GetStringForGame(stat.Weapon.Name, stat.Weapon.Game);
|
||||||
}
|
}
|
||||||
|
|
||||||
string GetWeaponAttachmentName(EFWeaponAttachmentCombo attachment)
|
string GetWeaponAttachmentName(EFWeaponAttachmentCombo attachment)
|
||||||
@ -47,16 +47,16 @@
|
|||||||
|
|
||||||
var attachmentText = string.Join('+', new[]
|
var attachmentText = string.Join('+', new[]
|
||||||
{
|
{
|
||||||
config.GetStringForGame(attachment.Attachment1.Name),
|
config.GetStringForGame(attachment.Attachment1.Name, attachment.Attachment1.Game),
|
||||||
config.GetStringForGame(attachment.Attachment2?.Name),
|
config.GetStringForGame(attachment.Attachment2?.Name, attachment.Attachment2?.Game),
|
||||||
config.GetStringForGame(attachment.Attachment3?.Name)
|
config.GetStringForGame(attachment.Attachment3?.Name, attachment.Attachment3?.Game)
|
||||||
}.Where(attach => !string.IsNullOrWhiteSpace(attach)));
|
}.Where(attach => !string.IsNullOrWhiteSpace(attach)));
|
||||||
|
|
||||||
return attachmentText;
|
return attachmentText;
|
||||||
}
|
}
|
||||||
|
|
||||||
var weapons = Model.ByWeapon
|
var weapons = Model.ByWeapon
|
||||||
.Where(hit => hit.DamageInflicted > 0)
|
.Where(hit => hit.DamageInflicted > 0 || (hit.DamageInflicted == 0 && hit.HitCount > 0))
|
||||||
.GroupBy(hit => new {hit.WeaponId})
|
.GroupBy(hit => new {hit.WeaponId})
|
||||||
.Select(group =>
|
.Select(group =>
|
||||||
{
|
{
|
||||||
@ -404,7 +404,7 @@
|
|||||||
@foreach (var hitLocation in filteredHitLocations.Take(8))
|
@foreach (var hitLocation in filteredHitLocations.Take(8))
|
||||||
{
|
{
|
||||||
<tr>
|
<tr>
|
||||||
<td class="@textClass text-force-break">@config.GetStringForGame(hitLocation.HitLocation.Name)</td>
|
<td class="@textClass text-force-break">@config.GetStringForGame(hitLocation.HitLocation.Name, hitLocation.HitLocation.Game)</td>
|
||||||
<td class="text-success text-force-break">@hitLocation.HitCount</td>
|
<td class="text-success text-force-break">@hitLocation.HitCount</td>
|
||||||
<td class="text-muted text-force-break">@Math.Round((hitLocation.HitCount / (float) totalHits) * 100.0).ToString(Utilities.CurrentLocalization.Culture)%</td>
|
<td class="text-muted text-force-break">@Math.Round((hitLocation.HitCount / (float) totalHits) * 100.0).ToString(Utilities.CurrentLocalization.Culture)%</td>
|
||||||
<td class="text-muted text-force-break">@hitLocation.DamageInflicted.ToNumericalString()</td>
|
<td class="text-muted text-force-break">@hitLocation.DamageInflicted.ToNumericalString()</td>
|
||||||
@ -414,7 +414,7 @@
|
|||||||
@foreach (var hitLocation in filteredHitLocations.Skip(8))
|
@foreach (var hitLocation in filteredHitLocations.Skip(8))
|
||||||
{
|
{
|
||||||
<tr class="bg-dark hidden-row" style="display:none;">
|
<tr class="bg-dark hidden-row" style="display:none;">
|
||||||
<td class="@textClass text-force-break">@config.GetStringForGame(hitLocation.HitLocation.Name)</td>
|
<td class="@textClass text-force-break">@config.GetStringForGame(hitLocation.HitLocation.Name, hitLocation.HitLocation.Game)</td>
|
||||||
<td class="text-success text-force-break">@hitLocation.HitCount</td>
|
<td class="text-success text-force-break">@hitLocation.HitCount</td>
|
||||||
<td class="text-muted text-force-break">@Math.Round((hitLocation.HitCount / (float) totalHits) * 100.0).ToString(Utilities.CurrentLocalization.Culture)%</td>
|
<td class="text-muted text-force-break">@Math.Round((hitLocation.HitCount / (float) totalHits) * 100.0).ToString(Utilities.CurrentLocalization.Culture)%</td>
|
||||||
<td class="text-muted text-force-break">@hitLocation.DamageInflicted.ToNumericalString()</td>
|
<td class="text-muted text-force-break">@hitLocation.DamageInflicted.ToNumericalString()</td>
|
||||||
|
Reference in New Issue
Block a user