C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
using System.Collections.Generic;
using Oxide.Core;
using Oxide.Game.Rust.Cui;
using Rust;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Shrinking Radiation Zone", "k1lly0u", "0.1.5")]
[Description("Create shrinking radiation zones for BR style events")]
class ShrinkingRadZone : RustPlugin
{
#region Fields
private Hash<string, ShrinkZone> activeZones = new Hash<string, ShrinkZone>();
private const string SPHERE_ENTITY = "assets/prefabs/visualization/sphere.prefab";
#endregion
#region Oxide Hooks
private void Loaded()
{
permission.RegisterPermission("shrinkingradzone.use", this);
lang.RegisterMessages(messages, this);
}
private void Unload()
{
ShrinkZone[] shrinkZones = UnityEngine.Object.FindObjectsOfType<ShrinkZone>();
for (int i = 0; i < shrinkZones?.Length ; i++)
{
UnityEngine.Object.Destroy(shrinkZones[i]);
}
Configuration = null;
}
#endregion
#region API
private string CreateShrinkZone(Vector3 position, float radius, float time)
{
string zoneId = CuiHelper.GetGuid();
ShrinkZone zone = new GameObject().AddComponent<ShrinkZone>();
activeZones[zoneId] = zone;
zone.CreateZones(zoneId, position, radius, time);
return zoneId;
}
private void ToggleZoneShrink(string id)
{
ShrinkZone shrinkZone;
if (activeZones.TryGetValue(id, out shrinkZone))
shrinkZone.ToggleShrinking();
}
private void DestroyShrinkZone(string id)
{
ShrinkZone shrinkZone;
if (activeZones.TryGetValue(id, out shrinkZone))
{
UnityEngine.Object.Destroy(shrinkZone);
activeZones.Remove(id);
}
}
#endregion
#region Classes
private class ShrinkZone : MonoBehaviour
{
private string zoneId;
private float initialRadius;
private float modifiedRadius;
private float targetRadius;
private float timeToTake;
private float timeTaken;
private SphereEntity[] innerSpheres;
private SphereEntity[] outerSpheres;
private SphereCollider innerCollider;
private TriggerRadiation radiation;
private void Awake()
{
gameObject.layer = (int)Layer.Reserved1;
gameObject.name = "ShrinkZone";
enabled = false;
targetRadius = Configuration.FinalZoneSize;
timeToTake = Configuration.ShrinkTime;
timeTaken = 0;
}
private void OnDestroy()
{
foreach (BaseEntity entity in radiation.entityContents)
entity.LeaveTrigger(radiation);
foreach (SphereEntity entity in innerSpheres)
entity.Kill();
foreach (SphereEntity entity in outerSpheres)
entity.Kill();
Destroy(gameObject);
}
private void Update()
{
timeTaken = timeTaken + UnityEngine.Time.deltaTime;
float single = Mathf.InverseLerp(0f, timeToTake, timeTaken);
modifiedRadius = initialRadius * (1 - single);
foreach (SphereEntity innerSphere in innerSpheres)
{
innerSphere.currentRadius = (initialRadius * 2) * (1 - single);
innerSphere.SendNetworkUpdateImmediate();
}
innerCollider.radius = modifiedRadius;
if (modifiedRadius <= targetRadius)
{
enabled = false;
Interface.CallHook("OnRadiationZoneShrunk", zoneId);
}
}
private void OnTriggerEnter(Collider obj)
{
BasePlayer player = obj?.GetComponentInParent<BasePlayer>();
if (player != null)
{
player.LeaveTrigger(radiation);
}
}
private void OnTriggerExit(Collider obj)
{
BasePlayer player = obj?.GetComponentInParent<BasePlayer>();
if (player != null)
{
player.EnterTrigger(radiation);
}
}
public void CreateZones(string zoneId, Vector3 position, float initialRadius, float timeToTake)
{
transform.position = position;
this.zoneId = zoneId;
this.initialRadius = initialRadius;
this.timeToTake = timeToTake;
innerSpheres = new SphereEntity[Configuration.DomeShade];
outerSpheres = new SphereEntity[Configuration.DomeShade];
for (int i = 0; i < Configuration.DomeShade; i++)
{
SphereEntity innerSphere = (SphereEntity)GameManager.server.CreateEntity(SPHERE_ENTITY, position, Quaternion.identity, true);
innerSphere.currentRadius = initialRadius * 2;
innerSphere.lerpSpeed = 0;
innerSphere.enableSaving = false;
innerSphere.Spawn();
innerSpheres[i] = innerSphere;
}
innerCollider = gameObject.AddComponent<SphereCollider>();
innerCollider.isTrigger = true;
innerCollider.radius = initialRadius;
for (int i = 0; i < Configuration.DomeShade; i++)
{
SphereEntity outerSphere = (SphereEntity)GameManager.server.CreateEntity(SPHERE_ENTITY, position, Quaternion.identity, true);
outerSphere.currentRadius = (initialRadius * 2) + Configuration.RadiationBuffer;
outerSphere.lerpSpeed = 0;
outerSphere.enableSaving = false;
outerSphere.Spawn();
if (i == 0)
{
SphereCollider outerCollider = outerSphere.gameObject.AddComponent<SphereCollider>();
outerCollider.isTrigger = true;
outerCollider.radius = 0.5f;
radiation = outerSphere.gameObject.AddComponent<TriggerRadiation>();
radiation.RadiationAmountOverride = Configuration.RadiationStrength;
radiation.interestLayers = 131072;
radiation.enabled = true;
}
outerSpheres[i] = outerSphere;
}
enabled = true;
}
public void ToggleShrinking() => enabled = !enabled;
}
#endregion
#region Commands
[ChatCommand("shrink")]
private void cmdShrink(BasePlayer player, string command, string[] args)
{
if (!player.IsAdmin && !permission.UserHasPermission(player.UserIDString, "shrinkingradzone.use"))
return;
if (args.Length == 0)
{
SendReply(player, $"<color=#00CC00>{Title}</color> <color=#939393>v</color><color=#00CC00>{Version}</color> <color=#939393>-</color> <color=#00CC00>{Author}</color>");
SendReply(player, msg("/shrink on me - Starts a shrinking rad zone on your position", player.UserIDString));
SendReply(player, msg("/shrink on <x> <z> - Starts a shrinking rad zone on the specified position", player.UserIDString));
SendReply(player, msg("/shrink stop - Destroys all active zones", player.UserIDString));
SendReply(player, msg("/shrink buffer <## value> - Set the radiation buffer size", player.UserIDString));
SendReply(player, msg("/shrink startsize <## value> - Set the initial zone size", player.UserIDString));
SendReply(player, msg("/shrink endsize <## value> - Set the final zone size", player.UserIDString));
SendReply(player, msg("/shrink strength <## value> - Set the radiation strength (rads per second)", player.UserIDString));
SendReply(player, msg("/shrink time <## value> - Set the time it takes to shrink (in seconds)", player.UserIDString));
return;
}
switch (args[0].ToLower())
{
case "on":
if (args.Length >= 2)
{
object position = null;
if (args[1].ToLower() == "me")
position = player.transform.position;
else if (args.Length > 2)
{
float x;
float z;
if (float.TryParse(args[1], out x) && float.TryParse(args[2], out z))
{
Vector3 temp = new Vector3(x, 0, z);
float height = TerrainMeta.HeightMap.GetHeight((Vector3)temp);
position = new Vector3(x, height, z);
}
}
if (position is Vector3)
{
CreateShrinkZone((Vector3) position, Configuration.InitialZoneSize, Configuration.ShrinkTime);
SendReply(player, "Zone Created!");
return;
}
}
else
{
SendReply(player, "/shrink on me\n/shrink on <x> <z>");
return;
}
return;
case "stop":
foreach (KeyValuePair<string, ShrinkZone> zone in activeZones)
{
UnityEngine.Object.DestroyImmediate(zone.Value.gameObject);
Interface.CallHook("RadzoneEnd", zone.Key);
}
activeZones.Clear();
SendReply(player, msg("All zones destroyed"));
return;
case "buffer":
if (args.Length == 2)
{
float value;
if (float.TryParse(args[1], out value))
{
Configuration.RadiationBuffer = value;
SaveConfig();
SendReply(player, string.Format(msg("Radiation buffer set to : {0}", player.UserIDString), value));
}
else SendReply(player, msg("You must enter a number value", player.UserIDString));
}
else SendReply(player, msg("/shrink buffer <##>", player.UserIDString));
return;
case "startsize":
if (args.Length == 2)
{
float value;
if (float.TryParse(args[1], out value))
{
Configuration.InitialZoneSize = value;
SaveConfig();
SendReply(player, string.Format(msg("Initial size set to : {0}", player.UserIDString), value));
}
else SendReply(player, msg("You must enter a number value", player.UserIDString));
}
else SendReply(player, msg("/shrink startsize <##>", player.UserIDString));
return;
case "endsize":
if (args.Length == 2)
{
float value;
if (float.TryParse(args[1], out value))
{
Configuration.FinalZoneSize = value;
SaveConfig();
SendReply(player, string.Format(msg("Final size set to : {0}", player.UserIDString), value));
}
else SendReply(player, msg("You must enter a number value", player.UserIDString));
}
else SendReply(player, msg("/shrink endsize <##>", player.UserIDString));
return;
case "strength":
if (args.Length == 2)
{
float value;
if (float.TryParse(args[1], out value))
{
Configuration.RadiationStrength = value;
SaveConfig();
SendReply(player, string.Format(msg("Radiation strength set to : {0}", player.UserIDString), value));
}
else SendReply(player, msg("You must enter a number value", player.UserIDString));
}
else SendReply(player, msg("/shrink strength <##>", player.UserIDString));
return;
case "time":
if (args.Length == 2)
{
float value;
if (float.TryParse(args[1], out value))
{
Configuration.ShrinkTime = value;
SaveConfig();
SendReply(player, string.Format(msg("Shrink time set to : {0}", player.UserIDString), value));
}
else SendReply(player, msg("You must enter a number value", player.UserIDString));
}
else SendReply(player, msg("/shrink time <##>", player.UserIDString));
return;
default:
break;
}
}
[ConsoleCommand("shrink")]
private void ccmdShrink(ConsoleSystem.Arg arg)
{
if (arg.Connection != null)
return;
if (arg.Args.Length == 0)
{
SendReply(arg, $"{Title} v{Version} - {Author}");
SendReply(arg, "shrink on <x> <z> - Starts a shrinking rad zone on the specified position");
SendReply(arg, "shrink stop - Destroys all active zones");
SendReply(arg, "shrink buffer <## value> - Set the radiation buffer size");
SendReply(arg, "shrink startsize <## value> - Set the initial zone size");
SendReply(arg, "shrink endsize <## value> - Set the final zone size");
SendReply(arg, "shrink strength <## value> - Set the radiation strength (rads per second)");
SendReply(arg, "shrink time <## value> - Set the time it takes to shrink (in seconds)");
return;
}
switch (arg.Args[0].ToLower())
{
case "on":
if (arg.Args.Length >= 2)
{
object position = null;
if (arg.Args.Length > 2)
{
float x;
float z;
if (float.TryParse(arg.Args[1], out x) && float.TryParse(arg.Args[2], out z))
{
Vector3 temp = new Vector3(x, 0, z);
float height = TerrainMeta.HeightMap.GetHeight((Vector3)temp);
position = new Vector3(x, height, z);
}
}
if (position is Vector3)
{
CreateShrinkZone((Vector3)position, Configuration.InitialZoneSize, Configuration.ShrinkTime);
SendReply(arg, "Zone Created!");
return;
}
}
else
{
SendReply(arg, "/shrink on me\n/shrink on <x> <z>");
return;
}
return;
case "stop":
foreach (var zone in activeZones)
{
UnityEngine.Object.DestroyImmediate(zone.Value.gameObject);
Interface.CallHook("RadzoneEnd", zone.Key);
}
activeZones.Clear();
SendReply(arg, msg("All zones destroyed"));
return;
case "buffer":
if (arg.Args.Length == 2)
{
float value;
if (float.TryParse(arg.Args[1], out value))
{
Configuration.RadiationBuffer = value;
SaveConfig();
SendReply(arg, string.Format(msg("Radiation buffer set to : {0}"), value));
}
else SendReply(arg, msg("You must enter a number value"));
}
else SendReply(arg, msg("shrink buffer <##>"));
return;
case "startsize":
if (arg.Args.Length == 2)
{
float value;
if (float.TryParse(arg.Args[1], out value))
{
Configuration.InitialZoneSize = value;
SaveConfig();
SendReply(arg, string.Format(msg("Initial size set to : {0}"), value));
}
else SendReply(arg, msg("You must enter a number value"));
}
else SendReply(arg, msg("shrink startsize <##>"));
return;
case "endsize":
if (arg.Args.Length == 2)
{
float value;
if (float.TryParse(arg.Args[1], out value))
{
Configuration.FinalZoneSize = value;
SaveConfig();
SendReply(arg, string.Format(msg("Final size set to : {0}"), value));
}
else SendReply(arg, msg("You must enter a number value"));
}
else SendReply(arg, msg("shrink endsize <##>"));
return;
case "strength":
if (arg.Args.Length == 2)
{
float value;
if (float.TryParse(arg.Args[1], out value))
{
Configuration.RadiationStrength = value;
SaveConfig();
SendReply(arg, string.Format(msg("Radiation strength set to : {0}"), value));
}
else SendReply(arg, msg("You must enter a number value"));
}
else SendReply(arg, msg("shrink strength <##>"));
return;
case "time":
if (arg.Args.Length == 2)
{
float value;
if (float.TryParse(arg.Args[1], out value))
{
Configuration.ShrinkTime = value;
SaveConfig();
SendReply(arg, string.Format(msg("Shrink time set to : {0}"), value));
}
else SendReply(arg, msg("You must enter a number value"));
}
else SendReply(arg, msg("shrink time <##>"));
return;
default:
break;
}
}
#endregion
#region Config
private static ConfigData Configuration;
private class ConfigData
{
public float RadiationBuffer { get; set; }
public float FinalZoneSize { get; set; }
public float InitialZoneSize { get; set; }
public float ShrinkTime { get; set; }
public float RadiationStrength { get; set; }
public int DomeShade { get; set; }
public Oxide.Core.VersionNumber Version { get; set; }
}
protected override void LoadConfig()
{
base.LoadConfig();
Configuration = Config.ReadObject<ConfigData>();
if (Configuration.Version < Version)
UpdateConfigValues();
Config.WriteObject(Configuration, true);
}
protected override void LoadDefaultConfig() => Configuration = GetBaseConfig();
private ConfigData GetBaseConfig()
{
return new ConfigData
{
FinalZoneSize = 20,
InitialZoneSize = 150,
RadiationBuffer = 50,
RadiationStrength = 40,
ShrinkTime = 120,
DomeShade = 4,
Version = Version
};
}
protected override void SaveConfig() => Config.WriteObject(Configuration, true);
private void UpdateConfigValues()
{
PrintWarning("Config update detected! Updating config values...");
if (Configuration.Version < new VersionNumber(0, 1, 4))
Configuration.DomeShade = 4;
Configuration.Version = Version;
PrintWarning("Config update completed!");
}
#endregion
#region Localization
private string msg(string key, string playerId = null) => lang.GetMessage(key, this, playerId);
private Dictionary<string, string> messages = new Dictionary<string, string>
{
{"Radiation strength set to : {0}","Radiation strength set to : {0}" },
{"You must enter a number value","You must enter a number value" },
{"Shrink time set to : {0}","Shrink time set to : {0}" },
{"Final size set to : {0}","Final size set to : {0}" },
{"Initial size set to : {0}","Initial size set to : {0}" },
{"Radiation buffer set to : {0}","Radiation buffer set to : {0}" },
{"Zone Created!","Zone Created!" },
{"/shrink on me - Starts a shrinking rad zone on your position","/shrink on me - Starts a shrinking rad zone on your position" },
{"/shrink on <x> <z> - Starts a shrinking rad zone on the specified position","/shrink on <x> <z> - Starts a shrinking rad zone on the specified position" },
{"/shrink buffer <## value> - Set the radiation buffer size","/shrink buffer <## value> - Set the radiation buffer size" },
{"/shrink startsize <## value> - Set the initial zone size","/shrink startsize <## value> - Set the initial zone size" },
{"/shrink endsize <## value> - Set the final zone size","/shrink endsize <## value> - Set the final zone size" },
{"/shrink strength <## value> - Set the radiation strength (rads per second)","/shrink strength <## value> - Set the radiation strength (rads per second)" },
{"/shrink time <## value> - Set the time it takes to shrink (in seconds)","/shrink time <## value> - Set the time it takes to shrink (in seconds)" },
{"All zones destroyed","All zones destroyed" }
};
#endregion
}
}