C#:
using Newtonsoft.Json;
using UnityEngine;
using Oxide.Game.Rust.Cui;
using Oxide.Core;
using System.Text;
using ConVar;
using Object = System.Object;
using Oxide.Core.Plugins;
using Rust.Ai.Gen2;
using System.Linq;
using System.Collections;
using Pool = Facepunch.Pool;
using System;
using UnityEngine.Networking;
using Oxide.Core.Database;
using System.Collections.Generic;
namespace Oxide.Plugins {
[Info("IQEconomic", "Mercury", "2.20.23")]
[Description("Экономика на ваш сервер")]
public class IQEconomic : RustPlugin {
void OnItemCraftCancelled(ItemCraftTask task, ItemCrafter crafter) {
BasePlayer player = crafter.owner;
if (!player) return;
player.ResetInputIdleTime();
}
private Boolean isUsedStores = false;
private void TransferToPlayer(BasePlayer player, String nameOrID, String amountString) {
if (String.IsNullOrWhiteSpace(nameOrID)) {
SendChat(GetLang("CHAT_ALERT_TRANSFER_NO_NAME", player.UserIDString), player);
return;
}
if (String.IsNullOrWhiteSpace(amountString) || !Int32.TryParse(amountString, out Int32 amount)) {
SendChat(GetLang("CHAT_ALERT_TRANSFER_INCORRECT_AMOUNT", player.UserIDString), player);
return;
}
(BasePlayer, String) targetPlayer = FindPlayerNameOrID(player, nameOrID);
if (!targetPlayer.Item1) {
if (targetPlayer.Item2 != null && !String.IsNullOrWhiteSpace(targetPlayer.Item2)) {
SendChat(targetPlayer.Item2, player);
return;
}
SendChat(GetLang("CHAT_ALERT_TRANSFER_PLAYER_OFFLINE", player.UserIDString), player);
return;
}
if (!IsValidTransfer(player, targetPlayer.Item1, amount)) return;
ExecuteTransfer(player, targetPlayer.Item1, amount);
}
private void RemoveBalance(String userID, Int32 amount, TypeLog typeLog) {
if (config.generalSetting.typeCoins == TypeCoins.Physics) {
PrintWarning(LanguageEn ? $"You cannot take currency from player {userID} while they are offline" : $"Нельзя забрать валюту у игрока {userID} пока он оффлайн");
return;
}
if (isUsedSQL) GetAndFunctionalBalancePlayerSQL(userID, false, amount);
else {
PlayerInfo pInfo = PlayerInfo.GetOffline(userID);
if (pInfo == null) return;
if (!DoesHaveEnoughBalance(pInfo.Balance)) {
pInfo.Balance = 0;
LogAction(userID, pInfo.Balance, typeLog, false);
}
else {
pInfo.Balance -= amount;
LogAction(userID, amount, typeLog, false);
}
PlayerInfo.SaveOffline(userID, pInfo);
Interface.Oxide.CallHook("OnRemovedBalance", UInt64.Parse(userID), amount, null, pInfo.Balance);
Interface.Oxide.CallHook("OnUpdatedBalance", UInt64.Parse(userID), null, pInfo.Balance);
}
}
private Item OnItemSplited(Item item, Int32 amount) //Other plugin hook
{
switch (item.skin) {
case 47328465 : case 57854932 : case 23156768 : case 31213265 : return null;
}
Item x = config.generalSetting.physicsItem.CreatePhysicMoney(amount);
item.amount -= amount;
item.MarkDirty();
return x;
}
private void OnPlayerDeath(BasePlayer target, HitInfo hitInfo) {
if(!target) return;
Boolean isRealPlayerTarget = IsRealPlayer(target);
Configuration.EarningCoins.PresetEarning earningPlayer = config.earningCoins.killedPlayer;
Configuration.EarningCoins.PresetEarning earningNpc = config.earningCoins.killedNpcs;
if (isRealPlayerTarget) {
if (isUsedUI) InterfaceBuilder.DestroyPlayerUI(target);
if (config.generalSetting.physicsItem.useSaveDeath && config.generalSetting.typeCoins == TypeCoins.Physics) {
Int32 balance = GetBalancePlayer(target);
RemoveBalance(target, balance, TypeLog.SaveAfterDeath);
saveAfterDeath[target] = balance;
}
}
if (!earningPlayer.useEarning && !earningNpc.useEarning) return;
if (hitInfo == null) return;
BasePlayer attacker = hitInfo.InitiatorPlayer;
if (!attacker) return;
if (!IsRealPlayer(attacker)) return;
if (attacker == target) return;
if (isRealPlayerTarget) {
if (IsBlockedEarningKillPlayer(attacker, target)) return;
if (!IsOnlyTakeEarning(attacker, earningPlayer)) return;
AddBalance(attacker, earningPlayer.countMoney, TypeLog.Action, earningPlayer.useChatAlert ? "CHAT_ALERT_EARNING_KILLED_PLAYER" : default, earningNpc.useNoteAlert);
return;
}
if (!IsOnlyTakeEarning(attacker, earningNpc)) return;
AddBalance(attacker, earningNpc.countMoney, TypeLog.Action, earningNpc.useChatAlert ? "CHAT_ALERT_EARNING_KILLED_NPC" : default, earningNpc.useNoteAlert);
}
private void Unload() {
if (_ == null) return;
if (coroutineMigrate != null) {
ServerMgr.Instance.StopCoroutine(coroutineMigrate);
coroutineMigrate = null;
}
else {
foreach (BasePlayer player in BasePlayer.activePlayerList) DisconnectedPlayer(player);
}
if (!String.IsNullOrWhiteSpace(config.commandExchanger) && config.exchangerSetting.useExchanger) WriteData();
if (saveAfterDeath != null) {
saveAfterDeath.Clear();
saveAfterDeath = null;
}
if (heliKilleds != null) {
heliKilleds.Clear();
heliKilleds = null;
}
if (timerTrackerTimes is {
Destroyed : false
}
) {
timerTrackerTimes.Destroy();
timerTrackerTimes = null;
}
if (timerWaitSQL is {
Destroyed : false
}
) {
timerWaitSQL.Destroy();
timerWaitSQL = null;
}
if (timerUpdateCourse is {
Destroyed : false
}
) {
timerUpdateCourse.Destroy();
timerUpdateCourse = null;
}
if (sqlConnection != null && sqlLibrary != null) {
sqlLibrary.CloseDb(sqlConnection);
sqlConnection = null;
}
InterfaceBuilder.DestroyAll();
if (_imageUI != null) {
_imageUI.UnloadImages();
_imageUI = null;
}
if (cachedUI != null) {
cachedUI.Clear();
cachedUI = null;
}
if (exchangerDataPlayer != null) {
exchangerDataPlayer.Clear();
exchangerDataPlayer = null;
}
lootedEntity.Clear();
_ = null;
}
private (BasePlayer, String) FindPlayerNameOrID(BasePlayer finder, String nameOrID) {
List<BasePlayer> players = Pool.Get<List<BasePlayer>>();
players.AddRange(BasePlayer.activePlayerList);
if (nameOrID.IsSteamId() && ulong.TryParse(nameOrID, out UInt64 userID)) {
BasePlayer player = BasePlayer.FindByID(userID);
Pool.FreeUnmanaged(ref players);
return (player, null);
}
List<BasePlayer> matchingPlayers = Pool.Get<List<BasePlayer>>();
try {
matchingPlayers.AddRange(players.Where(player => player.displayName != null && player.displayName.IndexOf(nameOrID, StringComparison.OrdinalIgnoreCase) >= 0));
switch (matchingPlayers.Count) {
case 1 : {
BasePlayer foundPlayer = matchingPlayers[0];
return (foundPlayer, null);
}
case > 1 : {
String nicknameList = String.Join(", ", matchingPlayers.Take(3).Select(p => p.displayName));
return (null, GetLang("CHAT_ALERT_TRANSFER_MATCHES_PLAYERS", finder.UserIDString, nameOrID, nicknameList));
}
default : return (null, null);
}
}
finally {
Pool.FreeUnmanaged(ref players);
Pool.FreeUnmanaged(ref matchingPlayers);
}
}
private void UpdateExchangedUI(BasePlayer player, Int32 balancePlayer, Int32 limitExchanged) {
if (!exchangerDataPlayer.ContainsKey(player)) return;
DrawUI_UpdateExchangeBalance_Menu(player, balancePlayer);
DrawUI_UpdateExchangeOne_Menu(player, balancePlayer, limitExchanged, exchangerDataPlayer[player]);
DrawUI_UpdateExchangeFull_Menu(player, balancePlayer, limitExchanged);
if (limitExchanged >= 0) DrawUI_UpdateExchangeLimite_Menu(player, limitExchanged);
}
private abstract class DataManager<T> where T : DataManager<T>, new() {
private const String baseFolder = "IQSystem/IQEconomic/";
public static Dictionary<String, T> _players = new();
protected static void ImportPlayer(String userId, T data) => _players[userId] = data;
protected static void SavePlayer(String userId) {
if (!_players.TryGetValue(userId, out T data)) return;
Interface.Oxide.DataFileSystem.WriteObject(baseFolder + userId, data);
}
protected static void SaveOfflinePlayer(String userId, T data) => Interface.Oxide.DataFileSystem.WriteObject(baseFolder + userId, data);
protected static void RemovePlayer(String userId) {
if (!_players.ContainsKey(userId)) return;
_players.Remove(userId);
}
protected static void DeletePlayer(String userId) {
RemovePlayer(userId);
Interface.Oxide.DataFileSystem.DeleteDataFile(baseFolder + userId);
}
protected static T GetPlayer(String userId) => _players.GetValueOrDefault(userId);
protected static T GetOfflinePlayer(String userId) {
T data = null;
try {
data = Interface.Oxide.DataFileSystem.ReadObject<T>(baseFolder + userId);
}
catch (Exception e) {
Interface.Oxide.LogError(e.ToString());
}
return data;
}
protected static T LoadPlayer(String userId) {
T data = null;
try {
data = Interface.Oxide.DataFileSystem.ReadObject<T>(baseFolder + userId);
}
catch (Exception e) {
Interface.Oxide.LogError(e.ToString());
}
return _players[userId] = data;
}
protected static String[] GetFilesPlayers() {
try {
Int32 json = ".json".Length;
String[] paths = Interface.Oxide.DataFileSystem.GetFiles(baseFolder, "*.json");
for (Int32 i = 0; i < paths.Length; i++) {
String path = paths[i];
Int32 separatorIndex = path.LastIndexOf("/", StringComparison.Ordinal);
paths[i] = path.Substring(separatorIndex + 1, path.Length - separatorIndex - 1 - json);
}
return paths;
}
catch {
return Array.Empty<String>();
}
}
}
void API_SET_BALANCE(BasePlayer player, Int32 balance, ItemContainer itemContainer = null) => AddBalance(player, balance, TypeLog.API);
private void SendChat(String Message, BasePlayer player, Chat.ChatChannel channel = Chat.ChatChannel.Global) {
Configuration.OtherPlugins.IQChatSetting chatContoller = config.otherPlugins.settingIQChat;
if (IQChat) {
if (chatContoller.useUiAlert) IQChat.Call("API_ALERT_PLAYER_UI", player, Message);
else IQChat.Call("API_ALERT_PLAYER", player, Message, chatContoller.customPrefix, chatContoller.customAvatar);
}
else player.SendConsoleCommand("chat.add", channel, 0, Message);
}
private Boolean isUsedSQL = false;
private void OnEntityEnter(TriggerWorkbench trigger, BasePlayer player) {
if (!player || player.IsNpc) return;
InterfaceBuilder.DestroyPlayerUI(player);
}
private void OnNewSave(String filename) => CleanerDataFiles();
private void OnServerInitialized() {
RegisteredPermission();
if (isUsedSQL) SQL_OpenConnection();
if (config.earningCoins.timeTracked.timeTrackerPreset.useEarning) timerTrackerTimes = timer.Every(timeTracker, TrackedPlayers);
if (config.generalSetting.interfaceSetting.useUI) {
_imageUI = new ImageUI();
_imageUI.DownloadImage();
}
else {
if (!_.isUsedSQL) foreach (BasePlayer player in BasePlayer.activePlayerList) OnPlayerConnected(player);
}
cmd.AddChatCommand(config.commandBalance, this, nameof(ChatCommandBalance));
cmd.AddConsoleCommand(config.commandBalance, this, nameof(ConsoleCommandBalance));
if (isUsedExchanger) {
orderedListExchanged = config.exchangerSetting.GetOrderedList();
UpdateExchangerCourse();
timerUpdateCourse = timer.Every(timeUpdateCourse, UpdateExchangerCourse);
cmd.AddChatCommand(config.commandExchanger, this, nameof(ChatCommandExchanger));
cmd.AddConsoleCommand(config.commandExchanger, this, nameof(ConsoleCommandExchanger));
}
else if (config.exchangerSetting.useTransferP2P) {
cmd.AddChatCommand(config.commandExchanger, this, nameof(ChatCommandExchanger));
cmd.AddConsoleCommand(config.commandExchanger, this, nameof(ConsoleCommandExchanger));
}
}
void API_SET_BALANCE(String userID, Int32 balance, ItemContainer itemContainer = null) {
if (!UInt64.TryParse(userID, out UInt64 id)) return;
BasePlayer player = BasePlayer.FindByID(id);
if(!player) AddBalance(userID, balance, TypeLog.API);
else AddBalance(player, balance, TypeLog.API);
}
private const String actionLogRemoved = (LanguageEn ? "written off" : "списано");
private Boolean IsTakeEarning(BasePlayer player, Configuration.EarningCoins.PresetEarning earning) => IsRealPlayer(player) && earning.IsEarning(player);
private Item OnItemSplit(Item item, Int32 amount) {
if (item.skin != config.generalSetting.physicsItem.skinID) return null;
Item x = config.generalSetting.physicsItem.CreatePhysicMoney(amount);
item.amount -= amount;
item.MarkDirty();
return x;
}
// TODO: Множитель получения валюты по разрешению [Под вопросом]
/// <summary>
/// - Изменана конфигурация по настройке выпадаемой валюты с ящиков
/// - Добавлена возможность начисление валюты за лутание ящиков для типа - Виртуальная
/// - Добавлена возможность включить отображенеи получения валюты в уведомлении Rust'a над метаболизмом
/// - Добавлена поддержка новых животных Gen2
/// - Добавлена поддержка новых NPC Gen2
/// - Корректировка в ответе API DoesHaveEnoughBalance при снятии нулевого баланса
/// - Исправлено, когда награда за вертолет могла не начислиться
/// </summary>
[PluginReference]
Plugin IQChat, Friends, Clans, Battles, Duel, RustStore, GameStoresRUST, Duelist, ArenaTournament, XFarmRoom;
private Configuration.ExchangerSetting.CourseController actualyCourse = null;
private const String arrowLogRemoved = "=======>";
private const String actionLogReceived = (LanguageEn ? "received" : "получил");
private const String transferPrivilage = "iqeconomic.transferuse";
private Int32 GetPlayerPhysicMoney(BasePlayer player) {
Configuration.GeneralSetting.PhysicsItem physicConfig = config.generalSetting.physicsItem;
Int32 balance = 0;
List<Item> allItems = GetAllItems(player);
foreach (Item itemInInventory in allItems) {
if (physicConfig.IsPhysicMoney(itemInInventory)) balance += itemInInventory.amount;
}
Pool.FreeUnmanaged(ref allItems);
return balance;
}
protected override void LoadConfig() {
base.LoadConfig();
try {
config = Config.ReadObject<Configuration>();
if (config == null) LoadDefaultConfig();
if (config.earningCoins.droppedItem == null) {
config.earningCoins.droppedItem = new Configuration.EarningCoins.DroppedItem() {
isUseDropped = false, dropItemPresets = new Dictionary<String, Configuration.EarningCoins.DroppedItem.DropSetting>() {
["heli_crate"]
= new Configuration.EarningCoins.DroppedItem.DropSetting() {
rare = 100, amountMin = 5, amountMax = 10
}
, ["bradley_crate"] = new Configuration.EarningCoins.DroppedItem.DropSetting() {
rare = 80, amountMin = 10, amountMax = 15
}
, ["crate_elite"] = new Configuration.EarningCoins.DroppedItem.DropSetting() {
rare = 70, amountMin = 2, amountMax = 3
}
, ["crate_normal"] = new Configuration.EarningCoins.DroppedItem.DropSetting() {
rare = 50, amountMin = 1, amountMax = 2
}
, ["crate_normal_2"] = new Configuration.EarningCoins.DroppedItem.DropSetting() {
rare = 50, amountMin = 1, amountMax = 2
}
, ["crate_basic"] = new Configuration.EarningCoins.DroppedItem.DropSetting() {
rare = 20, amountMin = 1, amountMax = 1
}
, ["crate_tools"] = new Configuration.EarningCoins.DroppedItem.DropSetting() {
rare = 20, amountMin = 1, amountMax = 1
}
,
}
}
;
}
if (config.earningCoins.droppedItem.dropItemPresets == null || config.earningCoins.droppedItem.dropItemPresets.Count == 0) {
config.earningCoins.droppedItem = new Configuration.EarningCoins.DroppedItem() {
isUseDropped = false, dropItemPresets = new Dictionary<String, Configuration.EarningCoins.DroppedItem.DropSetting>() {
["heli_crate"]
= new Configuration.EarningCoins.DroppedItem.DropSetting() {
rare = 100, amountMin = 5, amountMax = 10
}
, ["bradley_crate"] = new Configuration.EarningCoins.DroppedItem.DropSetting() {
rare = 80, amountMin = 10, amountMax = 15
}
, ["crate_elite"] = new Configuration.EarningCoins.DroppedItem.DropSetting() {
rare = 70, amountMin = 2, amountMax = 3
}
, ["crate_normal"] = new Configuration.EarningCoins.DroppedItem.DropSetting() {
rare = 50, amountMin = 1, amountMax = 2
}
, ["crate_normal_2"] = new Configuration.EarningCoins.DroppedItem.DropSetting() {
rare = 50, amountMin = 1, amountMax = 2
}
, ["crate_basic"] = new Configuration.EarningCoins.DroppedItem.DropSetting() {
rare = 20, amountMin = 1, amountMax = 1
}
, ["crate_tools"] = new Configuration.EarningCoins.DroppedItem.DropSetting() {
rare = 20, amountMin = 1, amountMax = 1
}
,
}
}
;
}
if (config.earningCoins.killedBarrels == null) {
config.earningCoins.killedBarrels = new Configuration.EarningCoins.PresetEarning() {
useEarning = false, permissionEarning = String.Empty, rare = 20, countMoney = 3
}
;
}
if (config.generalSetting.interfaceSetting.colorsUI == null) {
config.generalSetting.interfaceSetting.colorsUI = new Configuration.GeneralSetting.InterfaceSetting.ColorsSetting() {
colorText = "0.969 0.922 0.882 1", colorPanel = "0.969 0.922 0.882 0.03137255"
}
;
}
if (config.generalSetting.interfaceSetting.positionUI == null) {
config.generalSetting.interfaceSetting.positionUI = new Configuration.GeneralSetting.InterfaceSetting.PositionsSetting() {
balanceIconHided = new Configuration.GeneralSetting.InterfaceSetting.PositionsSetting.PositionPreset() {
anchorMin = "1 0", anchorMax = "1 0", offsetMin = "-235.733 15.867", offsetMax = "-209.733 41.867"
}
, balancePanel = new Configuration.GeneralSetting.InterfaceSetting.PositionsSetting.PositionPreset {
anchorMin = "1 0", anchorMax = "1 0", offsetMin = "-340.067 15.867", offsetMax = "-238.067 41.867"
}
, firstButton = new Configuration.GeneralSetting.InterfaceSetting.PositionsSetting.PositionPreset {
anchorMin = "1 0", anchorMax = "1 0", offsetMin = "-235.733765 43.667567", offsetMax = "-209.73345 69.66776"
}
, twoButton = new Configuration.GeneralSetting.InterfaceSetting.PositionsSetting.PositionPreset {
anchorMin = "1 0", anchorMax = "1 0", offsetMin = "-235.73356 71.84754", offsetMax = "-209.73365 97.84776"
}
}
;
}
}
catch {
PrintWarning(LanguageEn ? "Error #49" + $"reading the configuration 'oxide/config/{Name}', creating a new configuration! #33" : "Ошибка #49" + $"чтения конфигурации 'oxide/config/{Name}', создаём новую конфигурацию! #33");
LoadDefaultConfig();
}
NextTick(SaveConfig);
}
private void GetPlayerSQL(String userID, BasePlayer player = null) {
if (sqlConnection == null) return;
Sql sql = SQL_SelectPlayer(userID);
sqlLibrary.Query(sql, sqlConnection, list => {
if (list == null || list.Count == 0) {
PlayerInfo.Import(userID, new PlayerInfo {
Balance = 0, LimitBalance = 0, Time = 0, DateTime = CurrentTime, IsHide = false,
}
);
if (player) DrawUI_HudPanel(player);
return;
}
Dictionary<String, Object> entry = list[0];
Int32 balance = ReadInt(entry["balance"]);
Int32 limit = ReadInt(entry["limit_balance"]);
Int32 time = ReadInt(entry["time"]);
Boolean hide = ReadBool(entry["is_hide"]);
PlayerInfo.Import(userID, new PlayerInfo {
Balance = balance, LimitBalance = limit, Time = time, DateTime = CurrentTime, IsHide = hide,
}
);
if (player) DrawUI_HudPanel(player);
}
);
}
private void OnEntityDeath(BradleyAPC entity, HitInfo info) {
Configuration.EarningCoins.PresetEarning earning = config.earningCoins.killedBradley;
if (!earning.useEarning) return;
if (!entity || info == null) return;
BasePlayer player = info.InitiatorPlayer;
if(!IsTakeEarning(player, earning)) return;
AddBalance(player, earning.countMoney, TypeLog.Action, earning.useChatAlert ? "CHAT_ALERT_EARNING_DESTROY_BRADLEY" : default, earning.useNoteAlert);
}
public class CourseInfo {
public Double lastUpdateCourseTime = 0;
public Int32 keyCourse;
}
void API_REMOVE_BALANCE(UInt64 userID, Int32 balance) {
String idString = userID.ToString();
API_REMOVE_BALANCE(idString, balance);
}
private static Configuration config = new Configuration();
private Sql SQL_UpsertPlayer(String steamId, Int32 balance, Int32 limit, Int32 time, Double lastConn, Boolean isHide) {
return Sql.Builder.Append($"INSERT INTO `{config.generalSetting.mySQLConnectionSettings.dbTableName}` (steamid,balance,limit_balance,`time`,last_connection,`is_hide`) " + $"VALUES (@0,@1,@2,@3,@4,@5) " + $"ON DUPLICATE KEY UPDATE " + $"balance=@1, limit_balance=@2, `time`=@3, last_connection=@4, `is_hide`=@5;", steamId, balance.ToString(), limit.ToString(), time.ToString(), lastConn.ToString(System.Globalization.CultureInfo.InvariantCulture), isHide ? "true" : "false" );
}
Boolean API_IS_REMOVED_BALANCE(String userID, Int32 amount) {
if (!UInt64.TryParse(userID, out UInt64 id)) return false;
BasePlayer player = BasePlayer.FindByID(id);
return player && DoesHaveEnoughBalance(player, amount);
}
private readonly Dictionary<UInt64, BasePlayer> heliLastAttacker = new();
private static void AddUI(BasePlayer player, String json) {
if (!player || player.net?.connection == null) return;
CommunityEntity.ServerInstance.ClientRPC<String>(RpcTarget.Player("AddUI", player.net.connection), json);
}
private Dictionary<BasePlayer, Int32> exchangerDataPlayer = new();
private const Boolean LanguageEn = false;
private void UpdateExchangerCourse() {
Configuration.ExchangerSetting.CourseController courseUpdated = GetActualyCourse();
if (actualyCourse != null && courseUpdated == actualyCourse) return;
actualyCourse = courseUpdated;
if (courseData.keyCourse == courseUpdated.secondsAfterWipe) return;
courseData.keyCourse = actualyCourse.secondsAfterWipe;
courseData.lastUpdateCourseTime = CurrentTime;
if (!config.exchangerSetting.useMessageUpdateCourse) return;
foreach (BasePlayer basePlayer in BasePlayer.activePlayerList) SendChat(GetLang("CHAT_ALERT_COURSE_UPDATE", basePlayer.UserIDString, config.commandExchanger), basePlayer);
}
void API_TRANSFERS(UInt64 userID, BasePlayer transferUser, Int32 balance) {
BasePlayer player = BasePlayer.FindByID(userID);
if (!player) return;
if (!transferUser) return;
TransferToPlayer(player, transferUser, balance);
}
private Boolean DoesHaveEnoughBalance(Int32 balancePlayer, Int32 amount = 0) {
if (balancePlayer == 0) return true;
return balancePlayer >= amount;
}
private void OnPlayerSleep(BasePlayer player) {
if (!player) return;
if (_interface == null) return;
InterfaceBuilder.DestroyPlayerUI(player);
}
private Boolean isUsedExchanger = false;
private const Int32 timeUpdateCourse = 600;
private Connection sqlConnection = null;
public String FormatTime(TimeSpan time, string userId) {
if (time.Days > 0) return Format(time.Days, GetLang("EXCHANGER_COURSE_TITLE_FORMAT_TIME_DAYS", userId));
if (time.Hours > 0) return Format(time.Hours, GetLang("EXCHANGER_COURSE_TITLE_FORMAT_TIME_HOURSE", userId));
if (time.Minutes > 0) return Format(time.Minutes, GetLang("EXCHANGER_COURSE_TITLE_FORMAT_TIME_MINUTES", userId));
return time.Seconds > 0 ? Format(time.Seconds, GetLang("EXCHANGER_COURSE_TITLE_FORMAT_TIME_SECONDS", userId)) : String.Empty;
}
private void DrawUI_StaticHider(BasePlayer player, Boolean hideStatus) {
if (_interface == null) return;
String panelType = !hideStatus ? "UI_Hide_Panel_Static" : "UI_UnHide_Panel_Static";
DestroyUI(player, InterfaceBuilder.UI_PANEL_STATIC_HIDER);
List<String> cashedStaticPanel = GetOrSetCacheUI(panelType);
if (cashedStaticPanel != null) {
foreach (String uiCached in cashedStaticPanel) AddUI(player, uiCached);
}
else {
String Interface = InterfaceBuilder.GetInterface(panelType);
if (Interface == null) return;
List<String> newUI = GetOrSetCacheUI(panelType, Interface);
cashedStaticPanel = newUI;
foreach (String uiCached in cashedStaticPanel) AddUI(player, uiCached);
}
}
private Sql SQL_CreateTableIfNotExists() {
return Sql.Builder.Append($"CREATE TABLE IF NOT EXISTS `{config.generalSetting.mySQLConnectionSettings.dbTableName}` (" + "`id` INT NOT NULL AUTO_INCREMENT," + "`steamid` VARCHAR(32) NOT NULL," + "`balance` VARCHAR(20) NOT NULL," + "`limit_balance` VARCHAR(20) NOT NULL," + "`time` VARCHAR(20) NOT NULL," + "`last_connection` VARCHAR(32) NOT NULL," + "`is_hide` VARCHAR(6) NOT NULL," + "PRIMARY KEY(`id`)," + "UNIQUE KEY `ux_steamid` (`steamid`)" + $") ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;");
}
private Boolean IsOnlyTakeEarning(BasePlayer player, Configuration.EarningCoins.PresetEarning earning) => earning.IsEarning(player);
private ImageUI _imageUI;
private void HookController() {
Configuration.EarningCoins earningCoins = config.earningCoins;
if (!earningCoins.timeTracked.useAfkChecker) {
Unsubscribe(nameof(OnPlayerChat));
Unsubscribe(nameof(OnPlayerCommand));
Unsubscribe(nameof(OnItemCraft));
Unsubscribe(nameof(OnItemCraftCancelled));
}
if (!isUsedUI) {
Unsubscribe(nameof(OnPlayerSleepEnded));
Unsubscribe(nameof(OnPlayerSleep));
}
if (!isUsedSQL) Unsubscribe(nameof(CanUserLogin));
else {
Unsubscribe(nameof(OnNewSave));
Unsubscribe(nameof(OnPlayerConnected));
}
if (config.generalSetting.typeCoins == TypeCoins.Virtual) {
Unsubscribe(nameof(OnLootSpawn));
Unsubscribe(nameof(OnItemSplit));
}
else {
Unsubscribe(nameof(OnLootEntity));
if (!config.earningCoins.droppedItem.isUseDropped) Unsubscribe(nameof(OnLootSpawn));
if (config.generalSetting.physicsItem.skinID == 0 || plugins.Find("Stacks") || plugins.Find("Loottable") || plugins.Find("CustomSkinsStacksFix") || plugins.Find("SkinBox") || plugins.Find("StackModifier")) {
Unsubscribe(nameof(OnPluginLoaded));
Unsubscribe(nameof(OnItemSplit));
}
}
Boolean anyGather = earningCoins.resourceGatherEarning.Count == 0 || earningCoins.resourceGatherEarning.Any(x => x.Value.useEarning);
if(!anyGather) Unsubscribe(nameof(OnDispenserBonusReceived));
Boolean anyCollectable = earningCoins.resourceCollectable.Count == 0 || earningCoins.resourceCollectable.Any(x => x.Value.useEarning);
if(!anyCollectable) Unsubscribe(nameof(OnCollectiblePickedup));
if (!isUsedUI && !earningCoins.killedPlayer.useEarning && !earningCoins.killedNpcs.useEarning && !config.generalSetting.physicsItem.useSaveDeath) Unsubscribe(nameof(OnPlayerDeath));
if(!config.generalSetting.physicsItem.useSaveDeath || config.generalSetting.typeCoins == TypeCoins.Virtual) Unsubscribe(nameof(OnPlayerRespawned));
if (!earningCoins.killedBradley.useEarning && !earningCoins.killedAnimal.useEarning && !earningCoins.killedBarrels.useEarning) Unsubscribe(nameof(OnEntityDeath));
if (!earningCoins.killedHelicopter.useEarning) {
Unsubscribe(nameof(OnPatrolHelicopterKill));
Unsubscribe(nameof(OnPatrolHelicopterTakeDamage));
}
if(!earningCoins.killedHelicopter.useEarning && !earningCoins.droppedItem.isUseDropped) Unsubscribe(nameof(OnEntityKill));
}
private void StoreAddedBalance(BasePlayer player, (Int32 exchangeCoins, Int32 storeMoney) exchangeDetail, UInt64 userID = 0) {
MoscovOVHBalanceSet(player, exchangeDetail, userID);
GameStoreBalanceSet(player, exchangeDetail, userID);
}
private void GameStoreBalanceSet(BasePlayer player, (Int32 exchangeCoins, Int32 storeMoney) exchangeDetail, UInt64 userID = 0) {
if (!config.exchangerSetting.storeSetting.useGameStores) return;
if (!GameStoresRUST) {
PrintWarning(LanguageEn ? "GameStores store is not configured" : "У вас не установлен магазин GameStores");
return;
}
if (exchangeDetail.storeMoney <= 0) return;
Boolean isSetOffline = !player || exchangeDetail.exchangeCoins <= 0;
userID = !isSetOffline ? player.userID : userID;
PlayerInfo pInfo = PlayerInfo.Get(userID.ToString());
if (!isSetOffline) {
if (config.exchangerSetting.limitStoreMoney > 0 && pInfo != null) {
Int32 limit = config.exchangerSetting.limitStoreMoney;
Int32 left = Math.Max(0, limit - pInfo.LimitBalance);
if (left <= 0 || exchangeDetail.storeMoney <= 0) return;
if (exchangeDetail.storeMoney > left) {
Int32 allowedPacksMoney = left;
Int32 allowedCoins = (allowedPacksMoney / actualyCourse.storeMoney) * actualyCourse.coin;
if (allowedCoins <= 0) return;
exchangeDetail = (allowedCoins, (allowedCoins * actualyCourse.storeMoney) / actualyCourse.coin);
}
pInfo.LimitBalance += exchangeDetail.storeMoney;
}
RemoveBalance(player, exchangeDetail.exchangeCoins, TypeLog.Exchanger);
SendChat(GetLang("CHAT_ALERT_EXCHANGED_SUCCES", player.UserIDString), player);
}
GameStoresRUST.CallHook("API_ChangePlayerBalance", userID, exchangeDetail.storeMoney, "plus", null, new Action<Boolean, String>((code, result) => {
LogToFile("DebugGS", $"GameStores DebugFile : [{DateTime.Now:dd : HH:mm:ss}] {userID} isSetOffline : {isSetOffline}, exchangeCoins : {exchangeDetail.exchangeCoins}, code : {code}, result : {result}", this);
if (code) {
return;
}
if (isSetOffline) return;
SendChat(GetLang("CHAT_ALERT_EXCHANGED_FAIL", player.UserIDString), player);
}
));
}
private void RemoveBalance(BasePlayer player, Int32 amount, TypeLog typeLog) {
if (!player) return;
PlayerInfo pInfo = PlayerInfo.Get(player.UserIDString);
if (pInfo == null) return;
RemoveBalance(player, pInfo, amount, typeLog);
}
void API_TRANSFERS(UInt64 userID, String transferUserID, Int32 balance) {
BasePlayer player = BasePlayer.FindByID(userID);
if (!player) return;
TransferToPlayer(player, transferUserID, balance);
}
private void DrawUI_UpdateHider(BasePlayer player, Boolean typeHide) {
if (!isUsedUI) return;
if (player.IsSleeping()) return;
if (_interface == null) return;
String panelType = String.Empty;
if (typeHide) {
DrawUI_StaticIconBalance(player);
panelType = "UI_UnHide_Panel_Update";
}
else {
panelType = "UI_Hide_Panel_Update";
DrawUI_StaticPanelBalance(player);
}
List<String> cashedStaticPanel = GetOrSetCacheUI(panelType);
if (cashedStaticPanel != null) {
foreach (String uiCached in cashedStaticPanel) AddUI(player, uiCached);
}
else {
String Interface = InterfaceBuilder.GetInterface(panelType);
if (Interface == null) return;
List<String> newUI = GetOrSetCacheUI(panelType, Interface);
cashedStaticPanel = newUI;
foreach (String uiCached in cashedStaticPanel) AddUI(player, uiCached);
}
}
private void OnPatrolHelicopterKill(PatrolHelicopter patrolHelicopter, HitInfo info) {
UInt64 patrolNetID = patrolHelicopter.net.ID.Value;
BasePlayer player = info.InitiatorPlayer;
if (!IsRealPlayer(player)) return;
heliKilleds[patrolNetID] = player;
}
private Boolean isUsedUI = false;
private void DisconnectedPlayer(BasePlayer player) {
if (isUsedSQL) {
PlayerInfo pInfo = PlayerInfo.Get(player.UserIDString);
if (pInfo == null) return;
ImportPlayerSQL(player.UserIDString, pInfo.Balance, pInfo.LimitBalance, pInfo.Time, pInfo.DateTime, pInfo.IsHide);
return;
}
PlayerInfo.Save(player.UserIDString);
PlayerInfo.Remove(player.UserIDString);
}
private Boolean IsDuel(UInt64 userID) {
Object obj = Interface.Oxide.RootPluginManager.GetPlugin("AimTraining")?.CallHook("IsArenaPlayer", userID);
if (obj is Boolean) return (Boolean)obj;
if (Battles) return (Boolean)Battles?.Call("IsPlayerOnBattle", userID);
if (Duel) return (Boolean)Duel?.Call("IsPlayerOnActiveDuel", BasePlayer.FindByID(userID));
if (Duelist) return (Boolean)Duelist?.Call("inEvent", BasePlayer.FindByID(userID));
if (ArenaTournament) return ArenaTournament.Call<Boolean>("IsOnTournament", userID);
if (XFarmRoom) return XFarmRoom.Call<Boolean>("API_PlayerInRoom", userID);
return false;
}
private void OnPlayerRespawned(BasePlayer player) {
if (!saveAfterDeath.TryGetValue(player, out Int32 balance)) return;
if (balance == 0) return;
AddBalance(player, balance, TypeLog.ReturnedSaveAfterDeath);
}
private void WriteData() => Oxide.Core.Interface.Oxide.DataFileSystem.WriteObject("IQSystem/IQEconomic/Exchanger/UpdateCourseTime", courseData);
private Dictionary<String, List<String>> cachedUI = new();
private void OnEntityDeath(LootContainer entity, HitInfo info) {
if (!entity.PrefabName.Contains("barrel") || entity.PrefabName.Contains("hobobarrel")) return;
Configuration.EarningCoins.PresetEarning earning = config.earningCoins.killedBarrels;
if (!earning.useEarning) return;
if (!entity || info == null) return;
BasePlayer player = info.InitiatorPlayer;
if(!IsTakeEarning(player, earning)) return;
AddBalance(player, earning.countMoney, TypeLog.Action, earning.useChatAlert ? "CHAT_ALERT_EARNING_DESTROY_BARREL" : default, earning.useNoteAlert);
}
private void ConnectedPlayer(BasePlayer player) {
PlayerInfo pInfo = PlayerInfo.Load(player.UserIDString);
if (pInfo != null) {
pInfo.DateTime = CurrentTime;
return;
}
PlayerInfo.Import(player.UserIDString, new PlayerInfo {
Balance = 0, LimitBalance = 0, Time = 0, DateTime = CurrentTime, IsHide = false,
}
);
PlayerInfo.Save(player.UserIDString);
}
private void ImportPlayerSQL(String userID, Int32 balance, Int32 limitBalance, Int32 time, Double dateTime, Boolean isHide, Boolean isMigrate = false) {
if (sqlConnection == null) return;
Sql upsert = SQL_UpsertPlayer(userID, balance, limitBalance, time, dateTime, isHide);
sqlLibrary.Insert(upsert, sqlConnection, _ => {
if (!isMigrate) Puts(LanguageEn ? $"Player {userID} data has been inserted/updated in the database" : $"Данные игрока {userID} были внесены/обновлены в базе данных");
}
);
}
private void RemovePhysicMoney(BasePlayer player, Int32 amount) {
List<Item> physicMoney = GetPhysicsItems(player);
foreach (Item pItem in physicMoney) {
if (amount <= 0) break;
if (pItem.amount >= amount) {
pItem.amount -= amount;
if (pItem.amount == 0) {
pItem.RemoveFromContainer();
pItem.Remove();
}
amount = 0;
}
else {
amount -= pItem.amount;
pItem.RemoveFromContainer();
pItem.Remove();
}
pItem.MarkDirty();
}
Pool.FreeUnmanaged(ref physicMoney);
}
private Boolean IsFriends(BasePlayer player, UInt64 targetID) {
List<UInt64> friendList = GetFriendList(player);
Boolean isFriend = friendList != null && friendList.Contains(targetID);
Pool.FreeUnmanaged(ref friendList);
return isFriend;
}
void API_TRANSFERS(BasePlayer player, UInt64 transferUserID, Int32 balance) {
if (!player) return;
BasePlayer targetPlayer = BasePlayer.FindByID(transferUserID);
if (!targetPlayer) return;
TransferToPlayer(player, targetPlayer, balance);
}
private readonly Core.MySql.Libraries.MySql sqlLibrary = Interface.Oxide.GetLibrary<Core.MySql.Libraries.MySql>();
private void DrawUI_UpdateExchangeLimite_Menu(BasePlayer player, Int32 limitExchanged) {
if (!exchangerDataPlayer.ContainsKey(player)) return;
if (player.IsSleeping()) return;
if (_interface == null) return;
String Interface = InterfaceBuilder.GetInterface("UI_Exchanger_Update_Limite_Label");
if (Interface == null) return;
Interface = Interface.Replace("%EXCHANGER_ACTUALY_LIMITE%", GetLang("EXCHANGER_ACTUALY_LIMITE", player.UserIDString, limitExchanged));
AddUI(player, Interface);
}
void API_TRANSFERS(UInt64 userID, UInt64 transferUserID, Int32 balance) {
BasePlayer player = BasePlayer.FindByID(userID);
if (!player) return;
TransferToPlayer(player, transferUserID.ToString(), balance);
}
private void TrackedPlayers() {
Configuration.EarningCoins.PresetEarning timerEarning = config.earningCoins.timeTracked.timeTrackerPreset;
Boolean isCheckAFK = config.earningCoins.timeTracked.useAfkChecker;
List<BasePlayer> pList = Pool.Get<List<BasePlayer>>();
pList.AddRange(BasePlayer.activePlayerList);
foreach (BasePlayer player in pList) {
PlayerInfo pInfo = PlayerInfo.Get(player.UserIDString);
if (pInfo == null) continue;
if(!IsOnlyTakeEarning(player, timerEarning)) continue;
if(isCheckAFK) if (player.IdleTime > 30) continue;
pInfo.Time += timeTracker / 60;
if (pInfo.Time >= config.earningCoins.timeTracked.timeMinuteGame) {
AddBalance(player, pInfo, timerEarning.countMoney, TypeLog.Action, timerEarning.useChatAlert ? "CHAT_ALERT_EARNING_TIME_TRACKED" : default);
pInfo.Time = 0;
}
}
Pool.FreeUnmanaged(ref pList);
}
Boolean API_IS_REMOVED_BALANCE(BasePlayer player, Int32 amount) => DoesHaveEnoughBalance(player, amount);
private void ConsoleCommandBalance(ConsoleSystem.Arg arg) {
BasePlayer player = arg.Player();
ChatCommandBalance(player);
}
private static Boolean IsUnblockExchangerCourse(Int32 timeExchange) => ((SaveRestore.SaveCreatedTime.ToUniversalTime().Subtract(epoch).TotalSeconds + timeExchange) - CurrentTime) <= 0;
private void GetAndFunctionalBalancePlayerSQL(String userID, Boolean addOrRemove, Int32 amount = 0) {
if (sqlConnection == null) return;
sqlLibrary.Query(SQL_SelectPlayer(userID), sqlConnection, list => {
if (list == null || list.Count == 0) {
Int32 balance = addOrRemove ? amount : 0;
PlayerInfo.Import(userID, new PlayerInfo {
Balance = balance, LimitBalance = 0, Time = 0, DateTime = CurrentTime, IsHide = false,
}
);
}
else {
var entry = list[0];
Int32 balance = ReadInt(entry["balance"]);
Int32 limit = ReadInt(entry["limit_balance"]);
Int32 time = ReadInt(entry["time"]);
Double last = ReadDouble(entry["last_connection"]);
Boolean hide = ReadBool(entry["is_hide"]);
Int32 newBalance = addOrRemove ? balance + amount : Math.Max(balance - amount, 0);
PlayerInfo.Import(userID, new PlayerInfo {
Balance = newBalance, LimitBalance = limi
// ... [Code preview truncated due to length. Full source in attached file] ...