C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System.Collections.Generic;
using UnityEngine;
using System.Reflection;
using System;
using System.IO;
using Newtonsoft.Json;
using System.Text;
using System.IO.Compression;
using Oxide.Core.Plugins;
using Oxide.Core.Configuration;
namespace Oxide.Plugins
{
[Info("RespawnBalance", "Jake_Rich", "1.0.1")]
[Description("Reset bed cooldown on death and configure metabolism when spawning.")]
public partial class RespawnBalance : RustPlugin
{
public static RespawnBalance _plugin;
public static FieldInfo BagField;
public JSONFile<ConfigData> _settingsFile;
public ConfigData Settings { get { return _settingsFile.Instance; } }
public RespawnTypeEnum RespawnType = RespawnTypeEnum.Default;
void Init()
{
_plugin = this;
_settingsFile = new JSONFile<ConfigData>("RespawnBalance", ConfigLocation.Config);
BagField = typeof(SleepingBag).GetField("unlockTime", BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public);
if (BagField == null)
{
PrintError("Warning! Didnt find bag field!");
}
}
void OnEntityDeath(BaseCombatEntity entity, HitInfo info)
{
if (!(entity is BasePlayer))
{
return;
}
SetCooldowns(entity as BasePlayer, entity.transform.position);
}
void OnServerCommand(ConsoleSystem.Arg args)
{
switch(args.cmd.FullName)
{
case "global.respawn":
{
RespawnType = RespawnTypeEnum.Default;
break;
}
case "global.respawn_sleepingbag":
{
uint uInt = args.GetUInt(0, 0u);
if (uInt == 0u)
{
RespawnType = RespawnTypeEnum.Default;
return;
}
var bed = BaseNetworkable.serverEntities.Find(uInt);
if (bed == null)
{
RespawnType = RespawnTypeEnum.Default;
return;
}
if (!(bed is SleepingBag))
{
RespawnType = RespawnTypeEnum.Default;
return;
}
if (bed.ShortPrefabName == "sleepingbag_leather_deployed")
{
RespawnType = RespawnTypeEnum.SleepingBag;
}
else if (bed.ShortPrefabName == "bed_deployed")
{
RespawnType = RespawnTypeEnum.Bed;
}
else
{
RespawnType = RespawnTypeEnum.Default;
}
break;
}
}
}
void OnPlayerRespawned(BasePlayer player)
{
switch (RespawnType)
{
case RespawnTypeEnum.Default:
{
Settings.DefaultSpawnSettings.Apply(player);
break;
}
case RespawnTypeEnum.SleepingBag:
{
Settings.SleepingBagSettings.Apply(player);
break;
}
case RespawnTypeEnum.Bed:
{
Settings.BedSettings.Apply(player);
break;
}
}
}
public class ConfigData
{
public int MaxCooldown = 300;
public float CooldownPerDistance = 3f;
public RespawnSettings DefaultSpawnSettings = new RespawnSettings(60f,100f,100f);
public RespawnSettings SleepingBagSettings = new RespawnSettings(20f, 40f, 40f);
public RespawnSettings BedSettings = new RespawnSettings(60f, 100f, 100f);
}
public class RespawnSettings
{
public float Health = 100f;
public float Hunger;
public float Water;
public void Apply(BasePlayer player)
{
player.health = Health;
player.metabolism.calories.value = Hunger;
player.metabolism.hydration.value = Water;
}
public RespawnSettings()
{
}
public RespawnSettings(float hp, float hunger, float water)
{
Health = hp;
Hunger = hunger;
Water = water;
}
}
public enum RespawnTypeEnum
{
Default = 0,
SleepingBag = 1,
Bed = 2,
}
public void SetCooldowns(BasePlayer player, Vector3 deathPosition)
{
foreach (var bag in SleepingBag.FindForPlayer(player.userID, true))
{
float distance = bag.Distance2D(player);
float targetCooldown = Mathf.Clamp(Settings.MaxCooldown - distance / Settings.CooldownPerDistance, 0, Settings.MaxCooldown);
//Puts($"Target cooldown for distance {distance} is {targetCooldown}");
if (bag.unlockSeconds < targetCooldown)
{
SetBagCooldown(bag, targetCooldown);
}
}
}
public static void SetBagCooldown(SleepingBag bag, float cooldown)
{
BagField.SetValue(bag, UnityEngine.Time.realtimeSinceStartup + cooldown);
}
#region PlayerData
public class BasePlayerData
{
[JsonIgnore]
public BasePlayer Player { get; set; }
public string userID { get; set; } = "";
public BasePlayerData()
{
}
public BasePlayerData(BasePlayer player) : base()
{
userID = player.UserIDString;
Player = player;
}
}
public class PlayerDataController<T> where T : BasePlayerData
{
[JsonPropertyAttribute(Required = Required.Always)]
private Dictionary<string, T> playerData { get; set; } = new Dictionary<string, T>();
private JSONFile<Dictionary<string, T>> _file;
private Timer _timer;
public IEnumerable<T> All { get { return playerData.Values; } }
public PlayerDataController()
{
}
public PlayerDataController(string filename = null)
{
if (filename == null)
{
return;
}
_file = new JSONFile<Dictionary<string, T>>(filename);
_timer = _plugin.timer.Every(120f, () =>
{
_file.Save();
});
}
public void Unload()
{
if (_file == null)
{
return;
}
_file.Save();
}
public T Get(string identifer)
{
T data;
if (!playerData.TryGetValue(identifer, out data))
{
data = Activator.CreateInstance<T>();
playerData[identifer] = data;
}
return data;
}
public T Get(ulong userID)
{
return Get(userID.ToString());
}
public T Get(BasePlayer player)
{
var data = Get(player.UserIDString);
data.Player = player;
return data;
}
public bool Has(ulong userID)
{
return playerData.ContainsKey(userID.ToString());
}
public void Set(string userID, T data)
{
playerData[userID] = data;
}
public bool Remove(string userID)
{
return playerData.Remove(userID);
}
public void Update(T data)
{
playerData[data.userID] = data;
}
}
#endregion
#region Configuration Files
public enum ConfigLocation
{
Data = 0,
Config = 1,
Logs = 2,
Plugins = 3,
Lang = 4,
Custom = 5,
}
public class JSONFile<Type> where Type : class
{
private DynamicConfigFile _file;
public string _name { get; set; }
public Type Instance { get; set; }
private ConfigLocation _location { get; set; }
private string _path { get; set; }
public bool SaveOnUnload = false;
public bool Compressed = false;
public JSONFile(string name, ConfigLocation location = ConfigLocation.Data, string path = null, string extension = ".json", bool saveOnUnload = false)
{
SaveOnUnload = saveOnUnload;
_name = name.Replace(".json", "");
_location = location;
switch (location)
{
case ConfigLocation.Data:
{
_path = $"{Oxide.Core.Interface.Oxide.DataDirectory}/{name}{extension}";
break;
}
case ConfigLocation.Config:
{
_path = $"{Oxide.Core.Interface.Oxide.ConfigDirectory}/{name}{extension}";
break;
}
case ConfigLocation.Logs:
{
_path = $"{Oxide.Core.Interface.Oxide.LogDirectory}/{name}{extension}";
break;
}
case ConfigLocation.Lang:
{
_path = $"{Oxide.Core.Interface.Oxide.LangDirectory}/{name}{extension}";
break;
}
case ConfigLocation.Custom:
{
_path = $"{path}/{name}{extension}";
break;
}
}
_file = new DynamicConfigFile(_path);
_file.Settings = new JsonSerializerSettings() { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
Init();
}
public virtual void Init()
{
_plugin.OnRemovedFromManager.Add(new Action<Plugin, PluginManager>(Unload));
Load();
Save();
Load();
}
public virtual void Load()
{
if (Compressed)
{
LoadCompressed();
return;
}
if (!_file.Exists())
{
Save();
}
Instance = _file.ReadObject<Type>();
if (Instance == null)
{
Instance = Activator.CreateInstance<Type>();
Save();
}
return;
}
private void LoadCompressed()
{
string str = _file.ReadObject<string>();
if (str == null || str == "")
{
Instance = Activator.CreateInstance<Type>();
return;
}
using (var compressedStream = new MemoryStream(Convert.FromBase64String(str)))
using (var zipStream = new GZipStream(compressedStream, CompressionMode.Decompress))
using (var resultStream = new MemoryStream())
{
var buffer = new byte[4096];
int read;
while ((read = zipStream.Read(buffer, 0, buffer.Length)) > 0)
{
resultStream.Write(buffer, 0, read);
}
Instance = JsonConvert.DeserializeObject<Type>(Encoding.UTF8.GetString(resultStream.ToArray()));
}
}
public virtual void Save()
{
if (Compressed)
{
SaveCompressed();
return;
}
_file.WriteObject(Instance);
return;
}
private void SaveCompressed()
{
using (var stream = new MemoryStream())
{
using (GZipStream zipStream = new GZipStream(stream, CompressionMode.Compress))
{
byte[] bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(Instance));
zipStream.Write(bytes, 0, bytes.Length);
zipStream.Close();
_file.WriteObject(Convert.ToBase64String(stream.ToArray()));
}
}
}
public virtual void Reload()
{
Load();
}
private void Unload(Plugin sender, PluginManager manager)
{
if (SaveOnUnload)
{
Save();
}
}
}
#endregion
}
}