C#:
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Libraries;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using Oxide.Plugins;
using UnityEngine;
using UnityEngine.XR;
namespace Oxide.Plugins {
[Info("Quest", "Hougan", "1.0.0")]
public class Quest : RustPlugin {
#region Classes
private class DResult {
[JsonProperty("code")]
public int Code;
[JsonProperty("result")]
public object Result;
public static DResult GenerateFromAnswer(string input, string id, string type) {
DResult obj = null;
try {
obj = JsonConvert.DeserializeObject<DResult>(input);
}
catch(Exception exception) {
_.LogToFile("QuestErrors", input, _);
Interface.Oxide.LogWarning($"WEB> Critical error in getting result from server [{id}][{type}]");
}
return obj;
}
}
private class DPart {
[JsonProperty("id")]
public int Id;
[JsonProperty("name")]
public string Name;
[JsonProperty("url")]
public string Url;
[JsonProperty("smallUrl")]
public string SmallUrl;
[JsonProperty("amount")]
public int Amount;
[JsonProperty("command")]
public string Command;
[JsonProperty("item")]
public string Item;
public string GetImage() => (string) _.ImageLibrary.Call("GetImage", $"PartsID.{Id}.Avatar");
public string GetSmallImage() => (string) _.ImageLibrary.Call("GetImage", $"PartsID.{Id}.SmallAvatar");
public static void LoadParts() {
_.webrequest.Enqueue($"{Settings.WebURL}/api/parts/fetch?pass=ABCBLOO1ss1009g", "", (i, s) => {
DResult result = DResult.GenerateFromAnswer(s, "0", "parts");
if (result == null) {
return;
}
HashSet<DPart> info = JsonConvert.DeserializeObject<HashSet<DPart>>(result.Result.ToString());
Parts = info;
if (!_.ImageLibrary) {
_.PrintError($"C#> Failed to load images [ERROR]");
return;
}
_.PrintWarning($"WEB> Loaded {info.Count} parts [OK]");
foreach (var part in info) {
_.ImageLibrary.Call("AddImage", part.Url, $"PartsID.{part.Id}.Avatar");
_.ImageLibrary.Call("AddImage", part.SmallUrl, $"PartsID.{part.Id}.SmallAvatar");
}
}
, _);
}
}
private class DPlayer {
[JsonProperty("id")]
public int Id;
[JsonProperty("displayName")]
public string DisplayName;
[JsonProperty("userId")]
public ulong UserID;
[JsonProperty("exp")]
public float Exp;
[JsonProperty("level")]
public float Level;
[JsonProperty("free")]
public bool Free;
[JsonProperty("players@items")]
public List<DItemCache> InventoryCaches = new List<DItemCache>();
[JsonIgnore]
public HashSet<DItem> Inventory = new HashSet<DItem>();
[JsonProperty("players@blockeditems")]
public List<DItem> Blocked = new List<DItem>();
[JsonProperty("murders")]
public List<DMurder> Murders = new List<DMurder>();
[JsonProperty("quest")]
public DQuest Quest = new DQuest();
public void DebugInformation() {
Interface.Oxide.LogWarning($"ID: {Id}");
Interface.Oxide.LogWarning($"Name: {DisplayName}");
Interface.Oxide.LogWarning($"UserID: {UserID}");
Interface.Oxide.LogWarning($"");
Interface.Oxide.LogWarning($"EXP: {Exp}");
Interface.Oxide.LogWarning($"Level: {Level}");
Interface.Oxide.LogWarning($"");
Interface.Oxide.LogWarning($"Inventory count: {Inventory.Count}");
Interface.Oxide.LogWarning($"Murders count: {Murders.Count}");
Interface.Oxide.LogWarning($"Active quest: {Quest != null}");
}
public void RefreshIDs() {
foreach (var check in Inventory) {
check.OutID = CuiHelper.GetGuid();
}
}
public void FinishQuest(Action<bool> callback, bool manual = false) {
if (Quest == null || !Quest.IsEnd()) return;
_.webrequest.Enqueue($"{Settings.WebURL}/api/players/finishQuest/{UserID}/{manual}?pass=ABCBLOO1ss1009g", "", (i, s) => {
UpdateAfterUpdate(s);
callback(true);
}
, _);
}
public void GenerateQuest(DMurder murder, Action<bool> callback) {
if (Quest != null) {
callback(false);
return;
}
var player = BasePlayer.Find(UserID.ToString());
float length = Settings.TaskPrice[murder.Level].Length;
if (murder.Level == 4) {
length = Mathf.FloorToInt(Oxide.Core.Random.Range(600, 7200));
}
_.webrequest.Enqueue($"{Settings.WebURL}/api/players/setQuest/{UserID}/{murder.Level}/{length}?pass=ABCBLOO1ss1009g", "", (i, s) => {
UpdateAfterUpdate(s);
player.GetComponent<WPlayer>().SendExpUpdate();
callback(true);
}
, _);
}
public static void GetFromPlayer(BasePlayer player, Action<DPlayer> callback) {
GetFromPlayer(player.displayName, player.userID, callback);
}
public static void GetFromPlayer(string displayName, ulong userId, Action<DPlayer> callback) {
_.webrequest.Enqueue($"{Settings.WebURL}/api/players/fetch/{userId}/FIX?pass=ABCBLOO1ss1009g", "", (i, s) => {
try {
var result = DResult.GenerateFromAnswer(s, userId.ToString(), "fetch player");
if (result == null) {
return;
}
var info = DPlayer.GenerateFromAnswer(result.Result as JObject);
if (info == null) {
return;
}
callback(info);
}
catch {
}
}
, _);
}
public void UpdateAfterUpdate(string s) {
var result = DResult.GenerateFromAnswer(s, UserID.ToString(), "update after update");
if (result == null) {
return;
}
var info = DPlayer.GenerateFromAnswer(result.Result as JObject);
if (info == null) {
return;
}
_.UpdatePlayer(BasePlayer.Find(UserID.ToString()), info);
}
public static DPlayer GenerateFromAnswer(JObject obj) {
DPlayer result = null;
try {
result = JsonConvert.DeserializeObject<DPlayer>(obj.ToString());
result.Murders.ForEach(p => p.LoadImage());
}
catch {
}
return result;
}
}
private class WPlayer : MonoBehaviour {
public BasePlayer Player;
public float Exp;
public int PlayTime;
public Vector3 LastPosition;
public HashSet<ulong> KillTarget = new HashSet<ulong>();
public void Awake() {
Player = GetComponent<BasePlayer>();
LastPosition = Player.transform.position;
InvokeRepeating(nameof(ScanPosition), 0f, 5f);
InvokeRepeating(nameof(ClearTargetList), 0f, 1200f);
}
public void ClearTargetList() {
KillTarget.Clear();
}
public void ScanPosition() {
if (!Player.IsConnected) {
Destroy(this);
return;
}
if (Vector3.Distance(Player.transform.position, LastPosition) < 0.5f) return;
LastPosition = Player.transform.position;
PlayTime += 5;
if (PlayTime == 60) {
PlayTime = 0;
List<string> names = new List<string> {
"bloodrust", "blood-rust", "blood rust"
}
;
if (names.Any(p => Player.displayName.ToLower().Contains(p.ToLower()))) {
AddExp(Settings.ExpForMinute * 2f, "За одну минуту игры на сервере");
}
else {
AddExp(Settings.ExpForMinute, "За одну минуту игры на сервере");
}
}
}
public bool AddExp(float amount, string mess, ulong playerId = 0) {
if (IsInvoking(nameof(SendExpUpdate))) CancelInvoke(nameof(SendExpUpdate));
if (playerId != 0) {
if (KillTarget.Contains(playerId)) {
//Player.ChatMessage("Вы его уже убивали!");
return false;
}
KillTarget.Add(playerId);
}
Exp += amount;
if (Settings.DebugErrors) Player.ChatMessage($"Add {amount}exp for {mess}");
Invoke(nameof(SendExpUpdate), 5f);
return true;
}
public void SendExpUpdate() {
try {
_.webrequest.Enqueue($"{Settings.WebURL}/api/players/addExp/{Player.userID}/{Exp}?pass=ABCBLOO1ss1009g", "", (i, s) => {
try {
float value = 0;
if (Player == null || !float.TryParse(s, out value)) {
return;
}
Exp = 0;
Base[Player].Exp = value;
UpdateExpCounter(Player, ExpAction.Minus, Base[Player].Exp);
}
catch {
}
}
, _);
}
catch {
}
}
}
private class DQuest {
[JsonProperty("id")]
public int Id;
[JsonProperty("timeStart")]
public double TimeStart;
[JsonProperty("timeEnd")]
public double TimeEnd;
[JsonProperty("items")]
public List<DItem> Items = new List<DItem>();
[JsonProperty("murder")]
public DMurder Murder = new DMurder();
public bool IsEnd() => Time() > TimeEnd / 1000;
public double TimeLeft() => IsEnd() ? 0 : TimeSpan.FromSeconds(TimeEnd / 1000 - Time()).TotalSeconds;
public string TimeLeftText() {
if (IsEnd()) {
return "КОНЕЦ";
}
string text = "<b>";
var timeSpan = TimeSpan.FromSeconds(TimeEnd / 1000 - Time());
if (timeSpan.Hours > 0) return $"<b>{timeSpan.Hours} ЧАС</b>";
if (timeSpan.Minutes > 0) return $"<b>{timeSpan.Minutes} МИН</b>";
if (timeSpan.Seconds > 0) return $"<b>{timeSpan.Seconds} СЕК</b>";
return "<b>0 СЕК</b>";
}
}
private class DMurder {
[JsonProperty("id")]
public int Id;
[JsonProperty("name")]
public string Name;
[JsonProperty("url")]
public string Url;
[JsonProperty("level")]
public int Level;
[JsonIgnore]
public string ImageID;
public void LoadImage() {
ImageID = (string) _.ImageLibrary.Call("GetImage", $"MurderID.{Id}.Avatar");
}
public static void LoadImages() {
_.webrequest.Enqueue($"{Settings.WebURL}/api/murders/fetch?pass=ABCBLOO1ss1009g", "", (i, s) => {
DResult result = DResult.GenerateFromAnswer(s, "UNKNOWN", "murders fetch");
if (result == null) {
return;
}
var info = JsonConvert.DeserializeObject<List<DMurder>>(result.Result.ToString());
if (!_.ImageLibrary) {
_.PrintError($"C#> Failed to load images [ERROR]");
return;
}
_.PrintWarning($"WEB> Loaded {info.Count} murders [OK]");
foreach (var murder in info) {
_.ImageLibrary.Call("AddImage", murder.Url, $"MurderID.{murder.Id}.Avatar");
}
}
, _);
}
}
private class DItemCache {
public int id {
get;
set;
}
public DateTime createdAt {
get;
set;
}
public DateTime updatedAt {
get;
set;
}
public int playerId {
get;
set;
}
public int itemId {
get;
set;
}
}
private class DItem {
[JsonProperty("id")]
public int Id;
[JsonProperty("shortName")]
public string ShortName;
[JsonProperty("skinId")]
public ulong SkinID;
[JsonProperty("amount")]
public int Amount;
[JsonProperty("exp")]
public float Exp;
[JsonProperty("expBuy")]
public float ExpBuy;
[JsonProperty("levelQuest")]
public int LevelQuest;
[JsonProperty("category")]
public string Category;
[JsonProperty("isPart")]
public string IsPart;
[JsonProperty("isBp")]
public bool IsBlueprint;
[JsonProperty("url")]
public string Url;
[JsonProperty("shouldBlock")]
public bool ShouldBlock;
[JsonIgnore]
public string OutID = "UNKNOWN";
public static DItem FromCache(DItemCache cache) {
var rItem = Market.FirstOrDefault(p => p.Id == cache.itemId);
if (rItem == null) {
_.PrintError($"Unknown item {cache.itemId} -> {cache.playerId} [{cache.id}]!");
return Market.FirstOrDefault();
}
return (DItem) rItem.Clone();
}
public string GetImage() {
if (ShortName.StartsWith("command: ")) {
return (string) _.ImageLibrary.Call("GetImage", "M.Custom." + Id);
}
else if (IsPart.Length < 2) {
return (string) _.ImageLibrary.Call("GetImage", ShortName);
}
else {
return (string) Parts.FirstOrDefault(p => p.Name == IsPart).GetSmallImage();
}
}
/// <summary>
/// Отображает процесс произведения процесса (что!?)
/// </summary>
private void ShowWaitingResult(BasePlayer player, bool success) {
CuiElementContainer container = new CuiElementContainer();
CuiHelper.DestroyUi(player, InitialLayer + $".HRPStore{OutID}.Wait");
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = "15 15", OffsetMax = "-15 -15"
}
, Button = {
Color = "1 1 1 0.5", Sprite = success ? "assets/icons/vote_up.png" : "assets/icons/vote_up.png"
}
, Text = {
Text = ""
}
}
, InitialLayer + $".HRPStore{OutID}", InitialLayer + $".HRPStore{OutID}.Wait");
CuiHelper.AddUi(player, container);
}
/// <summary>
/// Отображает процесс произведения процесса (что!?)
/// </summary>
private void WaitForResponseOnItem(BasePlayer player) {
CuiElementContainer container = new CuiElementContainer();
CuiHelper.DestroyUi(player, InitialLayer + $".HRPStore{OutID}.Overflow");
container.Add(new CuiElement {
Parent = InitialLayer + $".HRPStore{OutID}", Components = {
new CuiRawImageComponent {
Png = WhiteLockerImage, Color = "1 1 1 0.3"
}
, new CuiRectTransformComponent {
AnchorMin = "0 0", AnchorMax = "1 1", OffsetMax = "0 0"
}
}
}
);
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = "15 15", OffsetMax = "-15 -15"
}
, Button = {
Color = "1 1 1 0.5", Sprite = "assets/icons/refresh.png"
}
, Text = {
Text = ""
}
}
, InitialLayer + $".HRPStore{OutID}", InitialLayer + $".HRPStore{OutID}.Wait");
CuiHelper.AddUi(player, container);
}
public void Buy(BasePlayer player, DPlayer dPlayer) {
_.webrequest.Enqueue($"{Settings.WebURL}/api/players/buyItem/{dPlayer.UserID}/{Id}?pass=ABCBLOO1ss1009g", "", (i, s) => {
DResult result = DResult.GenerateFromAnswer(s, dPlayer.UserID.ToString(), "but item");
if (result == null) {
return;
}
if (result.Result is Boolean) {
dPlayer.Exp -= ExpBuy;
UpdateExpCounter(player, ExpAction.Minus, dPlayer.Exp);
dPlayer.Inventory.Add((DItem) Clone());
if (ShouldBlock) {
dPlayer.Blocked.Add((DItem) Clone());
}
_.InitializeShop(player, dPlayer);
Effect effect = new Effect("assets/prefabs/deployable/vendingmachine/effects/vending-machine-purchase-human.prefab", player, 0, new Vector3(), new Vector3());
EffectNetwork.Send(effect, player.Connection);
}
else {
//LogError($"C#> Не удалось купить {ShortName} [{Id}] игрком {dPlayer.UserID}.Причина: '{result.Result}'");
}
}
, _);
}
public void RefundItem(BasePlayer player, DPlayer dPlayer) {
WaitForResponseOnItem(player);
_.webrequest.Enqueue($"{Settings.WebURL}/api/players/removeItem/{dPlayer.UserID}/{Id}/{Exp}?pass=ABCBLOO1ss1009g", "", (i, s) => {
DResult result = DResult.GenerateFromAnswer(s, dPlayer.UserID.ToString(), "refund item");
if (result == null) {
return;
}
if (result.Result is Boolean) {
dPlayer.Exp += Exp;
ShowWaitingResult(player, (bool) result.Result);
UpdateExpCounter(player, ExpAction.Plus, dPlayer.Exp);
dPlayer.Inventory.Remove(this);
}
else {
LogError($"C#> Не удалось вернуть {ShortName} [{Id}] игрком {dPlayer.UserID}.Причина: '{result.Result}'");
}
}
, _);
}
public void ProcessItem(BasePlayer player, DPlayer dPlayer) {
WaitForResponseOnItem(player);
dPlayer.Inventory.Remove(this);
_.webrequest.Enqueue($"{Settings.WebURL}/api/players/removeItem/{dPlayer.UserID}/{Id}/false?pass=ABCBLOO1ss1009g", "", (i, s) => {
DResult result = DResult.GenerateFromAnswer(s, dPlayer.UserID.ToString(), "process item");
if (result == null) {
return;
}
if (result.Result is Boolean) {
ShowWaitingResult(player, (bool) result.Result);
Item item = null;
Effect effect = new Effect("assets/bundled/prefabs/fx/notice/stack.world.fx.prefab", player, 0, new Vector3(), new Vector3());
EffectNetwork.Send(effect, player.Connection);
if (ShortName != "") {
if (ShortName.StartsWith("command: ")) {
string cmd = ShortName.Replace("command: ", "").Replace("%STEAMID%", player.UserIDString);
_.Server.Command(cmd);
if (cmd.StartsWith("grant")) {
_.webrequest.Enqueue($"http://api2.hougan.space/blood/rcon/{cmd}/2281337ABC/all?pass=ABCBLOO1ss1009g", "", (i1, s1) => {
}
, _);
}
}
else {
if (IsBlueprint) {
item = ItemManager.CreateByItemID(-996920608, 1, 0);
item.blueprintTarget = ItemManager.FindItemDefinition(ShortName).itemid;
}
else {
item = ItemManager.CreateByName(ShortName, Amount, SkinID);
}
if (!item.MoveToContainer(player.inventory.containerMain)) item.Drop(player.transform.position, Vector3.zero);
player.SendConsoleCommand($"note.inv {item.info.itemid} {item.amount}");
}
}
}
else {
LogError($"C#> Не удалось получить {ShortName} [{Id}] игрком {dPlayer.UserID}.Причина: '{result.Result}'");
}
}
, _);
}
public object Clone() {
return new DItem {
Amount = Amount, Category = Category, Exp = Exp, Id = Id, ExpBuy = ExpBuy, IsPart = IsPart, IsBlueprint = IsBlueprint, LevelQuest = LevelQuest, ShortName = ShortName, OutID = CuiHelper.GetGuid(), SkinID = SkinID
}
;
}
}
public class LevelSettings {
[JsonProperty("Стоимость наёмника в EXP")]
public int ExpCost;
[JsonProperty("Длительность поиска (сек.)")]
public int Length;
[JsonProperty("Минимальное количество предметов")]
public int MinimalItems;
[JsonProperty("Максимальное количество предметов")]
public int MaximumItems;
}
private class Configuration {
public bool DebugErrors = true;
public string WebURL = "http://mercenaries.bloodrust.ru/";
[JsonProperty("Настройки уровней для поиска наёмников")]
public Dictionary<int, LevelSettings> TaskPrice = new Dictionary<int, LevelSettings>();
[JsonProperty("Получение EXP за добычу ресурсов")]
public Hash<string, float> ResourceExp = new Hash<string, float>();
[JsonProperty("Получение EXP за посадку ресурсов")]
public Hash<string, float> PlantExp = new Hash<string, float>();
[JsonProperty("Получение EXP за убийство (разрушения)")]
public Hash<string, float> KillExp = new Hash<string, float>();
[JsonProperty("Получение EXP за открытие ящиков")]
public Hash<string, float> LootExp = new Hash<string, float>();
[JsonProperty("Получение EXP за постройки")]
public Hash<string, float> BuildExp = new Hash<string, float>();
[JsonProperty("EXP за минуту игры на сервере")]
public float ExpForMinute = 0.5f;
public static Configuration Generate() {
return new Configuration {
DebugErrors = true, ResourceExp = new Hash<string, float> {
["sulfur-ore"]
= 0.05f, ["tree"] = 10f
}
, PlantExp = new Hash<string, float> {
}
, BuildExp = new Hash<string, float> {
["tier1"]
= 1f, ["tier2"] = 1f, ["tier3"] = 1f, ["tier4"] = 1f,
}
, KillExp = new Hash<string, float> {
["player"]
= 1f, ["tier1"] = 1f, ["tier2"] = 1f, ["tier3"] = 1f, ["tier4"] = 1f,
}
, LootExp = new Hash<string, float> {
}
, ExpForMinute = 0.5f, TaskPrice = new Dictionary<int, LevelSettings> {
[1]
= new LevelSettings {
ExpCost = 10, Length = 1000, MinimalItems = 1, MaximumItems = 5
}
, [2] = new LevelSettings {
ExpCost = 20, Length = 1, MinimalItems = 1, MaximumItems = 5
}
, [3] = new LevelSettings {
ExpCost = 30, Length = 1, MinimalItems = 1, MaximumItems = 5
}
, [4] = new LevelSettings {
ExpCost = 40, Length = 1, MinimalItems = 1, MaximumItems = 5
}
}
}
;
}
}
#endregion
#region Variables
private static bool CheckEngine = false;
private static Hash<ulong, float> CheckData = new Hash<ulong, float>();
private static bool Initialized = false;
private static Quest _;
private enum ExpAction {
None, Plus, Minus
}
[PluginReference]
private Plugin ImageLibrary;
private static string BlueprintImage;
private static string LockerImage;
private static string WhiteLockerImage;
private static string HandlerCommand = "UI_Quest_FuryController";
private static HashSet<ulong> Joined = new HashSet<ulong>();
private static HashSet<DPart> Parts = new HashSet<DPart>();
private static HashSet<DItem> Market = new HashSet<DItem>();
private static Configuration Settings;
private static Hash<BasePlayer, DPlayer> Base = new Hash<BasePlayer, DPlayer>();
private static Hash<BasePlayer, WPlayer> Workers = new Hash<BasePlayer, WPlayer>();
private static Hash<BaseEntity, ulong> Tankers = new Hash<BaseEntity, ulong>();
private static Hash<ulong, double> SyncCooldowns = new Hash<ulong, double>();
private static Dictionary<string, string> Sections = new Dictionary<string, string> {
["FURY"]
= "НАЁМНИКИ", ["STORE"] = "ЯЩИК НАЁМНИКОВ", ["SHOP"] = "РЫНОК", ["PARTS"] = "СБОР ФРАГМЕНТОВ",
}
;
#endregion
#region Hooks
protected override void LoadConfig() {
base.LoadConfig();
try {
Settings = Config.ReadObject<Configuration>();
}
catch {
PrintWarning($"Error reading config, creating one new config!");
LoadDefaultConfig();
}
SaveConfig();
}
protected override void LoadDefaultConfig() => Settings = Configuration.Generate();
protected override void SaveConfig() => Config.WriteObject(Settings);
private void FetchBaseSync(Action callback) {
DPlayer.GetFromPlayer("TEST_BORDER", 2281337, dPlayer => {
PrintWarning("WEB> Testing account found [OK]");
_.timer.Once(1, DPart.LoadParts);
_.timer.Once(2, DMurder.LoadImages);
_.timer.Once(3, FetchMurders);
_.timer.Once(4, LoadImages);
_.timer.Once(6, FetchMarket);
_.timer.Once(30, callback);
}
);
}
private IEnumerator LoadGlobalPlayers() {
foreach (var check in BasePlayer.activePlayerList) {
int index = BasePlayer.activePlayerList.ToList().IndexOf(check);
if (index % 5 == 0) PrintWarning($"WEB> Loaded {(float) index / BasePlayer.activePlayerList.Count}% loaded [OK]");
OnPlayerConnected(check);
yield return new WaitForSeconds(0.25f);
}
Initialized = true;
yield return 0;
}
private void SaveData() {
Interface.Oxide.DataFileSystem.WriteObject($"{Name}/CheckEngine", CheckData);
}
private void OnServerInitialized() {
_ = this;
if (Interface.Oxide.DataFileSystem.ExistsDatafile($"{Name}/CheckEngine")) CheckData = Interface.Oxide.DataFileSystem.ReadObject<Hash<ulong, float>>($"{Name}/CheckEngine");
timer.Every(60, SaveData);
if (CheckEngine) {
PrintError("Аварийный режим, вам на разборочку");
return;
}
timer.Once(1, () => {
FetchBaseSync(() => {
timer.Every(5, () => {
foreach (var check in Base) {
if (check.Value.Quest != null && check.Value.Quest.TimeEnd / 1000 < Time()) {
if (check.Value.Quest.Murder.Level != 4) {
Interface.Oxide.CallHook("AddNotification", check.Key, $"{check.Value.Quest.Murder.Name.ToUpper()} ВЕРНУЛСЯ", $"Нажмите чтобы посмотреть найденные предметы", "1 1 1 0.5", 10, "", "", "chat.say /fury");
}
else {
Interface.Oxide.CallHook("AddNotification", check.Key, $"{check.Value.Quest.Murder.Name.ToUpper()} ОТКРЫТ", $"Нажмите чтобы посмотреть полученные предметы", "1 1 1 0.5", 10, "", "", "chat.say /fury");
}
}
}
}
);
timer.Every(5, () => {
if (Market.Count == 0) {
FetchBaseSync(null);
}
}
);
PrintError("Загрузка успешно окончена!");
}
);
}
);
}
private void OnPlayerConnected(BasePlayer player) {
FetchPlayer(player);
}
private void OnPlayerDisconnected(BasePlayer player, string reason) => DestroyPlayer(player);
private void Unload() => BasePlayer.activePlayerList.ToList().ToList().ToList().ForEach(DestroyPlayer);
private void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info) {
if ((entity.PrefabName.Contains("patrol") || entity.PrefabName.Contains("bradley") || entity.PrefabName.Contains("ch47")) && info?.InitiatorPlayer != null && Base.ContainsKey(info.InitiatorPlayer)) {
entity._name = info.InitiatorPlayer.UserIDString ?? "UNKNOWN";
}
}
private void OnEntityDeath(BaseCombatEntity entity, HitInfo info) {
if (entity == null || info == null) return;
var player = info.InitiatorPlayer;
if (player == null || !Base.ContainsKey(player)) {
if (entity._name?.Length == 17) {
player = BasePlayer.Find(entity._name);
}
if (player == null || !Base.ContainsKey(player)) return;
}
string shortName = entity.ShortPrefabName;
if (entity is BuildingBlock) shortName = "tier" + (int) ((entity as BuildingBlock).grade);
var amount = 0f;
if (!Settings.KillExp.TryGetValue(shortName, out amount)) {
if (Settings.DebugErrors) {
Server.Command($"echo {shortName}");
player.ChatMessage("Неизвестный тип [ED]: " + shortName);
}
return;
}
if ((entity is BasePlayer && ((BasePlayer) entity).userID == player.userID)) return;
player.SendConsoleCommand($"note.inv 605467368 1 \"<color=#d4d8ca>+{amount}</color><color=#b9bdaf>EXP</color>\"");
AddEXP(player, amount, "Убийство " + shortName, entity.GetComponent<BasePlayer>() != null ? ((BasePlayer) entity).userID : 0);
}
private void OnCardSwipe(CardReader cardReader, Keycard card, BasePlayer player) {
if (player == null || card.accessLevel != cardReader.accessLevel) return;
var amount = 0f;
if (!Settings.BuildExp.TryGetValue($"card{card.accessLevel}", out amount)) {
//Server.Command($"echo card{card.accessLevel}");
if (Settings.DebugErrors) {
player.ChatMessage("Неизвестный тип [EB]: " + $"echo card{card.accessLevel}");
}
return;
}
player.SendConsoleCommand($"note.inv 605467368 1 \"<color=#d4d8ca>+{amount}</color><color=#b9bdaf>EXP</color>\"");
AddEXP(player, amount, "Свайп " + $"echo card{card.accessLevel}");
}
private void OnEntityBuilt(Planner plan, GameObject go) {
var player = plan.GetOwnerPlayer();
var ent = go.ToBaseEntity();
if (player == null || ent == null) return;
string shortName = go.ToBaseEntity().ShortPrefabName;
var amount = 0f;
if (!Settings.BuildExp.TryGetValue(shortName, out amount)) {
if (Settings.DebugErrors) {
Server.Command($"echo {shortName}");
player.ChatMessage("Неизвестный тип [EB]: " + shortName);
}
return;
}
var planItem = plan?.GetItem();
if (planItem != null) {
if (planItem.skin != 0) {
return;
}
}
player.SendConsoleCommand($"note.inv 605467368 1 \"<color=#d4d8ca>+{amount}</color><color=#b9bdaf>EXP</color>\"");
AddEXP(player, amount, "Постройка " + shortName);
}
private void OnLootEntity(BasePlayer player, BaseEntity entity) {
if (entity.name == "LOOTED") return;
entity.name = "LOOTED";
string shortName = entity.ShortPrefabName;
var amount = 0f;
if (!Settings.LootExp.TryGetValue(shortName, out amount)) {
if (Settings.DebugErrors) {
Server.Command($"echo {shortName}");
player.ChatMessage("Неизвестный тип [EB]: " + shortName);
}
return;
}
player.SendConsoleCommand($"note.inv 605467368 1 \"<color=#d4d8ca>+{amount}</color><color=#b9bdaf>EXP</color>\"");
AddEXP(player, amount, "Постройка " + shortName);
}
private void CanAffordUpgrade(BasePlayer player, BuildingBlock block, BuildingGrade.Enum grade) {
if (player == null) return;
string shortName = "tier" + (int) grade;
var amount = 0f;
if (!Settings.BuildExp.TryGetValue(shortName, out amount)) {
if (Settings.DebugErrors) {
Server.Command($"echo {shortName}");
player.ChatMessage("Неизвестный тип [AU]: " + shortName);
}
return;
}
player.SendConsoleCommand($"note.inv 605467368 1 \"<color=#d4d8ca>+{amount}</color><color=#b9bdaf>EXP</color>\"");
AddEXP(player, amount, "Улучшение " + shortName);
}
private void OnCollectiblePickup(Item item, BasePlayer player, CollectibleEntity entity) {
string shortName = entity.GetComponent<BaseEntity>().ShortPrefabName;
var amount = 0f;
if (!Settings.ResourceExp.TryGetValue(shortName, out amount)) {
if (Settings.DebugErrors) {
Server.Command($"echo {shortName}");
player.ChatMessage("Неизвестный тип [CP]: " + shortName);
}
return;
}
if (AddEXP(player, amount, "[CP] Добыча " + shortName, entity.net.ID)) {
item.name = item.info.displayName.english + $" <size=10><color=#d4d8ca>+{amount}</color><color=#b9bdaf>EXP</color></size>";
NextTick(() => {
item.name = "";
}
);
}
}
private void OnDispenserBonus(ResourceDispenser dispenser, BasePlayer player, Item item) {
string shortName = dispenser.GetComponent<BaseEntity>().ShortPrefabName;
if (item.info.shortname == "wood") shortName = "tree";
if (item.info.shortname == "sulfur.ore") shortName = "sulfur-ore";
if (item.info.shortname == "metal.ore") shortName = "metal-ore";
if (item.info.shortname == "stones") shortName = "stones";
var amount = 0f;
if (!Settings.ResourceExp.TryGetValue(shortName, out amount)) {
if (Settings.DebugErrors) {
Server.Command($"echo {shortName}");
player.ChatMessage("Неизвестный тип [DB]: " + shortName);
}
return;
}
if (AddEXP(player, amount, "[DP] Добыча " + shortName, dispenser.GetComponent<BaseEntity>().net.ID)) {
player.SendConsoleCommand($"note.inv 605467368 1 \"<color=#d4d8ca>+{amount}</color><color=#b9bdaf>EXP</color>\"");
}
return;
}
private void OnGrowableGather(GrowableEntity plant, Item item, BasePlayer player) {
string shortName = plant.ShortPrefabName;
var amount = 0f;
if (!Settings.ResourceExp.TryGetValue(shortName, out amount)) {
if (Settings.DebugErrors) {
Server.Command($"echo {shortName}");
player.ChatMessage("Неизвестный тип [CG]: " + shortName);
}
return;
}
item.name = item.info.displayName.english + $" <size=10><color=#d4d8ca>+{amount}</color><color=#b9bdaf>EXP</color></size>";
NextTick(() => {
item.name = "";
}
);
AddEXP(player, amount, "[CG] Добыча " + shortName);
}
#endregion
#region Debug
[ConsoleCommand("exp_merge")]
private void CmdConsole(ConsoleSystem.Arg args) {
if (args.Player() != null) return;
foreach (var check in CheckData) {
webrequest.Enqueue($"{Settings.WebURL}/api/players/addExp/{check.Key}/{check.Value}?pass=ABCBLOO1ss1009g", "", (i, s) => {
}
, _);
}
PrintError($"Merged {CheckData.Count} pl., total: {CheckData.Sum(p => p.Value).ToString("F2")} EXP");
CheckData.Clear();
}
[ChatCommand("update.items")]
private void CmdChat(BasePlayer player) {
if (!player.IsAdmin) return;
ServerMgr.Instance.StartCoroutine(LoadingQueue());
}
private IEnumerator LoadingQueue() {
var list = ItemManager.itemList.Where(p => p.Blueprint != null && p.Blueprint.isResearchable && p.Blueprint.workbenchLevelRequired > 0 && p.Blueprint.userCraftable);
foreach (var check in list) {
PrintError($"Loaded ok: {check.shortname}");
webrequest.Enqueue($"{Settings.WebURL}api/items/add/{check.shortname}/0/{check.stackable}/{check.stackable}/{check.Blueprint.workbenchLevelRequired}/caban/{check.category.ToString()}?pass=ABCBLOO1ss1009g", "", (i, s) => {
}
, this);
yield return new WaitForSeconds(0.2f);
}
}
#region EXP Money
[ChatCommand("exp.none")]
private void CmdChatExpNone(BasePlayer player) {
Item item = ItemManager.CreateByPartialName("scraptransportheli.repair");
item.MoveToContainer(player.inventory.containerBelt);
UpdateExpCounter(player, ExpAction.None, 1488);
}
[ChatCommand("exp.plus")]
private void CmdChatExpPlus(BasePlayer player) => UpdateExpCounter(player, ExpAction.Plus, 1488);
[ChatCommand("exp.minus")]
private void CmdChatExpMinus(BasePlayer player) => UpdateExpCounter(player, ExpAction.Minus, 1488);
#endregion
#endregion
#region Methods
private bool AddEXP(BasePlayer player, float amount, string mess = "", ulong targetId = 0) {
//player.SendConsoleCommand($"note.inv 605467368 1 \"<color=#83c786>+{amount}EXP</color>\"");
if (CheckEngine) {
if (!CheckData.ContainsKey(player.userID)) CheckData.Add(player.userID, 0f);
CheckData[player.userID] += amount;
return false;
}
var obj = player.GetComponent<WPlayer>();
if (obj == null) {
return false;
}
return obj.AddExp(amount, mess, targetId);
}
private float GetExp(BasePlayer player) {
if (CheckEngine) {
if (!CheckData.ContainsKey(player.userID)) return 0f;
var info = CheckData[player.userID];
float left = info - Mathf.FloorToInt(info);
return left < 0 ? 0f : left;
}
if (!Base.ContainsKey(player)) return 0f;
var infos = Base[player];
float lefts = infos.Exp - Mathf.FloorToInt(infos.Exp);
return lefts < 0 ? 0f : lefts;
}
private float GetCurrentExp(BasePlayer player) {
if (CheckEngine) {
if (!CheckData.ContainsKey(player.userID)) return 0f;
var info = CheckData[player.userID];
float left = info - Mathf.FloorToInt(info);
return left < 0 ? 0f : left;
}
if (!Base.ContainsKey(player)) return 0f;
var infos = Base[player];
return infos.Exp;
}
/// <summary>
/// Сохраняет логи и выводит ошибку если включён DEBUG
/// </summary>
private static void LogError(string text) {
//_.PrintError(text);
if (Settings.DebugErrors) _.LogToFile(_.Name, text, _);
}
/// <summary>
/// Обновляет текущий счётчик EXP по середине экрана
/// </summary>
/// <param name="action">Тип, если стоит plus/minus - происходит анимация изменения</param>
private static void UpdateExpCounter(BasePlayer player, ExpAction action, float newValue) {
CuiElementContainer container = new CuiElementContainer();
CuiHelper.DestroyUi(player, InitialLayer + ".EXP");
container.Add(new CuiLabel {
RectTransform = {
AnchorMin = "0 1", AnchorMax = "1 1", OffsetMin = $"20 -100", OffsetMax = $"-0 -15"
}
, Text = {
Text = $"<b>{newValue}</b><color=#865f5a>EXP</color>", Align = TextAnchor.UpperLeft, Font = "robotocondensed-regular.ttf", FontSize = 32, Color = "0.93 0.89 0.85 1"
}
}
, InitialLayer + ".C", InitialLayer + ".EXP");
if (action != ExpAction.None) {
CuiHelper.DestroyUi(player, InitialLayer + ".EXP.Animation");
container.Add(new CuiLabel {
FadeOut = 2f, RectTransform = {
AnchorMin = "0 1", AnchorMax = "1 1", OffsetMin = $"5 -100", OffsetMax = $"-0 -20"
}
, Text = {
Text = action == ExpAction.Plus ? "⇡" : "⇣", Align = TextAnchor.UpperLeft, Font = "robotocondensed-bold.ttf", FontSize = 28, Color = action == ExpAction.Plus ? "0.462 0.79 0.27" : "0.95 0.278 0.231"
}
}
, InitialLayer + ".C", InitialLayer + ".EXP.Animation");
}
CuiHelper.AddUi(player, container);
if (action != ExpAction.None) CuiHelper.DestroyUi(player, InitialLayer + ".EXP.Animation");
}
private void LoadImages() {
ImageLibrary.Call("AddImage", "https://i.imgur.com/YkC5Np4.png", "Custom_Locker_Image_Murder");
ImageLibrary.Call("AddImage", "https://i.imgur.com/BQx3bap.png", "Custom_WhiteLocker_Image_Murder");
ImageLibrary.Call("AddImage", "http://static.moscow.ovh/images/games/rust/icons/blueprintbase.png", "Custom_Blueprint");
FetchImages();
}
private void FetchImages() {
if (!((bool) ImageLibrary.Call("HasImage", "Custom_Locker_Image_Murder"))) {
PrintError("C#> Images loaded failed [ERR]");
timer.Once(1f, FetchImages);
return;
}
if (!((bool) ImageLibrary.Call("HasImage", "Custom_Blueprint"))) {
PrintError("C#> Images loaded failed [ERR]");
timer.Once(1f, FetchImages);
return;
}
BlueprintImage = (string) ImageLibrary.Call("GetImage", "Custom_Blueprint");
LockerImage = (string) ImageLibrary.Call("GetImage", "Custom_Locker_Image_Murder");
// ... [Code preview truncated due to length. Full source in attached file] ...