C#:
using Facepunch;
using Newtonsoft.Json;
using Oxide.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using UnityEngine;
namespace Oxide.Plugins {
[Info("RaidProtector", "Vlad-00003", "1.4.0", ResourceId = 87)]
[Description("Decrease damage based on permissions, time and online state of the owner.")]
/*
* Author info:
* E-mail: Vlad-00003@mail.ru
* Vk: vk.com/vlad_00003
*/
class RaidProtector : RustPlugin {
#region Vars
private static RaidProtector Instance;
private PluginConfig _config;
private Dictionary<ulong, DateTime> _lastSeen;
private Dictionary<ulong, float> _informed;
private Dictionary<uint, BuildingOwners> _entityOwners;
private Dictionary<uint, BuildingOwners> _buildingOwners;
#endregion
#region Config
[JsonObject(MemberSerialization.OptIn)]
private class TimeConfig {
[JsonProperty("Использовать защиту в указанный промежуток времени")]
private readonly bool _use;
[JsonProperty("Час начала защиты")]
private readonly int _start;
[JsonProperty("Час снятия защиты")]
private readonly int _end;
private TimeSpan _startTimeSpan;
private TimeSpan _endTimeSpan;
//private TimeSpan _duration;
public TimeConfig(int start, int end, bool use) {
_start = start;
_end = end;
_use = use;
}
public bool IsActive {
get {
if (!_use) return false;
var now = Instance.CurrentTime;
if (_startTimeSpan < _endTimeSpan) return _startTimeSpan <= now && now <= _endTimeSpan;
return !(_endTimeSpan < now && now < _startTimeSpan);
}
}
[OnDeserialized]
internal void OnDeserializedMethod(StreamingContext context) {
_startTimeSpan = new TimeSpan(_start, 0, 0);
_endTimeSpan = new TimeSpan(_end, 0, 0);
//_duration = (_startTimeSpan - _endTimeSpan).Duration();
}
}
private class ProtectionSettings {
[JsonProperty("Множитель урона по постройкам")]
public float Modifier;
[JsonProperty("Настройка времени")]
public TimeConfig TimeConfig;
[JsonProperty("Защищать постройки когда игрок вне сети")]
public bool Offline;
#region Default Config
public static ProtectionSettings DefaultSettings => new ProtectionSettings {
Modifier = 0.7f, Offline = false, TimeConfig = new TimeConfig(23, 10, true)
}
;
public static ProtectionSettings Pro => new ProtectionSettings() {
Modifier = 0.5f, Offline = false, TimeConfig = new TimeConfig(20, 12, true)
}
;
public static ProtectionSettings Vip => new ProtectionSettings {
Modifier = 0.3f, Offline = true, TimeConfig = new TimeConfig(23, 10, false)
}
;
#endregion
public bool IsActive(bool anyOnline) {
// ReSharper disable once CompareOfFloatsByEqualityOperator
return Modifier != 1f && (TimeConfig.IsActive || Offline && !anyOnline);
}
public static ProtectionSettings GetBigger(ProtectionSettings first, ProtectionSettings second, bool anyOnline) {
if (!first.IsActive(anyOnline)) return second;
if (!second.IsActive(anyOnline)) return first;
return first.Modifier < second.Modifier ? first : second;
//if (first.Modifier > second.Modifier)
// return first;
//if (second.Modifier > first.Modifier)
// return second;
//return first.TimeConfig.Duration > second.TimeConfig.Duration ? first : second;
}
public static ProtectionSettings Default = new ProtectionSettings() {
Modifier = 999
}
;
}
private class MainSettings {
[JsonProperty("Чат-команда для получения короткого имени префаба предмета, на который вы смотрите")]
public string ChatCommand;
[JsonProperty("Задержка перед активацией защиты при выходе из игры (в секундах)")]
public float DelayBeforeOffline;
[JsonProperty("Время, которое должно пройти после нанесения урона для пересчёта владельцев постройки")]
public float ValidationDelay;
[JsonProperty("Защищать строительные блоки(Стены, фундаменты, каркасы...)")]
private bool _buildingBlock;
[JsonProperty("Защищать двери(обычные, двойные, высокие)")]
private bool _door;
[JsonProperty("Защищать простые строительные блоки(высокие стены)")]
private bool _simpleBuildingBlock;
[JsonProperty("Список префабов, которые необходимо защищать(короткое или полное имя префаба)")]
private List<string> _prefabs;
#region Default Config
public static MainSettings DefaultConfig => new MainSettings {
ChatCommand = "/shortname", DelayBeforeOffline = 120f, ValidationDelay = 120f, _buildingBlock = true, _door = true, _simpleBuildingBlock = true, _prefabs = new List<string> {
"mining_quarry", "vendingmachine.deployed", "furnace.large", "cupboard.tool.deployed", "refinery_small_deployed"
}
}
;
#endregion
public bool CheckEntity(BaseEntity entity) {
if (entity.OwnerID == 0) return false;
if (_prefabs.Contains(entity.ShortPrefabName)) return true;
if (entity is BuildingBlock && _buildingBlock) return true;
if (entity is Door && _door) return true;
if (entity is SimpleBuildingBlock && _simpleBuildingBlock) return true;
return false;
}
}
private class PluginConfig {
[JsonProperty("Использовать внутриигровое время (false - реальное время на серверной машине)")]
public bool InGameTime;
[JsonProperty("Настройка привилегий")]
public Dictionary<string, ProtectionSettings> Custom;
[JsonProperty("Стандартные настройки для всех игроков")]
public ProtectionSettings Default;
[JsonProperty("Настройки защиты")]
public MainSettings MainSettings;
[JsonProperty("Формат сообщений в чате")]
public string ChatFormat;
[JsonProperty("Задержка между сообщениями в чат о блокировке")]
public float MessageCooldown;
#region Default Config
public static PluginConfig DefaultConfig => new PluginConfig {
InGameTime = false, ChatFormat = "<color=#f4c842>[RaidProtector]</color> <color=#969696>{0}</color>", MessageCooldown = 15f, Default = ProtectionSettings.DefaultSettings, Custom = new Dictionary<string, ProtectionSettings> {
[nameof(RaidProtector)+".pro"]
= ProtectionSettings.Pro, [nameof(RaidProtector)+".vip"] = ProtectionSettings.Vip
}
, MainSettings = MainSettings.DefaultConfig
}
;
#endregion
}
#endregion
#region Config and data initialization
#region Config
private bool ShouldUpdateConfig() {
var res = false;
//Version < 1.1.0
if (Config["Настройки защиты", "Задержка перед активацией защиты при выходе из игры (в секундах)"] == null) {
PrintWarning("Option \"Delay before offline\" added to the config");
_config.MainSettings.DelayBeforeOffline = 120f;
res = true;
}
//Version < 1.3.0
if (Config["Настройки защиты", "Время, которое должно пройти после нанесения урона для пересчёта владельцев постройки"] == null) {
PrintWarning("Option \"Delay before validation\" added to the config");
_config.MainSettings.ValidationDelay = 120f;
res = true;
}
//version < 1.4.0
if (Config["Использовать внутриигровое время (false - реальное время на серверной машине)"] == null) {
PrintWarning("Option \"Use in-game time\" was added to the config");
_config.InGameTime = false;
res = true;
}
return res;
}
protected override void LoadDefaultConfig() {
PrintWarning("Благодарим за приобретение плагина на сайте RustPlugin.ru.Если вы приобрели этот плагин на другом ресурсе знайте - это лишает вас гарантированных обновлений!");
_config = PluginConfig.DefaultConfig;
}
protected override void LoadConfig() {
base.LoadConfig();
_config = Config.ReadObject<PluginConfig>();
if(ShouldUpdateConfig()) SaveConfig();
BuildingOwners.ValidateDelay = _config.MainSettings.ValidationDelay;
foreach (var perm in _config.Custom.Keys) {
permission.RegisterPermission(perm, this);
}
LoadData();
}
protected override void SaveConfig() {
Config.WriteObject(_config);
}
#endregion
#region Data
private void SaveData() {
Interface.Oxide.DataFileSystem.WriteObject(Title, _lastSeen);
}
private void LoadData() {
try {
_lastSeen = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<ulong, DateTime>>(Title);
}
catch (Exception ex) {
PrintError($"Failed to load last seen players data file (is the file corrupt?) ({ex.Message})");
_lastSeen = new Dictionary<ulong, DateTime>();
}
}
#endregion
#endregion
#region Initialization and quitting
// ... [Code preview truncated due to length. Full source in attached file] ...