C#:
using Pool = Facepunch.Pool;
using System.Collections.Generic;
using System;
using Newtonsoft.Json;
using System.Linq;
using Object = System.Object;
using ConVar;
using System.Text;
using UnityEngine;
using Oxide.Core.Plugins;
namespace Oxide.Plugins {
[Info("IQRates", "Mercury", "2.8.23")]
[Description("Настройка рейтинга на сервере")]
public class IQRates : RustPlugin {
private readonly List<Int64> itemDlcRemoved = new List<Int64>() {
1545779598, -1335497659, -139037392, 139037392, 44856928, -194953424, -1478855279, 110116923, 857465230, -1315992997,
}
;
private enum TypeEvent {
Bradley, Airdrop, CargoShip, Ch47, PatrolHelicopter,
}
private new void LoadDefaultMessages() {
lang.RegisterMessages(new Dictionary<String, String> {
["NIGHT_RATES_ALERT"]
= ":torch:<color=#7B6EF1>Night has fallen!</color>\n\n{0}", ["DAY_RATES_ALERT"] = ":granolabar:<color=#6EDDF1>Day has begun!</color>\n\n{0}", ["INFO_MY_RATE"] = "<color=#6EBBF1><b>Your rates:</b></color>" + "\nGathered resources: <color=#6EBBF1>x{0}</color>" + "\nFound resources: <color=#6EBBF1>x{1}</color>" + "\nLifted resources: <color=#6EBBF1>x{2}</color>" + "\nHarvested from plants: <color=#6EBBF1>x{3}</color>" + "\nQuarries: <color=#6EBBF1>x{4}</color>" + "\nExcavators: <color=#6EBBF1>x{5}</color>" + "\nFishing: <color=#6EBBF1>x{6}</color>", ["INFO_MY_RATE_BONUS"] = "\n+ bonus rates: <color=#6EBBF1>x{0}</color>", ["RATE_BONUS_DAY_OF_WEEK"] = ":exclamation:Attention, survivors!\n" + "\nThe increased rate period has begun!" + "\nAll <color=#6EBBF1>your</color> rates are boosted by a coefficient of <color=#6EBBF1>x{0}</color>" + "\nIt will be active from <color=#6EBBF1>{1} {2}</color>, until <color=#6EBBF1>{3} {4}</color>\n\nHurry to make the most of these bonuses!", ["RATE_BONUS_DAY_OF_WEEK_END"] = ":exclamation:Attention!\n" + "\nThe increased rate period has ended." + "\nThank you for participating!" + "\nStay tuned for new bonuses and continue your adventures!", ["MONDAY"] = "Monday", ["TUESDAY"] = "Tuesday", ["WEDNESDAY"] = "Wednesday", ["THURSDAY"] = "Thursday", ["FRIDAY"] = "Friday", ["SATURDAY"] = "Saturday", ["SUNDAY"] = "Sunday",
}
, this);
lang.RegisterMessages(new Dictionary<String, String> {
["NIGHT_RATES_ALERT"]
= ":torch:<color=#7B6EF1>Наступила ночь!</color>\n\n{0}", ["DAY_RATES_ALERT"] = ":granolabar:<color=#6EDDF1>Наступил день!</color>\n\n{0}", ["INFO_MY_RATE"] = "<color=#6EBBF1><b>Ваши рейты:</b></color>" + "\nДобываемые ресурсы: <color=#6EBBF1>x{0}</color>" + "\nНайденные ресурсы: <color=#6EBBF1>x{1}</color>" + "\nПоднимаемые ресурсы: <color=#6EBBF1>x{2}</color>" + "\nПоднимаемых с грядок: <color=#6EBBF1>x{3}</color>" + "\nКарьеров: <color=#6EBBF1>x{4}</color>" + "\nЭкскаваторы: <color=#6EBBF1>x{5}</color>" + "\nРыбалка: <color=#6EBBF1>x{6}</color>", ["INFO_MY_RATE_BONUS"] = "\n+ бонусные рейты : <color=#6EBBF1>x{0}</color>", ["RATE_BONUS_DAY_OF_WEEK"] = ":exclamation:Внимание, выжившие!\n" + "\nНаступил период увеличенного рейтинга!" + "\nКо всем <color=#6EBBF1>вашим</color> рейтингам прибавлен коэффициент <color=#6EBBF1>x{0}</color>" + "\nОн будет действовать с <color=#6EBBF1>{1} {2}</color>, до <color=#6EBBF1>{3} {4}</color>\n\nПоспешите воспользоваться бонусами!", ["RATE_BONUS_DAY_OF_WEEK_END"] = ":exclamation:Внимание!\n" + "\nПериод увеличенного рейтинга подошел к концу." + "\nСпасибо за участие!" + "\nСледите за новыми бонусами и продолжайте свои приключения!", ["MONDAY"] = "понедельника", ["TUESDAY"] = "вторника", ["WEDNESDAY"] = "средаы", ["THURSDAY"] = "четверга", ["FRIDAY"] = "пятницы", ["SATURDAY"] = "субботы", ["SUNDAY"] = "воскресенья",
}
, this, "ru");
Puts(LanguageEn ? "Language file loaded successfully" : "Языковой файл загружен успешно");
}
private void OnEntityKill(NPCPlayerCorpse corpse) => lootedEntity.Remove(corpse.net.ID.Value);
private ModifierDefintion CreateModifier(ModiferTea tea, Single difference) => GetDefintionModifer(tea.type, tea.duration, tea.value / difference);
private void SendDayNightMessages(Single hour, Int32 dayStart, Int32 nightStart) {
if (config.timeController.passageTime.skipNight || !config.timeController.passageTime.alertTimeController) return;
if (!sendMessageDay && sendMessageNight && Mathf.Abs(hour - dayStart) <= 0.1f) {
BroadcastRatesAlert("DAY_RATES_ALERT");
sendMessageDay = true;
sendMessageNight = false;
}
else if (!sendMessageNight && sendMessageDay && Mathf.Abs(hour - nightStart) <= 0.1f) {
BroadcastRatesAlert("NIGHT_RATES_ALERT");
sendMessageNight = true;
sendMessageDay = false;
}
}
private OvenController GetOrAddOvenController(BaseOven oven) {
if (ovenCotrollers.TryGetValue(oven, out OvenController controller)) return controller;
controller = oven.gameObject.AddComponent<OvenController>();
ovenCotrollers.TryAdd(oven, controller);
return controller;
}
private void OnEntitySpawned(HotAirBalloon balloon) {
if (!config.fuelTransportController.fuelPerSecTransport.useConsumedFuel) return;
balloon.fuelPerSec *= config.fuelTransportController.fuelPerSecTransport.consumedHotAirBalloon;
}
private void InitializeTimeComponent() {
timeComponent = TOD_Sky.Instance.Components.Time;
if (timeComponent == null) return;
SpeedTimes();
FreezeTimes();
}
private void UpdateBonusRate(String userID) {
Single bonusRate = config.rateBonusController.GetBonusRate(userID);
if (!bonusRatesPlayer.TryAdd(userID, bonusRate)) bonusRatesPlayer[userID] = bonusRate;
}
private void ReadData() {
lootedEntity = Oxide.Core.Interface.Oxide.DataFileSystem.ReadObject<HashSet<UInt64>>("IQSystem/IQRates/LootedContainers");
quarryToggled = Oxide.Core.Interface.Oxide.DataFileSystem.ReadObject<Dictionary<UInt64, String>>("IQSystem/IQRates/QuarryToggled");
}
private void WriteData() {
Oxide.Core.Interface.Oxide.DataFileSystem.WriteObject("IQSystem/IQRates/LootedContainers", lootedEntity);
Oxide.Core.Interface.Oxide.DataFileSystem.WriteObject("IQSystem/IQRates/QuarryToggled", quarryToggled);
}
private void SendChat(String Message, BasePlayer player, Chat.ChatChannel channel = Chat.ChatChannel.Global) {
if (IQChat && config.referencePlugins.iqchatReference.useIQChat) IQChat.Call("API_ALERT_PLAYER", player, Message, config.referencePlugins.iqchatReference.prefixChat, config.referencePlugins.iqchatReference.customAvatar);
else player.SendConsoleCommand("chat.add", channel, 0, Message);
}
// private Int32 wipeLeftHourse;
private BasePlayer excavatorUsePlayer = null;
private Double GetCarry(String userID, TypeConverted type, Int32 itemId) {
if (_carry.TryGetValue(userID, out Dictionary<TypeConverted, Dictionary<Int32, Double>> byType) && byType.TryGetValue(type, out Dictionary<Int32, Double> byItem) && byItem.TryGetValue(itemId, out Double c)) return c;
return 0d;
}
private Object OnQuarryGathered(MiningQuarry quarry, Item item) {
if (itemDlcRemoved.Contains(item.info.itemid)) return false;
return null;
}
private void OnDispenserGather(ResourceDispenser resource, BasePlayer player, Item item) => ConvertRate(TypeConverted.Gather, player.UserIDString, item);
private void OnLootEntity(BasePlayer player, BaseEntity targetEntity) {
if (!targetEntity || targetEntity.net == null) return;
if (!config.rateController.controllerList.IsConvetedPrefab(targetEntity.ShortPrefabName)) return;
UInt64 netID = targetEntity.net.ID.Value;
if (!lootedEntity.Add(netID)) return;
switch (targetEntity) {
case NPCPlayerCorpse corpse : {
if (!corpse) return;
foreach (ItemContainer corpseContainer in corpse.containers) {
foreach (Item item in corpseContainer.itemList) ConvertRate(TypeConverted.Loot, player.UserIDString, item);
}
break;
}
case LootContainer lootContainer : {
if (!lootContainer) return;
foreach (Item item in lootContainer.inventory.itemList) ConvertRate(TypeConverted.Loot, player.UserIDString, item);
break;
}
}
}
private void UnsubscribeFromEvents() {
timeComponent.OnSunrise -= OnSunrise;
timeComponent.OnSunset -= OnSunset;
timeComponent.OnHour -= OnHour;
}
private void OnServerInitialized() {
InitializeOvens();
Configuration.TimeController timeController = config.timeController;
if (timeController.passageTime.useTimeSpeed || timeController.freezeTime.useTimeFreeze) initializeTimeComponentTimer = timer.Once(5f, InitializeTimeComponent);
if (IsUsedEvents()) {
ChangeEventSchedule();
InitializeEvents();
}
if (config.rateBonusController.dayOfWeekBonusRated.useBonusDayOfWeek) config.rateBonusController.dayOfWeekBonusRated.UpdateBonusStatus(true);
foreach (Configuration.PermissionsRateList permissionOven in permissionsOvensSorted) if (!permission.PermissionExists(permissionOven.permission, this)) permission.RegisterPermission(permissionOven.permission, this);
foreach (Configuration.OvenController.CharacoalSetting.PermissionsChanceList permissionCharacoal in permissionsCharacoalChanceSorted) if (!permission.PermissionExists(permissionCharacoal.permission, this)) permission.RegisterPermission(permissionCharacoal.permission, this);
foreach (Configuration.PermissionsRateList permissionMixingTable in permissionsMixingTablesSorted) if (!permission.PermissionExists(permissionMixingTable.permission, this)) permission.RegisterPermission(permissionMixingTable.permission, this);
foreach (Configuration.PermissionsRateList permissionRecycler in permissionsSpeedRecyclerSorted) if (!permission.PermissionExists(permissionRecycler.permission, this)) permission.RegisterPermission(permissionRecycler.permission, this);
foreach (Configuration.PermissionsRateList permissionWipeBonus in permissionsWipeBonusSorted) if (!permission.PermissionExists(permissionWipeBonus.permission, this)) permission.RegisterPermission(permissionWipeBonus.permission, this);
foreach (KeyValuePair<String, Configuration.RateController.RateData> permissionRateDay in config.rateController.permissionRateDataDay) {
if (!permission.PermissionExists(permissionRateDay.Key, this)) permission.RegisterPermission(permissionRateDay.Key, this);
}
foreach (KeyValuePair<String, Configuration.RateController.RateData> permissionRateNight in config.rateController.permissionRateDataNight) {
if (!permission.PermissionExists(permissionRateNight.Key, this)) permission.RegisterPermission(permissionRateNight.Key, this);
}
foreach (Configuration.RateBonusController.RateControllerDayOfWeek.RateBonusDays permissionDayOfWeek in config.rateBonusController.dayOfWeekBonusRated.rateBonusDayOfWeek) {
foreach (Configuration.PermissionsRateList dayOfWeek in permissionDayOfWeek.permissionRateBonus) if (!permission.PermissionExists(dayOfWeek.permission, this)) permission.RegisterPermission(dayOfWeek.permission, this);
}
foreach (BasePlayer player in BasePlayer.activePlayerList) OnPlayerConnected(player);
}
private void AutoUpdateBonusRate() {
foreach (BasePlayer player in BasePlayer.activePlayerList) UpdateBonusRate(player.UserIDString);
}
private void OnHour() {
Single hour = TOD_Sky.Instance.Cycle.Hour;
Int32 dayStart = config.timeController.timeStartDay;
Int32 nightStart = config.timeController.timeStartNight;
if (hour >= dayStart && hour < nightStart) {
if (!activatedDay) OnSunrise();
SendDayNightMessages(hour, dayStart, nightStart);
return;
}
if (hour < dayStart || hour >= nightStart) {
if (activatedDay) OnSunset();
SendDayNightMessages(hour, dayStart, nightStart);
}
}
private void OnExcavatorResourceSet(ExcavatorArm arm, String resourceName, BasePlayer player) => excavatorUsePlayer = player;
private static Configuration config = new Configuration();
private void OnEntitySpawned(BaseVehicle vehicle) {
FuelFillingTransport(vehicle);
FuelPerSecController(vehicle);
}
private void OnOvenStarted(BaseOven oven) {
if (oven is BaseFuelLightSource) return;
if (config.ovenController.blackListOvenPrefab.Contains(oven.ShortPrefabName)) return;
//if(oven is not ElectricOven) return;
OvenController controller = GetOrAddOvenController(oven);
controller.SwitchOven(true);
}
private ModifierDefintion GetDefintionModifer(Modifier.ModifierType type, Single duration, Single value) {
return new ModifierDefintion {
source = Modifier.ModifierSource.Tea, type = type, duration = duration, value = value <= 0 ? 1.0f : value
}
;
}
private struct PlayerRateCache {
public Configuration.RateController.RateData dayRate;
public Configuration.RateController.RateData nightRate;
}
private readonly Dictionary<String, Dictionary<TypeConverted, Dictionary<Int32, Double>>> _carry = new(StringComparer.Ordinal);
private List<Configuration.PermissionsRateList> permissionsMixingTablesSorted = new();
[PluginReference]
Plugin IQChat;
private void FuelFillingTransport(BaseVehicle vehicle) {
if (!config.fuelTransportController.fuelBuyingShopKeeper.useAutoFillFuel) return;
Configuration.FuelTransportController.FuelBuingShopKeeper fuelTransportController = config.fuelTransportController.fuelBuyingShopKeeper;
IFuelSystem fuelSystem = vehicle.GetFuelSystem();
if (fuelSystem is not EntityFuelSystem entityFuelSystem) return;
Int32 fuelAmount = vehicle switch {
ScrapTransportHelicopter => fuelTransportController.fuelScrapTransport, Minicopter => fuelTransportController.fuelMinicopter, AttackHelicopter => fuelTransportController.fuelAttackHelicopter, RHIB or MotorRowboat => fuelTransportController.fuelBoat, BaseSubmarine => fuelTransportController.fuelSubmarine, _ => 0
}
;
if (fuelAmount == 0) return;
NextTick(() => {
Item Fuel = entityFuelSystem.GetFuelItem();
if (Fuel == null) return;
if (Fuel.amount is 50 or 100) Fuel.amount = fuelAmount;
}
);
}
private void OnGroupPermissionGranted(String name, String perm) {
foreach (BasePlayer player in BasePlayer.activePlayerList) RefreshPermissionPlayer(player.UserIDString);
}
private Dictionary<BaseOven, OvenController> ovenCotrollers = new Dictionary<BaseOven, OvenController>();
private class Configuration {
[JsonProperty(LanguageEn ? "Time data settings" : "Настройка данных о времени")]
public TimeController timeController = new TimeController();
[JsonProperty(LanguageEn ? "Plugin rate settings" : "Настройка рейтов плагина")]
public RateController rateController = new RateController();
[JsonProperty(LanguageEn ? "Bonus rate settings" : "Настройка бонусных рейтов")]
public RateBonusController rateBonusController = new RateBonusController();
[JsonProperty(LanguageEn ? "Furnace settings" : "Настройка печей")]
public OvenController ovenController = new OvenController();
[JsonProperty(LanguageEn ? "Tea mixing speed settings [Data is specified in %, from 0 to 100]" : "Настройка скорости смешивания чая [Данные указываются в %, от 0 до 100]")]
public MixingTableController mixingTableController = new MixingTableController();
[JsonProperty(LanguageEn ? "Tea influence on rate increase settings" : "Настройка влияния чая на увеличения рейтов")]
public TeaController teaController = new TeaController();
[JsonProperty(LanguageEn ? "Server events settings" : "Настройка ивентов сервера")]
public EventController eventController = new EventController();
[JsonProperty(LanguageEn ? "Recycler settings" : "Настройка переработчиков")]
public RecyclerController recyclerController = new RecyclerController();
[JsonProperty(LanguageEn ? "Transport fuel settings" : "Настройка топлива в транспорте")]
public FuelTransportController fuelTransportController = new FuelTransportController();
[JsonProperty(LanguageEn ? "Additional plugins settings" : "Настройка дополнительных плагинов")]
public ReferencePlugins referencePlugins = new ReferencePlugins();
internal class RateController {
[JsonProperty(LanguageEn ? "Exclusion/Rate adjustment list settings" : "Настройка списков исключений/корретировки рейтов")]
public ControllerListRate controllerList = new ControllerListRate();
[JsonProperty(LanguageEn ? "Day rates" : "Дневные рейты")]
public RateData dayRate = new RateData();
[JsonProperty(LanguageEn ? "Night rates" : "Ночные рейты")]
public RateData nightRate = new RateData();
[JsonProperty(LanguageEn ? "Day rate list by permissions [Permission = Day rate settings]" : "Список дневных рейтов по разрешениям [Разрешение = Настройка дневных рейтов]")]
public Dictionary<String, RateData> permissionRateDataDay = new Dictionary<String, RateData>();
[JsonProperty(LanguageEn ? "Night rate list by permissions [Permission = Night rate settings]" : "Список ночных рейтов по разрешениям [Разрешение = Настройка ночных рейтов]")]
public Dictionary<String, RateData> permissionRateDataNight = new Dictionary<String, RateData>();
public RateData GetRateData(String userID) {
if (!_.rateDataCache.TryGetValue(userID, out PlayerRateCache cache)) return dayRate;
return _.IsDayTime() ? cache.dayRate : cache.nightRate;
}
public void BuildCacheRate() {
dayRate.BuildCacheQuarry();
nightRate.BuildCacheQuarry();
foreach (RateData pDayRate in permissionRateDataDay.Values) pDayRate.BuildCacheQuarry();
foreach (RateData pNightRate in permissionRateDataNight.Values) pNightRate.BuildCacheQuarry();
}
internal class ControllerListRate {
[JsonProperty(LanguageEn ? "Blacklist or whitelist settings" : "Настройка черного или белого списка")]
public ItemLists itemLists = new ItemLists();
[JsonProperty(LanguageEn ? "Category blacklist (From F1 -> Items) to which rates will not apply [Leave empty if not needed]" : "Черный список категорий (Из F1 -> Items) на которые не будут действовать рейты [Если не нужно - оставьте пустым]")]
public List<String> blackListCategory = new List<String>();
[JsonProperty(LanguageEn ? "Prefab blacklist (shortPrefabName) to which rates will not apply [Leave empty if not needed]" : "Черный список префабов (shortPrefabName) на которые не будут действовать рейты [Если не нужно - оставьте пустым]")]
public HashSet<String> blackListPrefabs = new HashSet<String>();
[JsonProperty(LanguageEn ? "Blacklist of items by SkinID that the rates will not apply to [If not needed, leave blank]" : "Черный список предметов с SkinID на которые не будут действовать рейты [Если не нужно - оставьте пустым]")]
public HashSet<UInt64> blackListSkinIds = new HashSet<UInt64>();
internal class ItemLists {
[JsonProperty(LanguageEn ? "List type: 0 - Disabled, 1 - Whitelist, 2 - Blacklist" : "Тип списка : 0 - Выключено, 1 - Белый список, 2 - Черный список")]
public TypeList typeList;
[JsonProperty(LanguageEn ? "Item blacklist (shortname) to which rates will not apply" : "Черный список предметов (shortname) на которые не будут дейстовать рейты")]
public List<String> blackListShortname = new List<String>();
[JsonProperty(LanguageEn ? "Item whitelist (shortname) to which rates will apply, excluding other items" : "Белый список предметов (shortname) на которые будут дейстовать рейты, исключая другие предметы")]
public List<String> whiteListShortname = new List<String>();
[JsonIgnore]
public HashSet<Int32> whiteListItemIds = new HashSet<Int32>();
[JsonIgnore]
public HashSet<Int32> blackListItemIds = new HashSet<Int32>();
}
[JsonIgnore]
public HashSet<ItemCategory> blackListCategoryEnums = new HashSet<ItemCategory>();
public void GenerationCasheControllerListRate() {
if (blackListCategory != null && blackListCategory.Count != 0) {
foreach (String blackCategory in blackListCategory) {
if (!Enum.TryParse(blackCategory, out ItemCategory itemCategory)) {
_.PrintError(LanguageEn ? $"Invalid item category in 'Category BlackList'. Value: '{blackCategory}'" : $"Некорректная категория предмета в 'Черном списке категорий'. Значение: '{blackCategory}'");
continue;
}
blackListCategoryEnums.Add(itemCategory);
}
}
else blackListCategoryEnums = null;
if (itemLists.blackListShortname != null && itemLists.blackListShortname.Count != 0) {
foreach (String blackShortname in itemLists.blackListShortname) {
if (blackShortname.Contains("shortname")) continue;
ItemDefinition itemInfo = ItemManager.FindItemDefinition(blackShortname);
if (!itemInfo) {
_.PrintError(LanguageEn ? $"Invalid item shortname in 'BlackList (shortname)'. Value: '{blackShortname}'" : $"Некорректный shortname предмета в 'Черном списке предметов'. Значение: '{blackShortname}'");
continue;
}
itemLists.blackListItemIds.Add(itemInfo.itemid);
}
}
else itemLists.blackListItemIds = null;
if (itemLists.whiteListShortname != null && itemLists.whiteListShortname.Count != 0) {
foreach (String whiteShortname in itemLists.whiteListShortname) {
if (whiteShortname.Contains("shortname")) continue;
ItemDefinition itemInfo = ItemManager.FindItemDefinition(whiteShortname);
if (!itemInfo) {
_.PrintError(LanguageEn ? $"Invalid item shortname in 'WhihiteList (shortname)'. Value: '{whiteShortname}'" : $"Некорректный shortname предмета в 'Белом списке предметов'. Значение: '{whiteShortname}'");
continue;
}
itemLists.whiteListItemIds.Add(itemInfo.itemid);
}
}
else itemLists.whiteListItemIds = null;
}
public Boolean IsConvertedItem(Item item) => IsConvertedItem(item.info, item.skin);
public Boolean IsConvertedItem(ItemDefinition item, UInt64 skinId = 0) {
if (skinId != 0 && blackListSkinIds.Contains(skinId)) return false;
if (blackListCategoryEnums != null && blackListCategoryEnums.Contains(item.category)) return false;
return itemLists.typeList switch {
TypeList.WhiteList => itemLists.whiteListItemIds != null && itemLists.whiteListItemIds.Contains(item.itemid), TypeList.BlackList => itemLists.blackListItemIds == null || !itemLists.blackListItemIds.Contains(item.itemid), _ => true
}
;
}
public Boolean IsConvetedPrefab(String prefabName) => !blackListPrefabs.Contains(prefabName);
}
internal class RateData {
[JsonProperty(LanguageEn ? "Gathered items rates" : "Рейты добываемых предметов")]
public Single gatherRate;
[JsonProperty(LanguageEn ? "Found items rates" : "Рейты найденных предметов")]
public Single lootRate;
[JsonProperty(LanguageEn ? "Picked-up items rates" : "Рейты поднятых с земли предметов")]
public Single pickUpRate;
[JsonProperty(LanguageEn ? "Harvested items rates" : "Рейты поднятых с грядки предметов")]
public Single growableRate;
[JsonProperty(LanguageEn ? "Excavator output rates" : "Рейты добычи экскаватора")]
public Single excavatorRate;
[JsonProperty(LanguageEn ? "Fishing catch rates" : "Рейты пойманных с моря предметов (рыбалка)")]
public Single fishRate;
[JsonProperty(LanguageEn ? "Quarry rates settings" : "Настройка рейтов карьеров")]
public QuarryController quarryRate = new QuarryController();
[JsonProperty(LanguageEn ? "Setting individual rates. [Shortname] = [Rate]. This is a priority list, and the rates for items in this list will override all other settings." : "Настройка отдельных рейтов. [Shortname] = [Rate]. Это приоритетный список, рейты к предметам из него будут главнее всех других настроек.")]
public Dictionary<String, Single> rateCorrectly = new Dictionary<String, Single>();
[JsonIgnore]
public readonly Dictionary<Int32, Single> rateCorrectlyCache = new Dictionary<Int32, Single>();
public Single GetCorrectlyRate(Int32 itemId) => rateCorrectlyCache.GetValueOrDefault(itemId, 0);
internal class QuarryController {
[JsonProperty(LanguageEn ? "Quarry output rates" : "Рейты добычи карьера")]
public Single quarryRate;
[JsonProperty(LanguageEn ? "Detailed quarry output rates [shortname] - Rate" : "Детальные рейты добычи карьера [shortname] - Рейт")]
public Dictionary<String, Single> detailRateQuarry = new Dictionary<String, Single>();
[JsonIgnore]
public readonly Dictionary<Int32, Single> detailRateCache = new Dictionary<Int32, Single>();
public Single GetQuarryRate(Int32 itemID) => detailRateCache.GetValueOrDefault(itemID, quarryRate);
}
public void BuildCacheQuarry() {
foreach (KeyValuePair<String, Single> rCorrectly in rateCorrectly) {
if (rCorrectly.Key.Contains("shortname")) continue;
ItemDefinition itemInfo = ItemManager.FindItemDefinition(rCorrectly.Key);
if (!itemInfo) {
_.PrintError(LanguageEn ? $"Invalid item shortname in 'Setting individual rates'. Value: '{rCorrectly.Key}'" : $"Некорректный shortname предмета в 'Настройке отдельных рейтов карьера'. Значение: '{rCorrectly.Key}'");
continue;
}
if (!rateCorrectlyCache.TryAdd(itemInfo.itemid, rCorrectly.Value)) {
_.PrintError(LanguageEn ? $"Duplicate found in 'Setting individual rates'. Value: '{rCorrectly.Key}'" : $"Обнаружен дубликат в 'Настройке отдельных рейтов карьера'. Значение: '{rCorrectly.Key}'");
continue;
}
}
foreach (KeyValuePair<String, Single> dRate in quarryRate.detailRateQuarry) {
if (dRate.Key.Contains("shortname")) continue;
ItemDefinition itemInfo = ItemManager.FindItemDefinition(dRate.Key);
if (!itemInfo) {
_.PrintError(LanguageEn ? $"Invalid item shortname in 'Detailed quarry output rates'. Value: '{dRate.Key}'" : $"Некорректный shortname предмета в 'Детальные рейты добычи карьер'. Значение: '{dRate.Key}'");
continue;
}
if (!quarryRate.detailRateCache.TryAdd(itemInfo.itemid, dRate.Value)) {
_.PrintError(LanguageEn ? $"Duplicate found in 'Detailed quarry output rates'. Value: '{dRate.Key}'" : $"Обнаружен дубликат в 'Детальные рейты добычи карьер'. Значение: '{dRate.Key}'");
continue;
}
}
}
}
}
internal class RateBonusController {
[JsonProperty(LanguageEn ? "Settings for bonus increase of all rates after a wipe" : "Настройка бонусного увеличения всех рейтов после вайпа")]
public WipeBonusRated wipeBonusRated = new WipeBonusRated();
[JsonProperty(LanguageEn ? "Settings for bonus increase of all rates by days of the week and time" : "Настройка бонусного увеличения всех рейтов по дням недели и времени")]
public RateControllerDayOfWeek dayOfWeekBonusRated = new RateControllerDayOfWeek();
internal class WipeBonusRated {
[JsonProperty(LanguageEn ? "Enable bonus rate increase after a wipe [true - yes/false - no]" : "Использовать бонусное увеличение рейтов после вайпа [true - да/false - нет]")]
public Boolean useWipeBonus;
[JsonProperty(LanguageEn ? "Number of hours the bonus will be active after a wipe" : "Сколько часов будет действовать бонус после вайпа")]
public Int32 hourseActiveBonus;
[JsonProperty(LanguageEn ? "Bonus rate" : "Бонус к рейтам")]
public Single defaultRate;
[JsonProperty(LanguageEn ? "Bonus rates by permissions" : "Бонус к рейтам по разрешениям")]
public List<PermissionsRateList> permissionRateBonus = new List<PermissionsRateList>();
public Boolean IsActiveBonusWipeTime() => useWipeBonus && DateTime.UtcNow.Date.Subtract(SaveRestore.SaveCreatedTime.Date).TotalHours < hourseActiveBonus;
public Single GetWipeBonus(String userID) {
foreach (PermissionsRateList permissionsWipeBonus in _.permissionsWipeBonusSorted) {
if (_.permission.UserHasPermission(userID, permissionsWipeBonus.permission)) return permissionsWipeBonus.rate;
}
return defaultRate;
}
}
internal class RateControllerDayOfWeek {
[JsonProperty(LanguageEn ? "Enable bonus increase of all rates by days of the week" : "Использовать бонусное увеличение всех рейтов по дням недели")]
public Boolean useBonusDayOfWeek;
[JsonProperty(LanguageEn ? "List of days of the week and times with increased rates [Do not allow date overlap, as it may cause conflicts]" : "Список дней недели и времени с увеличенными рейтами [Не допускайте пересечение дат, иначе это может вызвать конфликт]")]
public List<RateBonusDays> rateBonusDayOfWeek = new();
[JsonIgnore]
private RateBonusDays[] _weekHourMap;
public void BuildCache() {
_weekHourMap = new RateBonusDays[7 * 24];
for (Int32 i = 0; i < rateBonusDayOfWeek.Count; i++) {
RateBonusDays w = rateBonusDayOfWeek[i];
if (!Enum.TryParse(w.timeStartBonus.dayOfWeek, ignoreCase : true, out DayOfWeek sd) || !Enum.TryParse(w.timeStopBonus.dayOfWeek, ignoreCase : true, out DayOfWeek ed)) {
_.PrintError(LanguageEn ? $"Invalid DayOfWeek in config: '{w.timeStartBonus.dayOfWeek}' -> '{w.timeStopBonus.dayOfWeek}'" : $"Некорректный день недели в конфиге: '{w.timeStartBonus.dayOfWeek}' -> '{w.timeStopBonus.dayOfWeek}'");
continue;
}
w.startDay = sd;
w.stopDay = ed;
w.startHour = w.timeStartBonus.timeHours;
w.stopHour = w.timeStopBonus.timeHours;
if (w.permissionRateBonus is {
Count : > 0
}
) {
PermissionsRateList[] arr = w.permissionRateBonus.ToArray();
Array.Sort(arr, (a, b) => b.rate.CompareTo(a.rate));
w.permissionRateBonusSorted = arr;
}
else {
w.permissionRateBonusSorted = Array.Empty<PermissionsRateList>();
}
Int32 start = ((Int32)w.startDay) * 24 + w.startHour;
Int32 stop = ((Int32)w.stopDay) * 24 + w.stopHour;
if ((UInt32)start >= 168 || (UInt32)stop >= 168) {
_.PrintError(LanguageEn ? $"Invalid hours range. Start={w.startDay} {w.startHour}, Stop={w.stopDay} {w.stopHour}. Expected hours 0..23." : $"Некорректный диапазон часов. Start={w.startDay} {w.startHour}, Stop={w.stopDay} {w.stopHour}. Ожидаются часы 0..23.");
continue;
}
void SetRange(Int32 from, Int32 toInclusive) {
for (Int32 h = from; h <= toInclusive; h++) {
if (_weekHourMap[h] != null && _weekHourMap[h] != w) {
_.PrintError(LanguageEn ? $"Overlap detected at weekHour={h}. Existing window will be kept." : $"Обнаружено пересечение окон в weekHour={h}. Будет использовано ранее заданное окно.");
continue;
}
_weekHourMap[h] = w;
}
}
if (start <= stop) SetRange(start, stop);
else {
SetRange(start, 167);
SetRange(0, stop);
}
}
}
internal class RateBonusDays {
[JsonProperty(LanguageEn ? "Bonus rate" : "Бонус к рейтам")]
public Single defaultRate;
[JsonProperty(LanguageEn ? "Bonus rates by permissions" : "Бонус к рейтам по разрешениям")]
public List<PermissionsRateList> permissionRateBonus = new List<PermissionsRateList>();
[JsonProperty(LanguageEn ? "Bonus start settings" : "Настройки запуска бонуса")]
public TimeController timeStartBonus = new();
[JsonProperty(LanguageEn ? "Bonus stop settings" : "Настройки завершения бонуса")]
public TimeController timeStopBonus = new();
internal class TimeController {
[JsonProperty(LanguageEn ? "Time in hours [1-24]" : "Время в часах [1-24]")]
public Int32 timeHours;
[JsonProperty(LanguageEn ? "Day of the week: Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday" : "День недели : Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday")]
public String dayOfWeek;
}
[JsonIgnore]
public DayOfWeek startDay;
[JsonIgnore]
public DayOfWeek stopDay;
[JsonIgnore]
public Int32 startHour;
[JsonIgnore]
public Int32 stopHour;
[JsonIgnore]
public PermissionsRateList[] permissionRateBonusSorted;
}
public void UpdateBonusStatus(Boolean isInit = false) {
RateBonusDays currentRateBonusDay = GetRateBonusForCurrentTime();
if (currentRateBonusDay != _.rateBonusDay || isInit) {
_.rateBonusDay = currentRateBonusDay;
if (currentRateBonusDay != null) {
String startDayOfWeek = currentRateBonusDay.timeStartBonus.dayOfWeek.ToUpper();
String stopDayOfWeek = currentRateBonusDay.timeStopBonus.dayOfWeek.ToUpper();
foreach (BasePlayer player in BasePlayer.activePlayerList) {
_.SendChat(_.GetLang("RATE_BONUS_DAY_OF_WEEK", player.UserIDString, GetDayOfWeekBonus(player.UserIDString), _.GetLang(startDayOfWeek, player.UserIDString), $"{currentRateBonusDay.timeStartBonus.timeHours}:00", _.GetLang(stopDayOfWeek, player.UserIDString), $"{currentRateBonusDay.timeStopBonus.timeHours}:00"), player);
}
}
else {
foreach (BasePlayer player in BasePlayer.activePlayerList) _.SendChat(_.GetLang("RATE_BONUS_DAY_OF_WEEK_END", player.UserIDString), player);
}
}
_.timerUpdateBonusRate = _.timer.Once(300f, () => UpdateBonusStatus());
}
public Single GetDayOfWeekBonus(String userID) {
RateBonusDays window = GetRateBonusForCurrentTime();
if (window == null) return 0f;
PermissionsRateList[] sorted = window.permissionRateBonusSorted;
for (Int32 i = 0; i < sorted.Length; i++) {
PermissionsRateList p = sorted[i];
if (_.permission.UserHasPermission(userID, p.permission)) return p.rate;
}
return window.defaultRate;
}
private RateBonusDays GetRateBonusForCurrentTime() {
DateTime now = DateTime.UtcNow;
Int32 idx = ((Int32)now.DayOfWeek) * 24 + now.Hour;
return _weekHourMap[idx];
}
}
public Single GetBonusRate(String userID) {
Single bonusRate = 0f;
if (wipeBonusRated.IsActiveBonusWipeTime()) bonusRate += wipeBonusRated.GetWipeBonus(userID);
if(dayOfWeekBonusRated.useBonusDayOfWeek) bonusRate += dayOfWeekBonusRated.GetDayOfWeekBonus(userID);
return bonusRate;
}
}
internal class TimeController {
[JsonProperty(LanguageEn ? "Server day start time [0-23]" : "Время начала дня на сервере [0-23]")]
public Int32 timeStartDay;
[JsonProperty(LanguageEn ? "Server night start time [0-23]" : "Время начала ночи на сервере [0-23]")]
public Int32 timeStartNight;
[JsonProperty(LanguageEn ? "Time acceleration settings [Note: Acceleration may cause standard events to appear faster, use custom event settings]" : "Настройка ускорения времени [Учтите, от ускорения стандартные ивенты могут появляться быстрее, используйте кастомную настройку ивентов]")]
public PassageTime passageTime = new PassageTime();
[JsonProperty(LanguageEn ? "Time freeze settings [Note: Freezing time may prevent standard events from appearing, use custom event settings]" : "Настройка заморозки времени [Учтите, от заморозки времени стандартные ивенты могут не появляться, используйте кастомную настройку ивентов]")]
public FreezeTime freezeTime = new FreezeTime();
internal class PassageTime {
[JsonProperty(LanguageEn ? "Use instant night skip [true - yes/false - no]" : "Использовать моментальный пропуск ночи [true - да/false - нет]")]
public Boolean skipNight;
[JsonProperty(LanguageEn ? "Use chat notification for day-night change" : "Использовать уведомление в чате о смене времени суток")]
public Boolean alertTimeController;
[JsonProperty(LanguageEn ? "Use time acceleration [true - yes/false - no]" : "Использовать ускорение времени [true - да/false - нет]")]
public Boolean useTimeSpeed;
[JsonProperty(LanguageEn ? "Number of minutes in a day" : "Сколько минут будет длиться день")]
public Int32 minutesDay;
[JsonProperty(LanguageEn ? "Number of minutes in a night" : "Сколько минут будет длиться ночь")]
public Int32 minutesNight;
}
internal class FreezeTime {
[JsonProperty(LanguageEn ? "Use time freeze [true - yes/false - no]" : "Использовать заморозку времени [true - да/false - нет]")]
public Boolean useTimeFreeze;
[JsonProperty(LanguageEn ? "Frozen time [0-23]" : "Замороженное время [0-23]")]
public Int32 timeFreeze;
}
}
internal class EventController {
[JsonProperty(LanguageEn ? "Cargo ship event settings" : "Настройка грузового корабля")]
public EventTemplate eventCargoShip = new EventTemplate();
[JsonProperty(LanguageEn ? "Bradley tank event settings" : "Настройка танка")]
public EventTemplate eventBradley = new EventTemplate();
[JsonProperty(LanguageEn ? "Patrol helicopter event settings" : "Настройка патрульного вертолета")]
public EventTemplate eventHelicopter = new EventTemplate();
[JsonProperty(LanguageEn ? "Chinook event settings" : "Настройка чинука")]
public EventTemplate eventCh47 = new EventTemplate();
[JsonProperty(LanguageEn ? "Airdrop event settings" : "Настройка аирдропа")]
public EventTemplate eventAirdrop = new EventTemplate();
internal class EventTemplate {
[JsonProperty(LanguageEn ? "Use custom settings for this event [true - yes/false - no]" : "Использовать собственные настройки для данного ивента [true - да/false - нет]")]
public Boolean useEvent;
[JsonProperty(LanguageEn ? "Completely disable this event [true - yes/false - no]" : "Полностью выключить данный ивент [true - да/false - нет]")]
public Boolean disableFullEvent;
[JsonProperty(LanguageEn ? "Event spawn settings" : "Настройка появления ивента")]
public SpawnController spawnController = new SpawnController();
internal class SpawnController {
[JsonProperty(LanguageEn ? "Timer type: true - Static, false - Random" : "Тип таймера : true - Статичный, false - Рандомный")]
public Boolean staticTimeOrRandom;
[JsonProperty(LanguageEn ? "Static event spawn time" : "Статичное время появления ивента")]
public Int32 staticTime;
[JsonProperty(LanguageEn ? "Random event spawn time settings" : "Настройка случайного времени появления ивента")]
public RandomTime randomTimePreset = new RandomTime();
internal class RandomTime {
[JsonProperty(LanguageEn ? "Minimum time" : "Минимальное время")]
public Int32 minTime;
[JsonProperty(LanguageEn ? "Maximum time" : "Максимальное время")]
public Int32 maxTime;
public Int32 GetRandomSpawnTime() => Oxide.Core.Random.Range(minTime, maxTime);
}
public Int32 GetSpawnTimeSecods() => staticTimeOrRandom ? staticTime : randomTimePreset.GetRandomSpawnTime();
}
}
}
internal class MixingTableController {
[JsonProperty(LanguageEn ? "Use tea mixing speed acceleration [true - yes/false - no]" : "Использовать ускорение смешивания чая [true - да/false - нет]")]
public Boolean useSpeedMixingTable;
[JsonProperty(LanguageEn ? "Default acceleration [Specify in %, from 0 to 100]" : "Стандартное ускорение [Указывайте в %, от 0 до 100]")]
public Single defaultRate;
[JsonProperty(LanguageEn ? "Acceleration by permissions [Specify in %, from 0 to 100]" : "Ускорение по разрешениям [Указывайте в %, от 0 до 100]")]
public List<PermissionsRateList> permissionList = new List<PermissionsRateList>();
pub
// ... [Code preview truncated due to length. Full source in attached file] ...