lots more live radar updates
107
Plugins/LiveRadar/Configuration/LiveRadarConfiguration.cs
Normal file
@ -0,0 +1,107 @@
|
||||
using SharedLibraryCore.Configuration;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace LiveRadar.Configuration
|
||||
{
|
||||
class LiveRadarConfiguration : IBaseConfiguration
|
||||
{
|
||||
public List<MapInfo> Maps { get; set; }
|
||||
|
||||
public IBaseConfiguration Generate()
|
||||
{
|
||||
Maps = new List<MapInfo>()
|
||||
{
|
||||
new MapInfo()
|
||||
{
|
||||
Name = "mp_afghan",
|
||||
MaxLeft = 4600, // ymax
|
||||
MaxRight = -1100, // ymin
|
||||
MaxBottom = -1400, // xmin
|
||||
MaxTop = 4600, // xmax
|
||||
Left = 52, // pxmin
|
||||
Right = 898, // pxmax
|
||||
Bottom = 930, // yxmax
|
||||
Top = 44 // pymin
|
||||
},
|
||||
new MapInfo()
|
||||
{
|
||||
Name = "mp_rust",
|
||||
Top = 212,
|
||||
Bottom = 812,
|
||||
Left = 314,
|
||||
Right = 856,
|
||||
MaxRight = -225,
|
||||
MaxLeft = 1809,
|
||||
MaxTop = 1773,
|
||||
MaxBottom = -469
|
||||
},
|
||||
|
||||
new MapInfo()
|
||||
{
|
||||
Name = "mp_subbase",
|
||||
MaxLeft = 1841, // ymax
|
||||
MaxRight = -3817, // ymin
|
||||
MaxBottom = -1585, // xmin
|
||||
MaxTop = 2593, // xmax
|
||||
Left = 18, // pxmin
|
||||
Right = 968, // pxmax
|
||||
Bottom = 864, // pymax
|
||||
Top = 160, // pymin
|
||||
CenterX = 0,
|
||||
CenterY = 0,
|
||||
Rotation = 0
|
||||
},
|
||||
|
||||
new MapInfo()
|
||||
{
|
||||
Name = "mp_estate",
|
||||
Top = 52,
|
||||
Bottom = 999,
|
||||
Left= 173,
|
||||
Right = 942,
|
||||
MaxTop = 2103,
|
||||
MaxBottom = -5077,
|
||||
MaxLeft = 4437,
|
||||
MaxRight = -1240,
|
||||
Rotation = 143,
|
||||
CenterX = -1440,
|
||||
CenterY = 1920,
|
||||
Scaler = 0.85f
|
||||
},
|
||||
|
||||
new MapInfo()
|
||||
{
|
||||
Name = "mp_highrise",
|
||||
MaxBottom = -3909,
|
||||
MaxTop = 1649,
|
||||
MaxRight = 5111,
|
||||
MaxLeft = 8906,
|
||||
Left = 108,
|
||||
Right = 722,
|
||||
Top = 66,
|
||||
Bottom = 974,
|
||||
},
|
||||
|
||||
new MapInfo()
|
||||
{
|
||||
Name = "mp_quarry",
|
||||
MaxBottom = -5905,
|
||||
MaxTop = -1423,
|
||||
MaxRight = -2095,
|
||||
MaxLeft = 3217,
|
||||
Left = 126,
|
||||
Right = 968,
|
||||
Top = 114,
|
||||
Bottom = 824
|
||||
}
|
||||
};
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public string Name() => "LiveRadar";
|
||||
}
|
||||
}
|
@ -18,6 +18,10 @@ namespace LiveRadar
|
||||
public int MaxBottom { get; set; }
|
||||
public int MaxLeft { get; set; }
|
||||
public int MaxRight { get; set; }
|
||||
public float Rotation { get; set; }
|
||||
public float CenterX { get; set; }
|
||||
public float CenterY { get; set; }
|
||||
public float Scaler { get; set; } = 1.0f;
|
||||
|
||||
public int Width => MaxLeft - MaxRight;
|
||||
public int Height => MaxTop - MaxBottom;
|
||||
|
@ -1,4 +1,6 @@
|
||||
using SharedLibraryCore;
|
||||
using LiveRadar.Configuration;
|
||||
using SharedLibraryCore;
|
||||
using SharedLibraryCore.Configuration;
|
||||
using SharedLibraryCore.Interfaces;
|
||||
using System;
|
||||
using System.Linq;
|
||||
@ -14,6 +16,8 @@ namespace LiveRadar
|
||||
|
||||
public string Author => "RaidMax";
|
||||
|
||||
internal static BaseConfigurationHandler<LiveRadarConfiguration> Config;
|
||||
|
||||
public Task OnEventAsync(GameEvent E, Server S)
|
||||
{
|
||||
if (E.Type == GameEvent.EventType.Unknown)
|
||||
@ -21,18 +25,28 @@ namespace LiveRadar
|
||||
if (E.Data?.StartsWith("LiveRadar") ?? false)
|
||||
{
|
||||
var radarUpdate = RadarEvent.Parse(E.Data);
|
||||
var client = S.GetClientsAsList().First(_client => _client.NetworkId == radarUpdate.Guid);
|
||||
radarUpdate.Name = client.Name;
|
||||
client.SetAdditionalProperty("LiveRadar", radarUpdate);
|
||||
var client = S.Manager.GetActiveClients().FirstOrDefault(_client => _client.NetworkId == radarUpdate.Guid);
|
||||
|
||||
if (client != null)
|
||||
{
|
||||
radarUpdate.Name = client.Name;
|
||||
client.SetAdditionalProperty("LiveRadar", radarUpdate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task OnLoadAsync(IManager manager)
|
||||
public async Task OnLoadAsync(IManager manager)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
// load custom configuration
|
||||
Config = new BaseConfigurationHandler<LiveRadarConfiguration>("LiveRadarConfiguration");
|
||||
if (Config.Configuration() == null)
|
||||
{
|
||||
Config.Set((LiveRadarConfiguration)new LiveRadarConfiguration().Generate());
|
||||
await Config.Save();
|
||||
}
|
||||
}
|
||||
|
||||
public Task OnTickAsync(Server S)
|
||||
|
@ -17,11 +17,11 @@ namespace LiveRadar
|
||||
public int Kills { get; set; }
|
||||
public int Deaths { get; set; }
|
||||
public int Score { get; set; }
|
||||
public int PlayTime { get; set; }
|
||||
public string Weapon { get; set; }
|
||||
public int Health { get; set; }
|
||||
public bool IsAlive { get; set; }
|
||||
public Vector3 RadianAngles => new Vector3(ViewAngles.X.ToRadians(), ViewAngles.Y.ToRadians(), ViewAngles.Z.ToRadians());
|
||||
public RadarEvent Previous { get; set; }
|
||||
public int Id => GetHashCode();
|
||||
|
||||
public override bool Equals(object obj)
|
||||
@ -41,7 +41,7 @@ namespace LiveRadar
|
||||
|
||||
public static RadarEvent Parse(string input)
|
||||
{
|
||||
var items = input.Split(';').ToList();
|
||||
var items = input.Split(';').Skip(1).ToList();
|
||||
|
||||
var parsedEvent = new RadarEvent()
|
||||
{
|
||||
@ -54,7 +54,8 @@ namespace LiveRadar
|
||||
Score = int.Parse(items[6]),
|
||||
Weapon = items[7],
|
||||
Health = int.Parse(items[8]),
|
||||
IsAlive = items[9] == "1"
|
||||
IsAlive = items[9] == "1",
|
||||
PlayTime = Convert.ToInt32(items[10])
|
||||
};
|
||||
|
||||
return parsedEvent;
|
||||
|
@ -10,34 +10,34 @@ namespace LiveRadar.Web.Controllers
|
||||
{
|
||||
public class RadarController : BaseController
|
||||
{
|
||||
private static readonly JsonSerializerSettings _serializerSettings = new JsonSerializerSettings()
|
||||
{
|
||||
ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
|
||||
ContractResolver = new Newtonsoft.Json.Serialization.CamelCasePropertyNamesContractResolver()
|
||||
};
|
||||
|
||||
[HttpGet]
|
||||
public IActionResult Index()
|
||||
{
|
||||
ViewBag.IsFluid = true;
|
||||
return View();
|
||||
}
|
||||
|
||||
public IActionResult Map(long? serverId = null)
|
||||
{
|
||||
var map = new MapInfo()
|
||||
{
|
||||
Name = "mp_rust",
|
||||
Top = 248,
|
||||
Bottom = 212,
|
||||
Left = 314,
|
||||
Right = 167,
|
||||
MaxRight = -225,
|
||||
MaxLeft = 1809,
|
||||
MaxTop = 1641,
|
||||
MaxBottom = -469
|
||||
};
|
||||
var server = Manager.GetServers().FirstOrDefault();
|
||||
|
||||
var map = Plugin.Config.Configuration().Maps.FirstOrDefault(_map => _map.Name == server.CurrentMap.Name);
|
||||
|
||||
return Json(map);
|
||||
}
|
||||
|
||||
[HttpGet]
|
||||
[ResponseCache(Duration = 0, Location = ResponseCacheLocation.None, NoStore = true)]
|
||||
public IActionResult Data(long? serverId = null)
|
||||
{
|
||||
var server = serverId == null ? Manager.GetServers()[0] : Manager.GetServers().First(_server => _server.GetHashCode() == serverId);
|
||||
var radarInfo = server.GetClientsAsList().Select(_client => _client.GetAdditionalProperty<RadarEvent>("LiveRadar"));
|
||||
var radarInfo = server.GetClientsAsList().Select(_client => _client.GetAdditionalProperty<RadarEvent>("LiveRadar")).ToList();
|
||||
return Json(radarInfo);
|
||||
}
|
||||
|
||||
@ -50,18 +50,10 @@ namespace LiveRadar.Web.Controllers
|
||||
if (client != null)
|
||||
{
|
||||
radarUpdate.Name = client.Name;
|
||||
var previous = client.GetAdditionalProperty<RadarEvent>("LiveRadar");
|
||||
// this prevents us from creating a never ending linked list
|
||||
if (previous != null)
|
||||
{
|
||||
previous.Previous = null;
|
||||
}
|
||||
|
||||
radarUpdate.Previous = previous;
|
||||
client.SetAdditionalProperty("LiveRadar", radarUpdate);
|
||||
}
|
||||
|
||||
return Ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,23 +1,108 @@
|
||||
@model IEnumerable<long>
|
||||
|
||||
<style>
|
||||
.progress {
|
||||
border-radius: 0 !important;
|
||||
}
|
||||
|
||||
.player-stat-icon {
|
||||
height: 1.5rem;
|
||||
width: 1.5rem;
|
||||
background-size: 1.5rem 1.5rem;
|
||||
}
|
||||
</style>
|
||||
<div class="row p-0 ml-auto mr-auto col-12 col-xl-10">
|
||||
<div class="p-0 pl-lg-3 pr-lg-3 m-0 col-lg-3 col-12 text-lg-right text-center player-data-left" style="opacity: 0">
|
||||
</div>
|
||||
<div class="pl-0 pr-0 pl-lg-3 pr-lg-3 col-lg-6 col-12 pb-4">
|
||||
<div id="map_name" class="h4 text-center pb-2 pt-2 mb-0 bg-primary">—</div>
|
||||
<div id="map_list" style="background-size:cover; padding-bottom: 100% !important;">
|
||||
<canvas id="map_canvas" style="position:absolute;"></canvas>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<canvas id="map_canvas" style="position:absolute; z-index:1"></canvas>
|
||||
<div id="map_list" style="position:absolute">
|
||||
<div class="p-0 pl-lg-3 pr-lg-3 m-0 col-lg-3 col-12 text-lg-left text-center player-data-right" style="opacity: 0">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- images used by canvas -->
|
||||
<img class="hide" id="hud_death" src="~/images/hud_weapons/hud_death.png" />
|
||||
|
||||
@section scripts {
|
||||
<script>
|
||||
const textOffset = 15;
|
||||
let previousRadarData = undefined;
|
||||
let newRadarData = undefined;
|
||||
|
||||
/************************
|
||||
* IW4 *
|
||||
* **********************/
|
||||
const weapons = {};
|
||||
weapons["ak47"] = "ak47";
|
||||
weapons["ak47classic"] = "icon_ak47_classic";
|
||||
weapons["ak47u"] = "akd74u";
|
||||
weapons["m16"] = "m16a4";
|
||||
weapons["m4"] = "m4carbine";
|
||||
weapons["fn2000"] = "fn2000";
|
||||
weapons["masada"] = "masada";
|
||||
weapons["famas"] = "famas";
|
||||
weapons["fal"] = "fnfal";
|
||||
weapons["scar"] = "scar_h";
|
||||
weapons["tavor"] = "tavor";
|
||||
|
||||
weapons["mp5k"] = "mp5k";
|
||||
weapons["uzi"] = "mini_uzi";
|
||||
weapons["p90"] = "p90";
|
||||
weapons["kriss"] = "kriss";
|
||||
weapons["ump45"] = "ump45";
|
||||
|
||||
weapons["rpd"] = "rpd";
|
||||
weapons["sa80"] = "sa80_lmg";
|
||||
weapons["mg4"] = "mg4";
|
||||
weapons["m240"] = "m240";
|
||||
weapons["aug"] = "steyr";
|
||||
|
||||
weapons["barrett"] = "barrett50cal";
|
||||
weapons["wa2000"] = "wa2000";
|
||||
weapons["m21"] = "m14ebr";
|
||||
weapons["cheytac"] = "cheytac";
|
||||
|
||||
weapons["beretta"] = "m9beretta";
|
||||
weapons["usp"] = "usp_45";
|
||||
weapons["deserteagle"] = "desert_eagle";
|
||||
weapons["deserteaglegold"] = "desert_eagle_gold";
|
||||
weapons["desert"]
|
||||
weapons["coltanaconda"] = "colt_anaconda";
|
||||
|
||||
weapons["tmp"] = "mp9";
|
||||
weapons["glock"] = "glock";
|
||||
weapons["beretta393"] = "beretta393";
|
||||
weapons["pp2000"] = "pp2000";
|
||||
|
||||
weapons["ranger"] = "sawed_off";
|
||||
weapons["model1887"] = "model1887";
|
||||
weapons["striker"] = "striker";
|
||||
weapons["aa12"] = "aa12";
|
||||
weapons["m1014"] = "benelli_m4";
|
||||
weapons["spas12"] = "spas12";
|
||||
|
||||
weapons["m79"] = "m79";
|
||||
weapons["rpg"] = "rpg";
|
||||
weapons["at4"] = "at4";
|
||||
weapons["stinger"] = "stinger";
|
||||
weapons["javelin"] = "javelin";
|
||||
|
||||
weapons["m40a3"] = "m40a3";
|
||||
weapons["none"] = "neutral";
|
||||
weapons["riotshield"] = "riot_shield";
|
||||
weapons["peacekeeper"] = "peacekeeper";
|
||||
|
||||
function drawCircle(context, x, y, color) {
|
||||
context.beginPath();
|
||||
context.arc(x, y, 6, 0, 2 * Math.PI, false);
|
||||
context.arc(x, y, 6 * stateInfo.imageScaler, 0, 2 * Math.PI, false);
|
||||
context.fillStyle = color;
|
||||
context.fill();
|
||||
context.lineWidth = 3;
|
||||
context.lineWidth = 0.5;
|
||||
context.strokeStyle = 'rgba(255, 255, 255, 0.5)';
|
||||
context.closePath();
|
||||
context.stroke();
|
||||
@ -42,30 +127,45 @@
|
||||
context.fill();
|
||||
}
|
||||
|
||||
function drawText(context, x, y, text, size, fillColor, strokeColor) {
|
||||
function drawText(context, x, y, text, size, fillColor, strokeColor, alignment = 'left') {
|
||||
context.beginPath();
|
||||
context.font = `bold ${size}px open sans`;
|
||||
context.font = `bold ${size * stateInfo.imageScaler}px verdana`;
|
||||
context.fillStyle = fillColor;
|
||||
context.strokeStyle = strokeColor;
|
||||
context.lineWidth = '0.5';
|
||||
context.textAlign = 'center';
|
||||
context.lineWidth = 1 * stateInfo.imageScaler;
|
||||
context.textAlign = alignment;
|
||||
context.fillText(text, x, y);
|
||||
context.strokeText(text, x, y);
|
||||
context.closePath();
|
||||
}
|
||||
|
||||
function drawImage(context, imgSelector, x, y, alpha = 1) {
|
||||
context.save();
|
||||
context.globalAlpha = alpha;
|
||||
context.drawImage(document.getElementById(imgSelector), x - (15 * stateInfo.imageScaler), y - (15 * stateInfo.imageScaler), 32 * stateInfo.imageScaler, 32 * stateInfo.imageScaler);
|
||||
context.globalAlpha = 1;
|
||||
context.restore();
|
||||
}
|
||||
|
||||
function checkCanvasSize(canvas, context, minimap, map) {
|
||||
var height = minimap.height() - map.top - map.bottom;
|
||||
var width = minimap.width() - map.left - map.right;
|
||||
|
||||
if (context.canvas.height != height || context.canvas.width != width) {
|
||||
context.canvas.height = height;
|
||||
context.canvas.width = width;
|
||||
let width = Math.round(minimap.width());
|
||||
if (Math.round(context.canvas.width) != width) {
|
||||
|
||||
canvas.width(width);
|
||||
canvas.height(width);
|
||||
|
||||
context.canvas.height = width;
|
||||
context.canvas.width = context.canvas.height;
|
||||
|
||||
canvas.css('position', 'absolute');
|
||||
canvas.css('left', map.left + minimap.offset().left);
|
||||
canvas.css('top', map.top + minimap.offset().top);
|
||||
}
|
||||
|
||||
stateInfo.imageScaler = (stateInfo.canvas.width() / 1024)
|
||||
stateInfo.mapScaler = ((stateInfo.mapInfo.right - stateInfo.mapInfo.left) / stateInfo.mapInfo.width) * stateInfo.imageScaler;
|
||||
stateInfo.mapScalerY =((stateInfo.mapInfo.bottom - stateInfo.mapInfo.top) / stateInfo.mapInfo.height) * stateInfo.imageScaler;
|
||||
|
||||
stateInfo.forwardDistance = 500.0 * ((stateInfo.mapInfo.right - stateInfo.mapInfo.left) / stateInfo.mapInfo.width) * stateInfo.imageScaler;
|
||||
stateInfo.fovWidth = 32.5 * ((stateInfo.mapInfo.right - stateInfo.mapInfo.left) / stateInfo.mapInfo.width);
|
||||
}
|
||||
|
||||
function calculateViewPosition(x, y, distance) {
|
||||
@ -113,15 +213,77 @@
|
||||
return { x: newX, y: newY };
|
||||
}
|
||||
|
||||
function toRadians(deg) {
|
||||
return deg * Math.PI / 180.0;
|
||||
}
|
||||
|
||||
function rotate(cx, cy, x, y, angle) {
|
||||
var radians = (Math.PI / 180) * angle,
|
||||
cos = Math.cos(radians),
|
||||
sin = Math.sin(radians),
|
||||
nx = (cos * (x - cx)) + (sin * (y - cy)) + cx,
|
||||
ny = (cos * (y - cy)) - (sin * (x - cx)) + cy;
|
||||
return {
|
||||
x: nx,
|
||||
y: ny
|
||||
};
|
||||
}
|
||||
|
||||
function weaponImageForWeapon(weapon) {
|
||||
let name = weapon.split('_')[0];
|
||||
if (weapons[name] == undefined) {
|
||||
console.log(name);
|
||||
name = "none";
|
||||
}
|
||||
|
||||
return `../images/hud_weapons/hud_${weapons[name]}.png`;
|
||||
}
|
||||
|
||||
function updatePlayerData() {
|
||||
$('.player-data-left').html('');
|
||||
$('.player-data-right').html('');
|
||||
|
||||
$.each(newRadarData, function (index, player) {
|
||||
if (player == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
let column = index % 2 == 0 ? $('.player-data-left') : $('.player-data-right');
|
||||
column.append(`<div class="progress" style="height: 1.5rem; background-color: transparent;">
|
||||
<div style="position: absolute; font-size: 1rem; left: 1.5rem;">${player.name}</div>
|
||||
<div class="progress-bar bg-success" role="progressbar" style="min-width: 0px; width: ${player.health}%" aria-valuenow="${player.health}" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
<div class="progress-bar bg-danger" role="progressbar" style="min-width: 0px; border-right: 0px; width: ${100 - player.health}%" aria-valuenow="${100 - player.health}" aria-valuemin="0" aria-valuemax="100"></div>
|
||||
</div>
|
||||
<div class="d-flex flex-row flex-wrap p-2 mb-4 bg-dark border-bottom">
|
||||
<div style="width: 3rem; height: 1.5rem; background-image:url(${weaponImageForWeapon(player.weapon)}); background-size: 3rem 1.5rem;" class="mr-auto text-left">
|
||||
</div>
|
||||
<div class="player-stat-icon" style="background-image:url('/images/radar/kills.png')"></div>
|
||||
<div class="pr-2">${player.kills}</div>
|
||||
<div class="player-stat-icon" style="background-image:url('/images/hud_weapons/hud_death.png')"></div>
|
||||
<div class="pr-3">${player.deaths}</div>
|
||||
<span class="align-self-center oi oi-target pr-1"></span>
|
||||
<div class="pr-3 ">${player.deaths == 0 ? player.kills.toFixed(2) : (player.kills / player.deaths).toFixed(2)}</div>
|
||||
<span class="align-self-center oi oi-graph pr-1"></span>
|
||||
<div>${Math.round(player.score / (player.playTime / 60))}</div>
|
||||
</div>`);
|
||||
//<img style="height: 1.5rem;" src="${weaponImageForWeapon(player.weapon)}"/>
|
||||
});
|
||||
|
||||
$('.player-data-left').delay(1000).animate({opacity: 1}, 500);
|
||||
$('.player-data-right').delay(1000).animate({opacity: 1}, 500);
|
||||
}
|
||||
|
||||
const stateInfo = {
|
||||
canvas: $('#map_canvas'),
|
||||
ctx: $('#map_canvas')[0].getContext('2d'),
|
||||
updateFrequency: 500,
|
||||
updateFrequency: 750,
|
||||
updateFrameTimeDeviation: 0,
|
||||
forwardDistance: undefined,
|
||||
fovWidth: undefined,
|
||||
mapInfo: undefined,
|
||||
mapScaler: undefined
|
||||
mapScaler: undefined,
|
||||
deathIcons: {},
|
||||
deathIconTime: 4000
|
||||
};
|
||||
|
||||
function updateRadarData() {
|
||||
@ -129,33 +291,58 @@
|
||||
newRadarData = _radarItem;
|
||||
});
|
||||
|
||||
|
||||
$.getJSON('@Url.Action("Map", "Radar", null)', function (_map) {
|
||||
stateInfo.mapInfo = _map
|
||||
});
|
||||
|
||||
$.each(newRadarData, function (index, value) {
|
||||
if (previousRadarData != undefined && index < previousRadarData.length) {
|
||||
|
||||
let previous = previousRadarData[index];
|
||||
let previous = previousRadarData[index];
|
||||
|
||||
// this happens when the player has first joined and we haven't gotten two snapshots yet
|
||||
if (value == null || previous == null) {
|
||||
return;
|
||||
}
|
||||
// this happens when the player has first joined and we haven't gotten two snapshots yet
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// we haven't gotten a new item, it's just the old one again
|
||||
if (previous.id === value.id) {
|
||||
value.animationTime = previous.animationTime;
|
||||
value.previous = value;
|
||||
}
|
||||
if (previous == null) {
|
||||
previous = value;
|
||||
}
|
||||
|
||||
// we don't want to treat a disconnected player snapshot as the previous
|
||||
else if (previous.guid == value.guid) {
|
||||
value.previous = previous;
|
||||
}
|
||||
|
||||
// we haven't gotten a new item, it's just the old one again
|
||||
if (previous.id === value.id) {
|
||||
value.animationTime = previous.animationTime;
|
||||
value.previous = value;
|
||||
}
|
||||
|
||||
// they died between this snapshot and last so we wanna setup the death icon
|
||||
if (!value.isAlive && previous.isAlive) {
|
||||
stateInfo.deathIcons[value.guid] = {
|
||||
animationTime: now,
|
||||
location: value.location
|
||||
};
|
||||
}
|
||||
|
||||
// they respawned between this snapshot and last so we don't want to show wherever the were specating from
|
||||
else if (value.isAlive && !previous.isAlive) {
|
||||
value.previous = value;
|
||||
}
|
||||
}});
|
||||
|
||||
// we switch out the items to
|
||||
previousRadarData = newRadarData;
|
||||
|
||||
checkCanvasSize(stateInfo.canvas, stateInfo.ctx, $('#map_list'), stateInfo.mapInfo)
|
||||
|
||||
if (stateInfo.forwardDistance == undefined) {
|
||||
stateInfo.mapScaler = stateInfo.mapInfo.width / stateInfo.canvas.width();
|
||||
stateInfo.forwardDistance = 500.0 / stateInfo.mapScaler;
|
||||
stateInfo.fovWidth = 32.5 / stateInfo.mapScaler;
|
||||
}
|
||||
$('#map_name').html(stateInfo.mapInfo.name);
|
||||
$('#map_list').css('background-image', `url(../images/radar/minimaps/compass_map_${stateInfo.mapInfo.name}@('@')2x.png)`);
|
||||
checkCanvasSize(stateInfo.canvas, stateInfo.ctx, $('#map_list'), stateInfo.mapInfo);
|
||||
updatePlayerData();
|
||||
window.requestAnimationFrame(updateMap);
|
||||
}
|
||||
|
||||
function updateMap() {
|
||||
@ -165,58 +352,104 @@
|
||||
now = performance.now();
|
||||
|
||||
$.each(previousRadarData, function (index, value) {
|
||||
if (value == null || value.previous == null) {
|
||||
console.log("skipping null snapshot");
|
||||
if (value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// this indicates we got a new snapshot to work with so we set the time based off the previous
|
||||
if (value.previous == null) {
|
||||
value.previous = value;
|
||||
}
|
||||
|
||||
// this indicates we got a new snapshot to work with so we set the time based off the previous
|
||||
// frame deviation to have minimal interpolation skipping
|
||||
if (value.animationTime === undefined) {
|
||||
value.animationTime = now - stateInfo.updateFrameTimeDeviation;
|
||||
}
|
||||
|
||||
if (!value.isAlive) {
|
||||
return;
|
||||
}
|
||||
|
||||
const elapsedFrameTime = now - value.animationTime;
|
||||
const completionPercent = elapsedFrameTime / stateInfo.updateFrequency;
|
||||
|
||||
const startX = (stateInfo.mapInfo.maxLeft - value.previous.location.y) / stateInfo.mapScaler;
|
||||
const startY = (stateInfo.mapInfo.maxTop - value.previous.location.x) / stateInfo.mapScaler;
|
||||
// certain maps like estate have an off center axis of origin, so we need to account for that
|
||||
let rotatedPreviousLocation = rotate(stateInfo.mapInfo.centerX, stateInfo.mapInfo.centerY, value.previous.location.x, value.previous.location.y, stateInfo.mapInfo.rotation);
|
||||
let rotatedCurrentLocation = rotate(stateInfo.mapInfo.centerX, stateInfo.mapInfo.centerY, value.location.x, value.location.y, stateInfo.mapInfo.rotation);
|
||||
|
||||
const endX = (stateInfo.mapInfo.maxLeft - value.location.y) / stateInfo.mapScaler;
|
||||
const endY = (stateInfo.mapInfo.maxTop - value.location.x) / stateInfo.mapScaler;
|
||||
const startX = ((stateInfo.mapInfo.maxLeft - rotatedPreviousLocation.y) * stateInfo.mapScaler) + (stateInfo.mapInfo.left * stateInfo.imageScaler);
|
||||
const startY = ((stateInfo.mapInfo.maxTop - rotatedPreviousLocation.x) * stateInfo.mapScalerY) + (stateInfo.mapInfo.top * stateInfo.imageScaler);
|
||||
|
||||
const endX = ((stateInfo.mapInfo.maxLeft - rotatedCurrentLocation.y) * stateInfo.mapScaler) + (stateInfo.mapInfo.left * stateInfo.imageScaler);
|
||||
const endY = ((stateInfo.mapInfo.maxTop - rotatedCurrentLocation.x) * stateInfo.mapScalerY) + (stateInfo.mapInfo.top * stateInfo.imageScaler);
|
||||
|
||||
let teamColor = value.team == 'allies' ? 'rgba(0, 122, 204, 1)' : 'rgba(255,69,69,.85)';
|
||||
let fovColor = value.team == 'allies' ? 'rgba(0, 122, 204, 0.25)' : 'rgba(255,69,69,.25)';
|
||||
let fovColor = value.team == 'allies' ? 'rgba(0, 122, 204, 0.2)' : 'rgba(255,69,69,.2)';
|
||||
|
||||
// this takes care of moving past the roll-over point of yaw/pitch (ie 360->0)
|
||||
const rollAngleFix = fixRollAngles(value.previous.radianAngles, value.radianAngles);
|
||||
|
||||
const radianLerpX = lerp(value.previous.radianAngles.x, rollAngleFix.x, completionPercent);
|
||||
const radianLerpY = lerp(value.previous.radianAngles.y, rollAngleFix.y, completionPercent);
|
||||
|
||||
// this is some jankiness to get the fov to point the right direction
|
||||
let firstVertex = calculateViewPosition((Math.PI * 2 * 0.75) - radianLerpX - (Math.PI + stateInfo.fovWidth), radianLerpY, stateInfo.forwardDistance);
|
||||
let secondVertex = calculateViewPosition((Math.PI * 2 * 0.75) - radianLerpX + (Math.PI + stateInfo.fovWidth), radianLerpY, stateInfo.forwardDistance);
|
||||
let firstVertex = calculateViewPosition((Math.PI * 2 * 0.75) + toRadians(stateInfo.mapInfo.rotation) - radianLerpX - (Math.PI + stateInfo.fovWidth), radianLerpY, stateInfo.forwardDistance);
|
||||
let secondVertex = calculateViewPosition((Math.PI * 2 * 0.75) + toRadians(stateInfo.mapInfo.rotation) - radianLerpX + (Math.PI + stateInfo.fovWidth), radianLerpY, stateInfo.forwardDistance);
|
||||
|
||||
let currentX = lerp(startX, endX, completionPercent);
|
||||
let currentY = lerp(startY, endY, completionPercent);
|
||||
|
||||
// we need to calculate the distance from the center of the map so we can scale if necessary
|
||||
let centerX = ((stateInfo.mapInfo.maxLeft - stateInfo.mapInfo.centerY) * stateInfo.mapScaler) + (stateInfo.mapInfo.left * stateInfo.imageScaler);
|
||||
let centerY = ((stateInfo.mapInfo.maxTop - stateInfo.mapInfo.centerX) * stateInfo.mapScaler) + (stateInfo.mapInfo.top * stateInfo.imageScaler);
|
||||
|
||||
// reuse lerp to scale the pixel to map ratio
|
||||
currentX = lerp(centerX, currentX, stateInfo.mapInfo.scaler);
|
||||
currentY = lerp(centerY, currentY, stateInfo.mapInfo.scaler);
|
||||
|
||||
drawCircle(ctx, centerX, centerY, 'green');
|
||||
drawCircle(ctx, currentX, currentY, teamColor);
|
||||
drawTriangle(ctx,
|
||||
{ x: currentX, y: currentY },
|
||||
{ x: currentX + firstVertex.x, y: currentY + firstVertex.y },
|
||||
{ x: currentX + secondVertex.x, y: currentY + secondVertex.y },
|
||||
fovColor);
|
||||
drawText(ctx, currentX, currentY - textOffset, value.name, 24, 'white', teamColor)
|
||||
drawText(ctx, currentX, currentY - textOffset, value.name, 24, 'white', teamColor, 'center')
|
||||
});
|
||||
|
||||
const completedIcons = [];
|
||||
|
||||
for (let key in stateInfo.deathIcons) {
|
||||
const icon = stateInfo.deathIcons[key];
|
||||
|
||||
const x = ((stateInfo.mapInfo.maxLeft - icon.location.y) * stateInfo.mapScaler) + (stateInfo.mapInfo.left * stateInfo.imageScaler);
|
||||
const y = ((stateInfo.mapInfo.maxTop - icon.location.x) * stateInfo.mapScaler) + (stateInfo.mapInfo.top * stateInfo.imageScaler);
|
||||
|
||||
const elapsedFrameTime = now - icon.animationTime;
|
||||
const completionPercent = elapsedFrameTime / stateInfo.deathIconTime;
|
||||
const opacity = easeLerp(1, 0, completionPercent);
|
||||
|
||||
drawImage(stateInfo.ctx, 'hud_death', x, y, opacity);
|
||||
|
||||
if (completionPercent >= 1) {
|
||||
completedIcons.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < completedIcons.length; i++) {
|
||||
delete stateInfo.deathIcons[completedIcons[i]];
|
||||
}
|
||||
|
||||
window.requestAnimationFrame(updateMap);
|
||||
}
|
||||
|
||||
$.getJSON('@Url.Action("Map", "Radar", null)', function (_map) {
|
||||
$('#map_list').append(`<img src=../images/compass_map_${_map.name}@('@')2x.png></img>`);
|
||||
stateInfo.mapInfo = _map
|
||||
setInterval(updateRadarData, stateInfo.updateFrequency);
|
||||
window.requestAnimationFrame(updateMap);
|
||||
});
|
||||
$(document).ready(function () {
|
||||
$.getJSON('@Url.Action("Map", "Radar", null)', function (_map) {
|
||||
stateInfo.mapInfo = _map;
|
||||
updateRadarData();
|
||||
setInterval(updateRadarData, stateInfo.updateFrequency);
|
||||
});
|
||||
})
|
||||
|
||||
</script>
|
||||
}
|
@ -11,8 +11,8 @@ var plugin = {
|
||||
|
||||
// connect or join event
|
||||
if (gameEvent.Type === 3) {
|
||||
// this GUID seems to have been packed in a IW4 torrent and results in an unreasonable amount of people using the same GUID
|
||||
if (gameEvent.Origin.NetworkId === -805366929435212061) {
|
||||
// this GUID seems to have been packed in a IW4 torrent and results in an unreasonable amount of people using the same GUID
|
||||
if (gameEvent.Origin.NetworkId === -805366929435212061 || gameEvent.Origin.NetworkId == -3304388024725980231) {
|
||||
gameEvent.Origin.Kick('Your GUID is generic. Delete players/guids.dat and rejoin', _IW4MAdminClient);
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ namespace SharedLibraryCore.Events
|
||||
{
|
||||
public class EventApi
|
||||
{
|
||||
const int MaxEvents = 100;
|
||||
const int MaxEvents = 25;
|
||||
static ConcurrentQueue<EventInfo> RecentEvents = new ConcurrentQueue<EventInfo>();
|
||||
|
||||
public static IEnumerable<EventInfo> GetEvents(bool shouldConsume)
|
||||
|
@ -51,6 +51,7 @@ namespace WebfrontCore.Controllers
|
||||
}).ToList();
|
||||
|
||||
ViewBag.Version = Manager.Version;
|
||||
ViewBag.IsFluid = false;
|
||||
}
|
||||
|
||||
public override void OnActionExecuting(ActionExecutingContext context)
|
||||
|
@ -125,7 +125,7 @@
|
||||
</div>
|
||||
<!-- End Action Modal -->
|
||||
|
||||
<div class="container p-4">
|
||||
<div class="@(ViewBag.IsFluid ?? false ? "container-fluid" : "container") pt-4 pb-4 pl-3 pr-3 pr-lg-4 pl-lg-4">
|
||||
@RenderBody()
|
||||
<footer id="footer_text">
|
||||
<div class="d-lg-none d-block text-center pt-4 pb-4">
|
||||
|
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_40mmgrenade.webp
Normal file
After Width: | Height: | Size: 594 B |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_aa12.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_aa12.webp
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_ak47.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_ak47.webp
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_akd74u.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_akd74u.webp
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_at4.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_at4.webp
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_barrett50cal.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_barrett50cal.webp
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_benelli_m4.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_benelli_m4.webp
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_beretta393.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_beretta393.webp
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_cheytac.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_cheytac.webp
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_colt45.webp
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_colt_anaconda.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_colt_anaconda.webp
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_death.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_desert_eagle.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_desert_eagle.webp
Normal file
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 3.1 KiB |
After Width: | Height: | Size: 1.6 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_dragunovsvd.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_dragunovsvd.webp
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_famas.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_famas.webp
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_fn2000.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_fn2000.webp
Normal file
After Width: | Height: | Size: 2.0 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_fnfal.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_fnfal.webp
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_g36c_mp.webp
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_glock.png
Normal file
After Width: | Height: | Size: 2.7 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_glock.webp
Normal file
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 1.7 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_javelin.png
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_javelin.webp
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_kriss.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_kriss.webp
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_m14ebr.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_m14ebr.webp
Normal file
After Width: | Height: | Size: 2.3 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_m16a4.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_m16a4.webp
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_m240.png
Normal file
After Width: | Height: | Size: 4.6 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_m240.webp
Normal file
After Width: | Height: | Size: 2.4 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_m249saw.webp
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_m40a3.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_m40a3.webp
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_m4carbine.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_m4carbine.webp
Normal file
After Width: | Height: | Size: 2.1 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_m79.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_m79.webp
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_m9beretta.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_m9beretta.webp
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_masada.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_masada.webp
Normal file
After Width: | Height: | Size: 2.6 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_mg4.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_mg4.webp
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_mini_uzi.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_mini_uzi.webp
Normal file
After Width: | Height: | Size: 1.3 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_model1887.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_model1887.webp
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_mp5k.png
Normal file
After Width: | Height: | Size: 6.0 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_mp5k.webp
Normal file
After Width: | Height: | Size: 3.3 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_mp9.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_mp9.webp
Normal file
After Width: | Height: | Size: 1.5 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_neutral.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_neutral.webp
Normal file
After Width: | Height: | Size: 952 B |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_p90.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_p90.webp
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_peacekeeper.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_peacekeeper.webp
Normal file
After Width: | Height: | Size: 2.2 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_pp2000.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_pp2000.webp
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_remington_700.webp
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_riot_shield.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_riot_shield.webp
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_rpd.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_rpd.webp
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_rpg.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_rpg.webp
Normal file
After Width: | Height: | Size: 1.6 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_sa80_lmg.png
Normal file
After Width: | Height: | Size: 4.5 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_sa80_lmg.webp
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_sawed_off.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_sawed_off.webp
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_scar_h.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
WebfrontCore/wwwroot/images/hud_weapons/hud_scar_h.webp
Normal file
After Width: | Height: | Size: 2.1 KiB |