C#:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using UnityEngine;
using Random = UnityEngine.Random;
namespace Oxide.Plugins
{
[Info("Hit Markers", "https://discord.gg/9vyTXsJyKR", "1.0.0")]
public class HitMarkersRu : RustPlugin
{
#region Fields
[PluginReference] private Plugin ImageLibrary, Notify, BMenu;
private const string Layer = "UI.HitMarkers";
private const string HitLayer = "UI.HitMarkers.Hit";
private const string HealthLineLayer = "UI.HitMarkers.HealthLine";
private static HitMarkersRu _instance;
#endregion
#region Config
private static Configuration _config;
private class Configuration
{
[JsonProperty(PropertyName = "Команды", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public string[] Commands = { "marker", "hits" };
[JsonProperty(PropertyName = "Разрешение (например: hitmarkersru.use)")]
public string Permission = string.Empty;
[JsonProperty(PropertyName = "Включить работу с Notify?")]
public bool UseNotify = true;
[JsonProperty(PropertyName = "Шрифты", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<int, FontConf> Fonts = new Dictionary<int, FontConf>
{
[0] = new FontConf
{
Font = "robotocondensed-bold.ttf",
Permission = string.Empty
},
[1] = new FontConf
{
Font = "robotocondensed-regular.ttf",
Permission = string.Empty
},
[2] = new FontConf
{
Font = "permanentmarker.ttf",
Permission = string.Empty
},
[3] = new FontConf
{
Font = "droidsansmono.ttf",
Permission = string.Empty
}
};
[JsonProperty(PropertyName = "Минимальный размер шрифта")]
public int MinFontSize = 8;
[JsonProperty(PropertyName = "Максимальный размер шрифта")]
public int MaxFontSize = 18;
[JsonProperty(PropertyName = "Кнопки", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public List<BtnConf> Buttons = new List<BtnConf>
{
new BtnConf
{
Enabled = true,
Title = "Текст",
Type = BtnType.Text,
Description = "<b>Цифры нанесённого урона</b> появится в центре экрана!",
Permission = string.Empty
},
new BtnConf
{
Enabled = true,
Title = "Иконка",
Type = BtnType.Icon,
Description = "Привычная всем иконка попадания, меняет цвет при выстреле <b>в голову</b>!",
Permission = string.Empty
},
new BtnConf
{
Enabled = true,
Title = "Полоса",
Type = BtnType.HealthLine,
Description = "Над слотами появляется полоса, показывающая <b>оставшееся</b> ХП врага.",
Permission = string.Empty
},
new BtnConf
{
Enabled = true,
Title = "Постройки",
Type = BtnType.Buildings,
Description = "Отображение повреждений по строениям",
Permission = string.Empty
}
};
[JsonProperty(PropertyName = "Иконка информации")]
public string InfoIcon = "https://i.imgur.com/YIRjnIT.png";
[JsonProperty(PropertyName = "Показывать урон по НПЦ")]
public bool ShowNpcDamage = true;
[JsonProperty(PropertyName = "Показывать урон по животным")]
public bool ShowAnimalDamage;
[JsonProperty(PropertyName = "Время удаления маркера")]
public float DestroyTime = 0.25f;
[JsonProperty(PropertyName = "Значения по умолчанию")]
public DefaultValues DefaultValues = new DefaultValues
{
FontSize = 14,
Buildings = false,
FontId = 0,
HealthLine = false,
Icon = false,
Text = true
};
[JsonProperty(PropertyName = "Настройка линии")]
public LineSettings Line = new LineSettings
{
Show = true,
Text = false
};
}
private class LineSettings
{
[JsonProperty(PropertyName = "Показывать линию?")]
public bool Show;
[JsonProperty(PropertyName = "Показывать текст?")]
public bool Text;
}
private class DefaultValues
{
[JsonProperty(PropertyName = "ID шрифта")]
public int FontId;
[JsonProperty(PropertyName = "Размер шрифта")]
public int FontSize;
[JsonProperty(PropertyName = "Текст")] public bool Text;
[JsonProperty(PropertyName = "Иконка")] public bool Icon;
[JsonProperty(PropertyName = "Полоса ХП ")]
public bool HealthLine;
[JsonProperty(PropertyName = "Урон по строениям")]
public bool Buildings;
}
private class BtnConf
{
[JsonProperty(PropertyName = "Включено")]
public bool Enabled;
[JsonProperty(PropertyName = "Название")] public string Title;
[JsonProperty(PropertyName = "Тип")] [JsonConverter(typeof(StringEnumConverter))]
public BtnType Type;
[JsonProperty(PropertyName = "Описание")]
public string Description;
[JsonProperty(PropertyName = "Разрешение (например: hitmarkersru.text)")]
public string Permission;
}
private enum BtnType
{
Text,
Icon,
HealthLine,
Buildings
}
private class FontConf
{
[JsonProperty(PropertyName = "Шрифт")] public string Font;
[JsonProperty(PropertyName = "Разрешение (например: hitmarkersru.font)")]
public string Permission;
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
_config = Config.ReadObject<Configuration>();
if (_config == null) throw new Exception();
SaveConfig();
}
catch (Exception ex)
{
PrintError("Your configuration file contains an error.Using default configuration values.");
LoadDefaultConfig();
Debug.LogException(ex);
}
}
protected override void SaveConfig()
{
Config.WriteObject(_config);
}
protected override void LoadDefaultConfig()
{
_config = new Configuration();
}
#endregion
#region Data
private static PluginData _data;
private void SaveData()
{
Interface.Oxide.DataFileSystem.WriteObject(Name, _data);
}
private void LoadData()
{
try
{
_data = Interface.Oxide.DataFileSystem.ReadObject<PluginData>(Name);
}
catch (Exception e)
{
PrintError(e.ToString());
}
if (_data == null) _data = new PluginData();
}
private class PluginData
{
[JsonProperty(PropertyName = "Players", ObjectCreationHandling = ObjectCreationHandling.Replace)]
public Dictionary<ulong, PlayerData> Players = new Dictionary<ulong, PlayerData>();
}
private class PlayerData
{
[JsonProperty(PropertyName = "Font ID")]
public int FontId;
[JsonProperty(PropertyName = "Font Size")]
public int FontSize;
[JsonProperty(PropertyName = "Text")] public bool Text;
[JsonProperty(PropertyName = "Icon")] public bool Icon;
[JsonProperty(PropertyName = "Health Line")]
public bool HealthLine;
[JsonProperty(PropertyName = "Buildings")]
public bool Buildings;
public static PlayerData GetOrAdd(BasePlayer player)
{
return GetOrAdd(player.userID);
}
public static PlayerData GetOrAdd(ulong userId)
{
if (!_data.Players.ContainsKey(userId))
_data.Players.Add(userId, new PlayerData
{
FontSize = _config.DefaultValues.FontSize,
FontId = _config.DefaultValues.FontId,
Text = _config.DefaultValues.Text,
Buildings = _config.DefaultValues.Buildings,
Icon = _config.DefaultValues.Icon,
HealthLine = _config.DefaultValues.HealthLine
});
return _data.Players[userId];
}
public bool GetValue(BtnType type)
{
switch (type)
{
case BtnType.Text:
return Text;
case BtnType.Icon:
return Icon;
case BtnType.HealthLine:
return HealthLine;
case BtnType.Buildings:
return Buildings;
default:
throw new ArgumentOutOfRangeException();
}
}
public void SetValue(BtnType type, bool newValue)
{
switch (type)
{
case BtnType.Text:
Text = newValue;
break;
case BtnType.Icon:
Icon = newValue;
break;
case BtnType.HealthLine:
HealthLine = newValue;
break;
case BtnType.Buildings:
Buildings = newValue;
break;
default:
throw new ArgumentOutOfRangeException();
}
}
}
#endregion
#region Hooks
private void OnServerInitialized()
{
_instance = this;
LoadData();
RegisterPermissions();
ImageLibrary?.Call("AddImage", _config.InfoIcon, _config.InfoIcon);
AddCovalenceCommand(_config.Commands, nameof(CmdOpenMarkers));
}
private void Unload()
{
foreach (var player in BasePlayer.activePlayerList) CuiHelper.DestroyUi(player, Layer);
_markerByPlayer.Values.ToList().ForEach(marker =>
{
if (marker != null)
marker.Kill();
});
SaveData();
_instance = null;
_data = null;
_config = null;
}
private void OnEntityTakeDamage(BuildingBlock block, HitInfo info)
{
if (block == null || info == null || info.damageTypes.Total() < 1) return;
var player = info.InitiatorPlayer;
if (player == null) return;
var marker = GetMarker(player);
if (marker == null) return;
if (PlayerData.GetOrAdd(player).Buildings)
NextTick(() =>
{
if (block != null && !block.IsDestroyed)
marker.ShowHit(block, info);
});
}
private void OnPlayerAttack(BasePlayer attacker, HitInfo info)
{
if (attacker == null || attacker.IsNpc || info == null) return;
var target = info.HitEntity as BaseCombatEntity;
if (target == null || target is BaseCorpse || target is BuildingBlock ||
!_config.ShowAnimalDamage && target is BaseAnimalNPC ||
!_config.ShowNpcDamage &&
(target is BaseNpc || target is BasePlayer && (target as BasePlayer).IsNpc)) return;
NextTick(() =>
{
if (target != null && !target.IsDestroyed)
GetOrAddMarker(attacker).ShowHit(target, info);
});
}
#endregion
#region Commands
private void CmdOpenMarkers(IPlayer cov, string command, string[] args)
{
var player = cov?.Object as BasePlayer;
if (player == null) return;
if (!string.IsNullOrEmpty(_config.Permission) &&
!permission.UserHasPermission(player.UserIDString, _config.Permission))
{
SendNotify(player, NoPermission, 1);
return;
}
MainUi(player, true);
}
[ConsoleCommand("UI_Markers")]
private void CmdConsoleMarkers(ConsoleSystem.Arg arg)
{
var player = arg?.Player();
if (player == null || !arg.HasArgs()) return;
switch (arg.Args[0])
{
case "settype":
{
BtnType type;
if (!arg.HasArgs(2) || !Enum.TryParse(arg.Args[1], out type)) return;
var data = PlayerData.GetOrAdd(player);
if (data == null) return;
var perm = _config.Buttons.Find(x => x.Type == type);
if (perm != null)
if (!string.IsNullOrEmpty(perm.Permission) &&
!permission.UserHasPermission(player.UserIDString, perm.Permission))
{
SendNotify(player, NoPermission, 1);
return;
}
data.SetValue(type, !data.GetValue(type));
MainUi(player);
break;
}
case "setsize":
{
int fontSize;
if (!arg.HasArgs(2) || !int.TryParse(arg.Args[1], out fontSize)) return;
var data = PlayerData.GetOrAdd(player);
if (data == null) return;
data.FontSize = fontSize;
MainUi(player);
break;
}
case "setfont":
{
int fontId;
if (!arg.HasArgs(2) || !int.TryParse(arg.Args[1], out fontId)) return;
var data = PlayerData.GetOrAdd(player);
if (data == null) return;
data.FontId = fontId;
MainUi(player);
break;
}
case "info":
{
int index;
if (!arg.HasArgs(2) || !int.TryParse(arg.Args[1], out index) || index < 0 ||
_config.Buttons.Count <= index) return;
InfoUi(player, _config.Buttons[index].Description);
break;
}
}
}
#endregion
#region Interface
private void MainUi(BasePlayer player, bool first = false)
{
var data = PlayerData.GetOrAdd(player);
if (data == null) return;
float xSwitch;
float ySwitch;
float width;
float height;
float margin;
var container = new CuiElementContainer();
#region Background
if (first)
{
CuiHelper.DestroyUi(player, Layer);
container.Add(new CuiPanel
{
RectTransform = { AnchorMin = "0 0", AnchorMax = "1.3 1" },
Image =
{
Color = "0 0 0 0.0",
Material = "assets/content/ui/uibackgroundblur.mat"
},
CursorEnabled = true
}, "SubContent_UI", Layer);
container.Add(new CuiButton
{
RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" },
Text = { Text = "" },
Button =
{
Color = "0 0 0 0",
Close = Layer
}
}, Layer);
}
#endregion
#region Main
container.Add(new CuiPanel
{
RectTransform =
{
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5",
OffsetMin = "-300 -190",
OffsetMax = "300 190"
},
Image =
{
Color = "0 0 0 0"
}
}, Layer, Layer + ".Main");
#region Header
container.Add(new CuiPanel
{
RectTransform =
{
AnchorMin = "0 1", AnchorMax = "1 1",
OffsetMin = "0 -50",
OffsetMax = "0 0"
},
Image = { Color = "0 0 0 0" }
}, Layer + ".Main", Layer + ".Header");
container.Add(new CuiLabel
{
RectTransform =
{
AnchorMin = "0 0", AnchorMax = "1 1",
OffsetMin = "30 0",
OffsetMax = "0 0"
},
Text =
{
Text = Msg(player, TitleMenu),
Align = TextAnchor.MiddleLeft,
Font = "robotocondensed-bold.ttf",
FontSize = 14,
Color = HexToCuiColor("#FFFFFF")
}
}, Layer + ".Header");
container.Add(new CuiButton
{
RectTransform =
{
AnchorMin = "1 1", AnchorMax = "1 1",
OffsetMin = "-50 -37.5",
OffsetMax = "-25 -12.5"
},
Text =
{
Text = Msg(player, CloseButton),
Align = TextAnchor.MiddleCenter,
Font = "robotocondensed-bold.ttf",
FontSize = 10,
Color = "0 0 0 0"
},
Button =
{
Close = Layer,
Color = "0 0 0 0"
}
}, Layer + ".Header");
#endregion
#region Preview
container.Add(new CuiPanel
{
RectTransform =
{
AnchorMin = "0.5 1", AnchorMax = "0.5 1",
OffsetMin = "95 -255",
OffsetMax = "265 -85"
},
Image =
{
Color = HexToCuiColor("#161617")
}
}, Layer + ".Main", Layer + ".Preview");
container.Add(new CuiLabel
{
RectTransform =
{
AnchorMin = "0 0", AnchorMax = "1 0",
OffsetMin = "0 0", OffsetMax = "0 18"
},
Text =
{
Text = Msg(player, LooksNow),
Align = TextAnchor.MiddleCenter,
Font = "robotocondensed-regular.ttf",
FontSize = 12,
Color = "1 1 1 0.4"
}
}, Layer + ".Preview");
container.Add(new CuiLabel
{
RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" },
Text =
{
Text = Msg(player, PreviewTitle),
Align = TextAnchor.MiddleCenter,
Font = $"{_config.Fonts[data.FontId].Font}",
FontSize = data.FontSize,
Color = "1 1 1 0.7"
}
}, Layer + ".Preview");
#endregion
#region Fonts
xSwitch = -265f;
ySwitch = -85f;
margin = 10f;
width = 80f;
height = 80f;
var i = 1;
foreach (var fontConf in _config.Fonts)
{
var selected = fontConf.Key == data.FontId;
container.Add(new CuiPanel
{
RectTransform =
{
AnchorMin = "0.5 1", AnchorMax = "0.5 1",
OffsetMin = $"{xSwitch} {ySwitch - height}",
OffsetMax = $"{xSwitch + width} {ySwitch}"
},
Image =
{
Color = selected ? HexToCuiColor("#4B68FF") : HexToCuiColor("#161617")
}
}, Layer + ".Main", Layer + $".Font.{fontConf.Key}");
container.Add(new CuiLabel
{
RectTransform =
{
AnchorMin = "0 0.5", AnchorMax = "1 1",
OffsetMin = "0 2", OffsetMax = "0 0"
},
Text =
{
Text = Msg(player, TextTitle),
Align = TextAnchor.LowerCenter,
Font = fontConf.Value.Font,
FontSize = 14,
Color = selected ? HexToCuiColor("#FFFFFF") : HexToCuiColor("#4B68FF")
}
}, Layer + $".Font.{fontConf.Key}");
container.Add(new CuiLabel
{
RectTransform =
{
AnchorMin = "0 0", AnchorMax = "1 0.5",
OffsetMin = "0", OffsetMax = "0 -2"
},
Text =
{
Text = Msg(player, FontTitle, i),
Align = TextAnchor.UpperCenter,
Font = "robotocondensed-regular.ttf",
FontSize = 14,
Color = HexToCuiColor("#FFFFFF")
}
}, Layer + $".Font.{fontConf.Key}");
container.Add(new CuiButton
{
RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" },
Text = { Text = "" },
Button =
{
Color = "0 0 0 0",
Command = $"UI_Markers setfont {fontConf.Key}"
}
}, Layer + $".Font.{fontConf.Key}");
xSwitch += margin + width;
i++;
}
#endregion
#region Font Size
container.Add(new CuiPanel
{
RectTransform =
{
AnchorMin = "0.5 1", AnchorMax = "0.5 1",
OffsetMin = "-265 -255",
OffsetMax = "85 -175"
},
Image =
{
Color = HexToCuiColor("#161617")
}
}, Layer + ".Main", Layer + ".FontSize");
container.Add(new CuiLabel
{
RectTransform =
{
AnchorMin = "0 0.5", AnchorMax = "1 1",
OffsetMin = "15 0", OffsetMax = "0 0"
},
Text =
{
Text = Msg(player, FontIncreaseTitle),
Align = TextAnchor.LowerLeft,
Font = "robotocondensed-regular.ttf",
FontSize = 12,
Color = "1 1 1 1"
}
}, Layer + ".FontSize");
container.Add(new CuiLabel
{
RectTransform =
{
AnchorMin = "0 0.5", AnchorMax = "1 0.5",
OffsetMin = "280 -25",
OffsetMax = "0 0"
},
Text =
{
Text = Msg(player, FontSizeFormat, data.FontSize),
Align = TextAnchor.MiddleLeft,
Font = "robotocondensed-regular.ttf",
FontSize = 14,
Color = "1 1 1 1"
}
}, Layer + ".FontSize");
container.Add(new CuiPanel
{
RectTransform =
{
AnchorMin = "0 0.5", AnchorMax = "0 0.5",
OffsetMin = "15 -15",
OffsetMax = "265 -10"
},
Image =
{
Color = HexToCuiColor("#C4C4C4", 20)
}
}, Layer + ".FontSize", Layer + ".FontSize.Line");
width = 250;
var steps = _config.MaxFontSize - _config.MinFontSize;
var progress = (float)(data.FontSize - _config.MinFontSize) / steps;
container.Add(new CuiPanel
{
RectTransform = { AnchorMin = "0 0", AnchorMax = $"{progress} 0.95" },
Image =
{
Color = HexToCuiColor("#4B68FF")
}
}, Layer + ".FontSize.Line", Layer + ".FontSize.Line.Finish");
container.Add(new CuiPanel
{
RectTransform =
{
AnchorMin = "1 0.5", AnchorMax = "1 0.5",
OffsetMin = "-5 -5", OffsetMax = "5 5"
},
Image =
{
Color = "1 1 1 1"
}
}, Layer + ".FontSize.Line.Finish");
var size = width / steps;
xSwitch = 0;
for (var j = _config.MinFontSize; j <= _config.MaxFontSize; j++)
{
container.Add(new CuiButton
{
RectTransform =
{
AnchorMin = "0 0", AnchorMax = "0 1",
OffsetMin = $"{xSwitch} 0",
OffsetMax = $"{xSwitch + size} 0"
},
Text =
{
Text = ""
},
Button =
{
Color = "0 0 0 0",
Command = $"UI_Markers setsize {j}"
}
}, Layer + ".FontSize.Line");
xSwitch += size;
}
#endregion
#region Buttons
width = 530;
var buttons = _config.Buttons.FindAll(x => x.Enabled);
margin = 10f;
size = (width - (buttons.Count - 1) * margin) / buttons.Count;
xSwitch = -265f;
for (i = 0; i < buttons.Count; i++)
{
var btn = buttons[i];
container.Add(new CuiPanel
{
RectTransform =
{
AnchorMin = "0.5 1", AnchorMax = "0.5 1",
OffsetMin = $"{xSwitch} -325",
OffsetMax = $"{xSwitch + size} -265"
},
Image =
{
Color = HexToCuiColor("#161617")
}
}, Layer + ".Main", Layer + $".Btn.{i}");
container.Add(new CuiLabel
{
RectTransform =
{
AnchorMin = "0 0.5", AnchorMax = "1 1",
OffsetMin = "0 0", OffsetMax = "0 0"
},
Text =
{
Text = $"{btn.Title}",
Align = TextAnchor.LowerCenter,
Font = "robotocondensed-regular.ttf",
FontSize = 12,
Color = "1 1 1 1"
}
}, Layer + $".Btn.{i}");
SwitchUi(ref container, Layer + $".Btn.{i}", data.GetValue(btn.Type), $"UI_Markers settype {btn.Type}");
#region Info
container.Add(new CuiLabel
{
RectTransform =
{
AnchorMin = "1 0", AnchorMax = "1 0",
OffsetMin = "-40 16",
OffsetMax = "0 32"
},
Text =
{
Text = Msg(player, InfoTitle),
Align = TextAnchor.MiddleLeft,
Font = "robotocondensed-regular.ttf",
FontSize = 12,
Color = "1 1 1 0.4"
}
}, Layer + $".Btn.{i}");
if (ImageLibrary)
container.Add(new CuiElement
{
Parent = Layer + $".Btn.{i}",
Components =
{
new CuiRawImageComponent { Png = ImageLibrary.Call<string>("GetImage", _config.InfoIcon) },
new CuiRectTransformComponent
{
AnchorMin = "1 0", AnchorMax = "1 0",
OffsetMin = "-52 18", OffsetMax = "-40 30"
}
}
});
container.Add(new CuiButton
{
RectTransform =
{
AnchorMin = "1 0", AnchorMax = "1 0",
OffsetMin = "-52 18", OffsetMax = "0 30"
},
Text = { Text = "" },
Button =
{
Color = "0 0 0 0",
Command = $"UI_Markers info {_config.Buttons.IndexOf(btn)}"
}
}, Layer + $".Btn.{i}");
#endregion
xSwitch += margin + size;
}
#endregion
#endregion
CuiHelper.DestroyUi(player, Layer + ".Main");
CuiHelper.AddUi(player, container);
}
private void SwitchUi(ref CuiElementContainer container, string parent, bool value, string command)
{
var guid = CuiHelper.GetGuid();
container.Add(new CuiPanel
{
RectTransform =
{
AnchorMin = "0 0", AnchorMax = "0 0",
OffsetMin = "18 16",
OffsetMax = "56 28"
},
Image =
{
Color = HexToCuiColor("#C4C4C4", 20)
}
}, parent, guid);
if (value)
container.Add(new CuiPanel
{
RectTransform = { AnchorMin = "0.5 0", AnchorMax = "1 1" },
Image =
{
Color = HexToCuiColor("#4B68FF")
}
}, guid);
else
container.Add(new CuiPanel
{
RectTransform = { AnchorMin = "0 0", AnchorMax = "0.5 1" },
Image =
{
Color = HexToCuiColor("#FFFFFF", 40)
}
}, guid);
container.Add(new CuiButton
{
RectTransform = { AnchorMin = "0 0", AnchorMax = "1 1" },
Text = { Text = "" },
Button =
{
Color = "0 0 0 0",
Command = $"{command}"
}
}, guid);
}
private void InfoUi(BasePlayer player, string text)
{
var container = new CuiElementContainer();
container.Add(new CuiLabel
{
RectTransform =
{
AnchorMin = "0.5 0", AnchorMax = "0.5 0",
OffsetMin = "-200 0", OffsetMax = "200 130"
},
Text =
{
Text = $"{text}",
Align = TextAnchor.MiddleCenter,
Font = "robotocondensed-regular.ttf",
FontSize = 14,
Color = "1 1 1 0.5"
}
}, Layer, Layer + ".Info");
CuiHelper.DestroyUi(player, Layer + ".Info");
CuiHelper.AddUi(player, container);
}
#endregion
#region Utils
private void RegisterPermissions()
{
foreach (var font in _config.Fonts.Values.Where(check =>
!string.IsNullOrEmpty(check.Permission) && !permission.PermissionExists(check.Permission)))
permission.RegisterPermission(font.Permission, this);
_config.Buttons.ForEach(btn =>
{
if (!string.IsNullOrEmpty(btn.Permission) && !permission.PermissionExists(btn.Permission))
permission.RegisterPermission(btn.Permission, this);
});
if (!string.IsNullOrEmpty(_config.Permission) && !permission.PermissionExists(_config.Permission))
permission.RegisterPermission(_config.Permission, this);
}
private static string HexToCuiColor(string hex, float alpha = 100)
{
if (string.IsNullOrEmpty(hex)) hex = "#FFFFFF";
var str = hex.Trim('#');
if (str.Length != 6) throw new Exception(hex);
var r = byte.Parse(str.Substring(0, 2), NumberStyles.HexNumber);
var g = byte.Parse(str.Substring(2, 2), NumberStyles.HexNumber);
var b = byte.Parse(str.Substring(4, 2), NumberStyles.HexNumber);
return $"{(double)r / 255} {(double)g / 255} {(double)b / 255} {alpha / 100f}";
}
private static bool IsTeammates(ulong player, ulong friend)
{
return RelationshipManager.ServerInstance.FindPlayersTeam(player)?.members?.Contains(friend) == true;
}
private static Vector2 GetRandomTextPosition()
{
var x = (float)Random.Range(45, 55) / 100;
var y = (float)Random.Range(40, 60) / 100;
return new Vector2(x, y);
}
private static string GetGradientColor(int count, int max)
{
if (count > max)
count = max;
var n = max > 0 ? (float)ColorsGradientDB.Length / max : 0;
var index = (int)(count * n);
if (index > 0) index--;
return ColorsGradientDB[index];
}
private static readonly string[] ColorsGradientDB =
{
"0.2000 0.8000 0.2000 1.0000",
"0.2471 0.7922 0.1961 1.0000",
"0.2824 0.7843 0.1922 1.0000",
"0.3176 0.7725 0.1843 1.0000",
"0.3451 0.7647 0.1804 1.0000",
"0.3686 0.7569 0.1765 1.0000",
"0.3922 0.7490 0.1725 1.0000",
"0.4118 0.7412 0.1686 1.0000",
"0.4314 0.7333 0.1647 1.0000",
"0.4471 0.7216 0.1608 1.0000",
"0.4667 0.7137 0.1569 1.0000",
"0.4784 0.7059 0.1529 1.0000",
"0.4941 0.6980 0.1490 1.0000",
"0.5098 0.6902 0.1412 1.0000",
"0.5216 0.6824 0.1373 1.0000",
"0.5333 0.6706 0.1333 1.0000",
"0.5451 0.6627 0.1294 1.0000",
"0.5569 0.6549 0.1255 1.0000",
"0.5647 0.6471 0.1216 1.0000",
"0.5765 0.6392 0.1176 1.0000",
"0.5843 0.6314 0.1137 1.0000",
"0.5922 0.6235 0.1137 1.0000",
"0.6039 0.6118 0.1098 1.0000",
"0.6118 0.6039 0.1059 1.0000",
"0.6196 0.5961 0.1020 1.0000",
"0.6275 0.5882 0.0980 1.0000",
"0.6314 0.5804 0.0941 1.0000",
"0.6392 0.5725 0.0902 1.0000",
"0.6471 0.5647 0.0863 1.0000",
"0.6510 0.5569 0.0824 1.0000",
"0.6588 0.5451 0.0784 1.0000",
"0.6627 0.5373 0.0784 1.0000",
"0.6667 0.5294 0.0745 1.0000",
"0.6745 0.5216 0.0706 1.0000",
"0.6784 0.5137 0.0667 1.0000",
"0.6824 0.5059 0.0627 1.0000",
"0.6863 0.4980 0.0588 1.0000",
"0.6902 0.4902 0.0588 1.0000",
"0.6941 0.4824 0.0549 1.0000",
"0.6980 0.4745 0.0510 1.0000",
"0.7020 0.4667 0.0471 1.0000",
"0.7020 0.4588 0.0471 1.0000",
"0.7059 0.4471 0.0431 1.0000",
"0.7098 0.4392 0.0392 1.0000",
"0.7098 0.4314 0.0392 1.0000",
"0.7137 0.4235 0.0353 1.0000",
"0.7176 0.4157 0.0314 1.0000",
"0.7176 0.4078 0.0314 1.0000",
"0.7216 0.4000 0.0275 1.0000",
"0.7216 0.3922 0.0275 1.0000",
"0.7216 0.3843 0.0235 1.0000",
"0.7255 0.3765 0.0235 1.0000",
"0.7255 0.3686 0.0196 1.0000",
"0.7255 0.3608 0.0196 1.0000",
"0.7255 0.3529 0.0196 1.0000",
"0.7294 0.3451 0.0157 1.0000",
"0.7294 0.3373 0.0157 1.0000",
"0.7294 0.3294 0.0157 1.0000",
"0.7294 0.3216 0.0118 1.0000",
"0.7294 0.3137 0.0118 1.0000",
"0.7294 0.3059 0.0118 1.0000",
"0.7294 0.2980 0.0118 1.0000",
"0.7294 0.2902 0.0078 1.0000",
"0.7255 0.2824 0.0078 1.0000",
"0.7255 0.2745 0.0078 1.0000",
"0.7255 0.2667 0.0078 1.0000",
"0.7255 0.2588 0.0078 1.0000",
"0.7255 0.2510 0.0078 1.0000",
"0.7216 0.2431 0.0078 1.0000",
"0.7216 0.2353 0.0039 1.0000",
"0.7176 0.2275 0.0039 1.0000",
"0.7176 0.2196 0.0039 1.0000",
"0.7176 0.2118 0.0039 1.0000",
"0.7137 0.2039 0.0039 1.0000",
"0.7137 0.1961 0.0039 1.0000",
"0.7098 0.1882 0.0039 1.0000",
"0.7098 0.1804 0.0039 1.0000",
"0.7059 0.1725 0.0039 1.0000",
"0.7020 0.1647 0.0039 1.0000",
"0.7020 0.1569 0.0039 1.0000",
"0.6980 0.1490 0.0039 1.0000",
"0.6941 0.1412 0.0039 1.0000",
"0.6941 0.1333 0.0039 1.0000",
"0.6902 0.1255 0.0039 1.0000",
"0.6863 0.1176 0.0039 1.0000",
"0.6824 0.1098 0.0039 1.0000",
"0.6784 0.1020 0.0039 1.0000",
"0.6784 0.0941 0.0039 1.0000",
"0.6745 0.0863 0.0039 1.0000",
"0.6706 0.0784 0.0039 1.0000",
"0.6667 0.0706 0.0039 1.0000",
"0.6627 0.0627 0.0039 1.0000",
"0.6588 0.0549 0.0039 1.0000",
"0.6549 0.0431 0.0039 1.0000",
"0.6510 0.0353 0.0000 1.0000",
"0.6471 0.0275 0.0000 1.0000",
"0.6392 0.0196 0.0000 1.0000",
"0.6353 0.0118 0.0000 1.0000",
"0.6314 0.0039 0.0000 1.0000",
"0.6275 0.0000 0.0000 1.0000"
};
#endregion
#region Component
private readonly Dictionary<BasePlayer, MarkerComponent> _markerByPlayer =
new Dictionary<BasePlayer, MarkerComponent>();
private MarkerComponent GetMarker(BasePlayer player)
{
MarkerComponent marker;
return _markerByPlayer.TryGetValue(player, out marker) && marker != null ? marker : null;
}
private MarkerComponent GetOrAddMarker(BasePlayer player)
{
MarkerComponent marker;
if (_markerByPlayer.TryGetValue(player, out marker) && marker != null) return marker;
return player.gameObject.AddComponent<MarkerComponent>();
}
private class MarkerComponent : FacepunchBehaviour
{
private BasePlayer _player;
private PlayerData _playerData;
private void Awake()
{
_player = GetComponent<BasePlayer>();
_playerData = PlayerData.GetOrAdd(_player);
_instance._markerByPlayer[_player] = this;
}
public void ShowHit(BaseCombatEntity target, HitInfo info)
{
if (_playerData.HealthLine) ShowLine(BtnType.HealthLine, target, info);
if (_playerData.Text) ShowLine(BtnType.Text, target, info);
if (_playerData.Icon) ShowLine(BtnType.Icon, target, info);
}
private void ShowLine(BtnType type, BaseCombatEntity target, HitInfo info)
{
var container = new CuiElementContainer();
switch (type)
{
case BtnType.Text:
{
var pos = GetRandomTextPosition();
var textDamage = info.damageTypes.Total().ToString("F0");
if (Mathf.FloorToInt(info.damageTypes.Total()) == 0)
return;
var targetPlayer = target as BasePlayer;
if (targetPlayer != null)
{
if (info.isHeadshot)
textDamage = _instance.Msg(_player, FormatHeadshotTitle, textDamage);
if (targetPlayer.IsWounded())
{
textDamage = _instance.Msg(_player, FormatFellTitle);
if (info.isHeadshot)
textDamage += _instance.Msg(_player, FormatFellHeadshotTitle);
}
if (IsTeammates(_player.userID, targetPlayer.userID))
textDamage = _instance.Msg(_player, FormatFriendTitle);
}
var hitId = CuiHelper.GetGuid();
container.Add(new CuiElement
{
Name = hitId,
Parent = "Hud",
FadeOut = 0.5f,
Components =
{
new CuiTextComponent
{
Text = $"{textDamage}",
Color = "1 1 1 1",
Font = _config.Fonts[_playerData.FontId].Font,
FontSize = _playerData.FontSize,
Align = TextAnchor.MiddleCenter
},
new CuiOutlineComponent { Color = "0 0 0 1", Distance = "0.15500772 0.1550507712" },
new CuiRectTransformComponent
{
AnchorMin = $"{pos.x} {pos.y}", AnchorMax = $"{pos.x} {pos.y}",
OffsetMin = "-100 -100", OffsetMax = "100 100"
}
}
});
CuiHelper.AddUi(_player, container);
StartCoroutine(DestroyHit(hitId));
break;
}
case BtnType.Icon:
{
var hitId = CuiHelper.GetGuid();
var color = "1 1 1 0.5";
var image = "assets/icons/close.png";
float margin = 10;
var targetPlayer = target as BasePlayer;
if (targetPlayer)
{
if (targetPlayer.IsWounded())
{
margin = 20;
image = "assets/icons/fall.png";
}
if (targetPlayer.IsWounded() || targetPlayer.IsDead())
color = "1 0.207745 0.20771 0.5";
}
if (info.isHeadshot) color = "1 0.2 0.2 0.5";
container.Add(new CuiButton
{
FadeOut = 0.3f,
RectTransform =
{
AnchorMin = "0.5 0.5", AnchorMax = "0.5 0.5", OffsetMin = $"-{margin} -{margin}",
OffsetMax = $"{margin} {margin}"
},
Button = { Color = color, Sprite = image },
Text = { Text = "" }
}, "Hud", hitId);
CuiHelper.AddUi(_player, container);
CuiHelper.DestroyUi(_player, hitId);
break;
}
case BtnType.HealthLine:
{
var curHealth = target.health;
var maxHealth = target._maxHealth;
var block = target as BuildingBlock;
if (block != null)
{
var curGrade = block.cur
// ... [Code preview truncated due to length. Full source in attached file] ...