diff --git a/defaults/oxide/config/HumanNPC.json b/defaults/oxide/config/HumanNPC.json
index 26048bfb..d487d071 100644
--- a/defaults/oxide/config/HumanNPC.json
+++ b/defaults/oxide/config/HumanNPC.json
@@ -1,4 +1,12 @@
-{
- "Chat": "{0}: ",
- "Place Npc in teams": true
+{
+ "Settings": {
+ "Chat": "{0}: ",
+ "NpcInTeams": false,
+ "NpcUseRadius": 5.0
+ },
+ "Version": {
+ "Major": 0,
+ "Minor": 3,
+ "Patch": 52
+ }
}
\ No newline at end of file
diff --git a/defaults/oxide/config/MonumentsRecycler.json b/defaults/oxide/config/MonumentsRecycler.json
index a0af486e..80edb2d5 100644
--- a/defaults/oxide/config/MonumentsRecycler.json
+++ b/defaults/oxide/config/MonumentsRecycler.json
@@ -6,7 +6,7 @@
"Large Oil Rig - Recycler Position - Level 6": true,
"Small Oil Rig - Recycler Position - Level 3": true,
"Small Oil Rig - Recycler Position - Level 4": true,
- "Dome - Recycler": false,
+ "Dome - Recycler": true,
"Fishing Village - Recycler - Large": true,
"Fishing Village - Recycler - Small A": true,
"Fishing Village - Recycler - Small B": true
diff --git a/defaults/oxide/config/PathFinding.json b/defaults/oxide/config/PathFinding.json
new file mode 100644
index 00000000..c5a759a5
--- /dev/null
+++ b/defaults/oxide/config/PathFinding.json
@@ -0,0 +1,3 @@
+{
+ "Max Depth": 5000
+}
\ No newline at end of file
diff --git a/defaults/oxide/plugins/BradleyGuards.cs b/defaults/oxide/plugins/BradleyGuards.cs
index 5c3f25cf..479de80a 100644
--- a/defaults/oxide/plugins/BradleyGuards.cs
+++ b/defaults/oxide/plugins/BradleyGuards.cs
@@ -1,7 +1,6 @@
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Linq;
using System;
-using Rust;
using Oxide.Core.Plugins;
using Oxide.Core;
using UnityEngine;
@@ -11,16 +10,16 @@
namespace Oxide.Plugins
{
- [Info("Bradley Guards", "Bazz3l", "1.3.6")]
- [Description("Calls reinforcements when bradley is destroyed at launch site.")]
+ [Info("Bradley Guards", "Bazz3l", "1.3.7")]
+ [Description("Call in armed reinforcements when bradley is destroyed at launch site.")]
public class BradleyGuards : RustPlugin
{
[PluginReference] Plugin Kits;
-
+
#region Fields
- private const string Ch47Prefab = "assets/prefabs/npc/ch47/ch47scientists.entity.prefab";
- private const string LandingName = "BradleyLandingZone";
+ private const string CH47_PREFAB = "assets/prefabs/npc/ch47/ch47scientists.entity.prefab";
+ private const string LANDING_NAME = "BradleyLandingZone";
private readonly HashSet _npcs = new HashSet();
private CH47HelicopterAIController _chinook;
@@ -37,7 +36,7 @@ public class BradleyGuards : RustPlugin
#region Config
- protected override void LoadDefaultConfig() => _config = GetDefaultConfig();
+ protected override void LoadDefaultConfig() => _config = PluginConfig.DefaultConfig();
protected override void LoadConfig()
{
@@ -51,48 +50,21 @@ protected override void LoadConfig()
{
throw new JsonException();
}
+
+ if (_config.ToDictionary().Keys
+ .SequenceEqual(Config.ToDictionary(x => x.Key, x => x.Value).Keys)) return;
}
catch
{
- LoadDefaultConfig();
+ PrintWarning("Loaded default config, please check your configuration file for errors.");
- SaveConfig();
-
- PrintWarning("Loaded default configuration file.");
+ LoadDefaultConfig();
}
}
protected override void SaveConfig() => Config.WriteObject(_config, true);
- private PluginConfig GetDefaultConfig()
- {
- return new PluginConfig
- {
- ChatIcon = 0,
- APCHealth = 1000f,
- APCCrates = 4,
- NPCAmount = 6,
- InstantCrates = true,
- GuardSettings = new List {
- new GuardSetting
- {
- Name = "Heavy Gunner",
- Health = 300f,
- MaxRoamRadius = 80f,
- MaxAggressionRange = 200f,
- },
- new GuardSetting
- {
- Name = "Light Gunner",
- Health = 200f,
- MaxRoamRadius = 80f,
- MaxAggressionRange = 150f,
- }
- }
- };
- }
-
- private class PluginConfig
+ class PluginConfig
{
[JsonProperty(PropertyName = "ChatIcon (chat icon SteamID64)")]
public ulong ChatIcon;
@@ -108,12 +80,49 @@ private class PluginConfig
[JsonProperty(PropertyName = "InstantCrates (unlock crates when guards are eliminated)")]
public bool InstantCrates;
+
+ [JsonProperty(PropertyName = "DisableChinookDamage (should chinook be able to take damage)")]
+ public bool DisableChinookDamage;
[JsonProperty(PropertyName = "GuardSettings (create different types of guards must contain atleast 1)")]
public List GuardSettings;
+
+ public static PluginConfig DefaultConfig()
+ {
+ return new PluginConfig
+ {
+ ChatIcon = 0,
+ APCHealth = 1000f,
+ APCCrates = 4,
+ NPCAmount = 6,
+ InstantCrates = true,
+ GuardSettings = new List {
+ new GuardSetting
+ {
+ Name = "Heavy Gunner",
+ Health = 300f,
+ MaxRoamRadius = 80f,
+ MaxAggressionRange = 200f,
+ },
+ new GuardSetting
+ {
+ Name = "Light Gunner",
+ Health = 200f,
+ MaxRoamRadius = 80f,
+ MaxAggressionRange = 150f,
+ }
+ }
+ };
+ }
+
+ public string ToJson() =>
+ JsonConvert.SerializeObject(this);
+
+ public Dictionary ToDictionary() =>
+ JsonConvert.DeserializeObject>(ToJson());
}
- private class GuardSetting
+ class GuardSetting
{
[JsonProperty(PropertyName = "Name (custom display name)")]
public string Name;
@@ -144,90 +153,88 @@ private class GuardSetting
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary {
- {"EventStart", "Bradley Gaurds: Tank commander sent for reinforcements, fight for your life."},
- {"EventEnded", "Bradley Gaurds: Reinforcements have been eliminated, loot up fast."},
+ {"EventStart", "Bradley Guards: Tank commander sent for reinforcements, fight for your life."},
+ {"EventEnded", "Bradley Guards: Reinforcements have been eliminated, loot up fast."},
}, this);
}
- private void OnServerInitialized() => GetLandingPoint();
+ void OnServerInitialized() =>
+ GetLandingPoint();
- private void Unload() => CleanUp();
+ void Unload() =>
+ CleanUp();
- private void OnEntitySpawned(BradleyAPC bradley) => OnAPCSpawned(bradley);
+ void OnEntitySpawned(BradleyAPC bradley) =>
+ OnAPCSpawned(bradley);
- private void OnEntityDeath(BradleyAPC bradley, HitInfo info) => OnAPCDeath(bradley);
+ void OnEntityDeath(BradleyAPC bradley, HitInfo info) =>
+ OnAPCDeath(bradley);
- private void OnEntityDeath(NPCPlayerApex npc, HitInfo info) => OnNPCDeath(npc);
+ void OnEntityDeath(NPCPlayerApex npc, HitInfo info) =>
+ OnNPCDeath(npc);
- private void OnEntityKill(NPCPlayerApex npc) => OnNPCDeath(npc);
+ void OnEntityKill(NPCPlayerApex npc) =>
+ OnNPCDeath(npc);
+
+ object OnHelicopterAttacked(CH47HelicopterAIController heli, HitInfo info) =>
+ OnCH47Attacked(heli, info);
- private void OnFireBallDamage(FireBall fire, NPCPlayerApex npc, HitInfo info)
+ void OnFireBallDamage(FireBall fireball, NPCPlayerApex npc, HitInfo info)
{
- if (!(_npcs.Contains(npc) && info.Initiator is FireBall))
- {
- return;
- }
-
- info.damageTypes = new DamageTypeList();
+ if (!(_npcs.Contains(npc) && info.Initiator is FireBall)) return;
+
info.DoHitEffects = false;
info.damageTypes.ScaleAll(0f);
}
- private void OnEntityDismounted(BaseMountable mountable, NPCPlayerApex npc)
+ void OnEntityDismounted(BaseMountable mountable, NPCPlayerApex npc)
{
- if (!_npcs.Contains(npc))
- {
- return;
- }
-
- npc.SetFact(NPCPlayerApex.Facts.IsMounted, (byte) 0, true, true);
- npc.SetFact(NPCPlayerApex.Facts.WantsToDismount, (byte) 0, true, true);
- npc.SetFact(NPCPlayerApex.Facts.CanNotWieldWeapon, (byte) 0, true, true);
+ if (!_npcs.Contains(npc)) return;
+
npc.Resume();
+ npc.modelState.mounted = false;
+ npc.modelState.onground = true;
+ npc.SetFact(NPCPlayerApex.Facts.IsMounted, 0, true, true);
+ npc.SetFact(NPCPlayerApex.Facts.CanNotWieldWeapon, 0, true, true);
+ npc.InvokeRandomized(new Action(npc.RadioChatter), npc.RadioEffectRepeatRange.x, npc.RadioEffectRepeatRange.x, npc.RadioEffectRepeatRange.y - npc.RadioEffectRepeatRange.x);
}
#endregion
#region Core
- private void SpawnEvent()
+ void SpawnEvent()
{
- _chinook = GameManager.server.CreateEntity(Ch47Prefab, _chinookPosition, Quaternion.identity) as CH47HelicopterAIController;
+ _chinook = GameManager.server.CreateEntity(CH47_PREFAB, _chinookPosition, Quaternion.identity) as CH47HelicopterAIController;
_chinook.Spawn();
_chinook.SetLandingTarget(_landingPosition);
_chinook.SetMinHoverHeight(1.5f);
_chinook.CancelInvoke(new Action(_chinook.SpawnScientists));
- _chinook.GetOrAddComponent();
+ _chinook.GetOrAddComponent();
for (int i = 0; i < _config.NPCAmount - 1; i++)
{
- SpawnScientist(_chinook, _config.GuardSettings.GetRandom(), _chinook.transform.position + _chinook.transform.forward * 10f, _bradleyPosition);
+ SpawnScientist(_config.GuardSettings.GetRandom(), _chinook.transform.position + _chinook.transform.forward * 10f, _bradleyPosition);
}
for (int j = 0; j < 1; j++)
{
- SpawnScientist(_chinook, _config.GuardSettings.GetRandom(), _chinook.transform.position - _chinook.transform.forward * 15f, _bradleyPosition);
+ SpawnScientist(_config.GuardSettings.GetRandom(), _chinook.transform.position - _chinook.transform.forward * 15f, _bradleyPosition);
}
MessageAll("EventStart");
}
- private void SpawnScientist(CH47HelicopterAIController chinook, GuardSetting settings, Vector3 position, Vector3 eventPos)
+ void SpawnScientist(GuardSetting settings, Vector3 position, Vector3 eventPos)
{
- NPCPlayerApex npc = GameManager.server.CreateEntity(chinook.scientistPrefab.resourcePath, position, Quaternion.identity) as NPCPlayerApex;
-
- if (npc == null)
- {
- return;
- }
+ NPCPlayerApex npc = GameManager.server.CreateEntity(_chinook.scientistPrefab.resourcePath, position, Quaternion.identity) as NPCPlayerApex;
+ if (npc == null) return;
npc.Spawn();
- npc.Mount((BaseMountable) chinook);
-
+ npc.Mount(_chinook);
npc.RadioEffect = new GameObjectRef();
npc.DeathEffect = new GameObjectRef();
npc.displayName = settings.Name;
- npc.startHealth = settings.Health;
npc.damageScale = settings.DamageScale;
npc.Stats.VisionRange = settings.MaxAggressionRange + 3f;
npc.Stats.DeaggroRange = settings.MaxAggressionRange + 2f;
@@ -237,45 +244,41 @@ private void SpawnScientist(CH47HelicopterAIController chinook, GuardSetting set
npc.Stats.Hostility = 1f;
npc.Stats.Defensiveness = 1f;
npc.Stats.OnlyAggroMarkedTargets = true;
+ npc.startHealth = settings.Health;
npc.InitializeHealth(settings.Health, settings.Health);
npc.InitFacts();
- (npc as Scientist).LootPanelName = settings.Name;
+ RenameNPC(npc as Scientist, settings.Name);
+
+ npc.GetOrAddComponent()
+ ?.SetDestination(GetRandomPoint(eventPos, 6f));
_npcs.Add(npc);
- npc.Invoke(() => {
- GiveKit(npc, settings.KitEnabled, settings.KitName);
+ npc.Invoke(() => GiveKit(npc, settings.KitEnabled, settings.KitName), 2f);
+ }
- npc.gameObject.AddComponent().SetDestination(GetRandomPoint(eventPos, 6f));
- }, 2f);
+ void RenameNPC(Scientist npc, string name)
+ {
+ npc.displayName = name;
+ npc.LootPanelName = name;
}
- private void GiveKit(NPCPlayerApex npc, bool kitEnabled, string kitName)
+ void GiveKit(NPCPlayerApex npc, bool kitEnabled, string kitName)
{
if (kitEnabled && !string.IsNullOrEmpty(kitName))
{
npc.inventory.Strip();
-
Interface.Oxide.CallHook("GiveKit", npc, kitName);
-
return;
}
ItemManager.CreateByName("scientistsuit_heavy", 1, 0)?.MoveToContainer(npc.inventory.containerWear);
}
- private void OnNPCDeath(NPCPlayerApex npc)
+ void OnNPCDeath(NPCPlayerApex npc)
{
- if (!_npcs.Remove(npc))
- {
- return;
- }
-
- if (_npcs.Count > 0)
- {
- return;
- }
+ if (!_npcs.Remove(npc) || _npcs.Count > 0) return;
if (_config.InstantCrates)
{
@@ -286,15 +289,12 @@ private void OnNPCDeath(NPCPlayerApex npc)
MessageAll("EventEnded");
}
- private void OnAPCSpawned(BradleyAPC bradley)
+ void OnAPCSpawned(BradleyAPC bradley)
{
Vector3 position = bradley.transform.position;
- if (!IsInBounds(position))
- {
- return;
- }
-
+ if (!IsInBounds(position)) return;
+
bradley.maxCratesToSpawn = _config.APCCrates;
bradley._maxHealth = bradley._health = _config.APCHealth;
bradley.health = bradley._maxHealth;
@@ -302,26 +302,27 @@ private void OnAPCSpawned(BradleyAPC bradley)
ClearGuards();
}
- private void OnAPCDeath(BradleyAPC bradley)
+ void OnAPCDeath(BradleyAPC bradley)
{
- if (bradley == null || bradley.IsDestroyed)
- {
- return;
- }
+ if (bradley == null || bradley.IsDestroyed) return;
Vector3 position = bradley.transform.position;
- if (!IsInBounds(position))
- {
- return;
- }
+ if (!IsInBounds(position)) return;
_bradleyPosition = position;
SpawnEvent();
}
- private void RemoveFlames()
+ object OnCH47Attacked(CH47HelicopterAIController heli, HitInfo info)
+ {
+ if (heli == null || !_config.DisableChinookDamage) return null;
+ if (heli == _chinook) return true;
+ return null;
+ }
+
+ void RemoveFlames()
{
List entities = Pool.GetList();
@@ -329,15 +330,16 @@ private void RemoveFlames()
foreach (FireBall fireball in entities)
{
- if (!(fireball.IsValid() && !fireball.IsDestroyed)) continue;
-
- NextFrame(() => fireball.Kill());
+ if (fireball.IsValid() && !fireball.IsDestroyed)
+ {
+ fireball.Kill();
+ }
}
Pool.FreeList(ref entities);
}
-
- private void UnlockCrates()
+
+ void UnlockCrates()
{
List entities = Pool.GetList();
@@ -362,34 +364,29 @@ private void UnlockCrates()
Pool.FreeList(ref entities);
}
- private void CreateLandingZone()
+ void CreateLandingZone()
{
- _landingZone = new GameObject(LandingName) {
- layer = 16,
- transform = {
- position = _landingPosition,
- rotation = _landingRotation
- }
- }.AddComponent();
+ GameObject gameObject = new GameObject(LANDING_NAME);
+ gameObject.transform.SetPositionAndRotation(_landingPosition, _landingRotation);
+ _landingZone = gameObject.AddComponent();
}
- private void CleanUp()
+ void CleanUp()
{
ClearGuards();
ClearZones();
}
-
- private void ClearZones()
+
+ void ClearZones()
{
- if (_landingZone != null)
- {
- UnityEngine.Object.Destroy(_landingZone.gameObject);
- }
-
+ if (_landingZone == null) return;
+
+ UnityEngine.Object.Destroy(_landingZone.gameObject);
+
_landingZone = null;
}
- private void ClearGuards()
+ void ClearGuards()
{
for (int i = 0; i < _npcs.Count; i++)
{
@@ -404,7 +401,7 @@ private void ClearGuards()
_npcs.Clear();
}
- private void GetLandingPoint()
+ void GetLandingPoint()
{
foreach (MonumentInfo monument in UnityEngine.Object.FindObjectsOfType())
{
@@ -413,135 +410,131 @@ private void GetLandingPoint()
SetLandingPoint(monument);
}
}
-
- private void SetLandingPoint(MonumentInfo monument)
+
+ void SetLandingPoint(MonumentInfo monument)
{
_monumentPosition = monument.transform.position;
-
+
_landingRotation = monument.transform.rotation;
- _landingPosition = monument.transform.position + monument.transform.right * 125f;
+ _landingPosition = _monumentPosition + monument.transform.right * 125f;
_landingPosition.y = TerrainMeta.HeightMap.GetHeight(_landingPosition);
- _chinookPosition = monument.transform.position + -monument.transform.right * 250f;
+ _chinookPosition = _monumentPosition + -monument.transform.right * 250f;
_chinookPosition.y += 150f;
_hasLaunch = true;
CreateLandingZone();
}
-
- private bool IsInBounds(Vector3 position)
- {
- return _hasLaunch && Vector3.Distance(_monumentPosition, position) <= 300f;
- }
+ bool IsInBounds(Vector3 position) => _hasLaunch && Vector3.Distance(_monumentPosition, position) <= 300f;
+
#endregion
#region Component
-
- private class CustomNavigation : MonoBehaviour
+
+ class NPCNavigationComponent : MonoBehaviour
{
- private NPCPlayerApex _npc;
- private Vector3 _targetPoint;
+ NPCPlayerApex _npc;
+ Vector3 _destination;
private void Awake()
{
_npc = gameObject.GetComponent();
- InvokeRepeating(nameof(Relocate), 0f, 5f);
+ InvokeRepeating(nameof(DoMove), 5f, 5f);
}
private void OnDestroy()
{
CancelInvoke();
-
+
if (_npc.IsValid() && !_npc.IsDestroyed)
{
_npc.Kill();
}
}
- public void SetDestination(Vector3 position)
+ public void SetDestination(Vector3 destination)
{
- _targetPoint = position;
+ _destination = destination;
}
- private void Relocate()
+ private void DoMove()
{
- if (_npc == null || _npc.IsDestroyed)
- {
- return;
- }
+ if (!(_npc.IsValid() && !_npc.IsDestroyed)) return;
+
+ if (_npc.isMounted) return;
- if (_npc.isMounted)
+ if (IsOutOfRange() && _npc.AttackTarget != null)
{
- return;
+ _npc.AttackTarget = null;
}
- if (!(_npc.AttackTarget == null || IsOutOfBounds()))
- {
- return;
- }
-
- if (_npc.IsStuck)
+ if (_npc.AttackTarget != null)
{
- DoWarp();
+ _npc.NeverMove = false;
}
- if (_npc.GetNavAgent == null || !_npc.GetNavAgent.isOnNavMesh)
- {
- _npc.finalDestination = _targetPoint;
- }
- else
+ if (_npc.AttackTarget == null)
{
- _npc.GetNavAgent.SetDestination(_targetPoint);
- _npc.IsDormant = false;
- }
+ _npc.NeverMove = true;
- _npc.IsStopped = false;
- _npc.Destination = _targetPoint;
- }
+ if (_npc.IsStuck)
+ {
+ Warp();
+ }
- private bool IsOutOfBounds()
- {
- return _npc.AttackTarget != null && Vector3.Distance(transform.position, _targetPoint) > _npc.Stats.MaxRoamRange;
+ if (_npc.GetNavAgent == null || !_npc.GetNavAgent.isOnNavMesh)
+ {
+ _npc.finalDestination = _destination;
+ }
+ else
+ {
+ _npc.GetNavAgent.SetDestination(_destination);
+ }
+
+ _npc.IsStopped = false;
+ _npc.Destination = _destination;
+ }
}
- private void DoWarp()
+ private void Warp()
{
_npc.Pause();
- _npc.ServerPosition = _targetPoint;
- _npc.GetNavAgent.Warp(_targetPoint);
+ _npc.ServerPosition = _destination;
+ _npc.GetNavAgent.Warp(_destination);
_npc.stuckDuration = 0f;
_npc.IsStuck = false;
_npc.Resume();
}
+
+ private bool IsOutOfRange() =>
+ Vector3.Distance(transform.position, _destination) > _npc.Stats.MaxRoamRange;
}
- private class CustomCh47 : MonoBehaviour
+ class CH47NavigationComponent : MonoBehaviour
{
- private CH47HelicopterAIController _chinook;
+ CH47HelicopterAIController _chinook;
- private void Awake()
+ void Awake()
{
_chinook = GetComponent();
InvokeRepeating(nameof(CheckDropped), 5f, 5f);
}
- private void OnDestroy()
+ void OnDestroy()
{
CancelInvoke();
-
- _chinook.Invoke(new Action(_chinook.DelayedKill), 10f);
+
+ if (_chinook.IsValid() && !_chinook.IsDestroyed)
+ _chinook.Invoke(_chinook.DelayedKill, 10f);
}
- private void CheckDropped()
+ void CheckDropped()
{
- if (_chinook == null || _chinook.IsDestroyed || _chinook.HasAnyPassengers())
- {
- return;
- }
+ if (_chinook.HasAnyPassengers()) return;
Destroy(this);
}
@@ -551,16 +544,16 @@ private void CheckDropped()
#region Helpers
- private string Lang(string key, string id = null, params object[] args) => string.Format(lang.GetMessage(key, this, id), args);
+ string Lang(string key, string id = null, params object[] args) =>
+ string.Format(lang.GetMessage(key, this, id), args);
- private void MessageAll(string key) => Server.Broadcast(Lang(key, null), _config.ChatIcon);
+ void MessageAll(string key) =>
+ Server.Broadcast(Lang(key, null), _config.ChatIcon);
- private Vector3 GetRandomPoint(Vector3 position, float radius)
+ Vector3 GetRandomPoint(Vector3 position, float radius)
{
Vector3 pos = position + UnityEngine.Random.onUnitSphere * radius;
-
pos.y = TerrainMeta.HeightMap.GetHeight(pos);
-
return pos;
}
diff --git a/defaults/oxide/plugins/CopyPaste.cs b/defaults/oxide/plugins/CopyPaste.cs
index 8a0248b6..e722d081 100644
--- a/defaults/oxide/plugins/CopyPaste.cs
+++ b/defaults/oxide/plugins/CopyPaste.cs
@@ -12,10 +12,14 @@
using Facepunch;
using Newtonsoft.Json;
using Oxide.Core;
+using Oxide.Core.Libraries.Covalence;
+using Oxide.Game.Rust.Libraries.Covalence;
using ProtoBuf;
using UnityEngine;
using Graphics = System.Drawing.Graphics;
+// ReSharper disable SpecifyACultureInStringConversionExplicitly
+
/*
* CREDITS
*
@@ -24,15 +28,20 @@
* bsdinis - Wire fix
* nivex - Ownership option, sign fix
* DezLife - CCTV fix
+ * Wulf - Skipping 4.1.24 :D
*
*/
namespace Oxide.Plugins
{
- [Info("Copy Paste", "misticos", "4.1.27")] // Wulf skipped 24 :(
+ [Info("Copy Paste", "misticos", "4.1.31")]
[Description("Copy and paste buildings to save them or move them")]
- public class CopyPaste : RustPlugin
+ public class CopyPaste : CovalencePlugin
{
+ // ReSharper disable once Unity.IncorrectMonoBehaviourInstantiation
+ private readonly Item _emptyItem = new Item { info = new ItemDefinition() };
+ private readonly IPlayer _consolePlayer = new RustConsolePlayer();
+
private int _copyLayer =
LayerMask.GetMask("Construction", "Prevent Building", "Construction Trigger", "Trigger", "Deployed",
"Default", "Ragdoll"),
@@ -46,7 +55,6 @@ public class CopyPaste : RustPlugin
_pastePermission = "copypaste.paste",
_pastebackPermission = "copypaste.pasteback",
_undoPermission = "copypaste.undo",
- _serverId = "Server",
_subDirectory = "copypaste/";
private Dictionary>> _lastPastes =
@@ -55,28 +63,28 @@ public class CopyPaste : RustPlugin
private Dictionary _signSizes = new Dictionary
{
//{"spinner.wheel.deployed", new SignSize(512, 512)},
- {"sign.pictureframe.landscape", new SignSize(256, 128)},
- {"sign.pictureframe.tall", new SignSize(128, 512)},
- {"sign.pictureframe.portrait", new SignSize(128, 256)},
- {"sign.pictureframe.xxl", new SignSize(1024, 512)},
- {"sign.pictureframe.xl", new SignSize(512, 512)},
- {"sign.small.wood", new SignSize(128, 64)},
- {"sign.medium.wood", new SignSize(256, 128)},
- {"sign.large.wood", new SignSize(256, 128)},
- {"sign.huge.wood", new SignSize(512, 128)},
- {"sign.hanging.banner.large", new SignSize(64, 256)},
- {"sign.pole.banner.large", new SignSize(64, 256)},
- {"sign.post.single", new SignSize(128, 64)},
- {"sign.post.double", new SignSize(256, 256)},
- {"sign.post.town", new SignSize(256, 128)},
- {"sign.post.town.roof", new SignSize(256, 128)},
- {"sign.hanging", new SignSize(128, 256)},
- {"sign.hanging.ornate", new SignSize(256, 128)},
- {"sign.neon.xl.animated", new SignSize(250, 250)},
- {"sign.neon.xl", new SignSize(250, 250)},
- {"sign.neon.125x215.animated", new SignSize(215, 125)},
- {"sign.neon.125x215", new SignSize(215, 125)},
- {"sign.neon.125x125", new SignSize(125, 125)},
+ { "sign.pictureframe.landscape", new SignSize(256, 128) },
+ { "sign.pictureframe.tall", new SignSize(128, 512) },
+ { "sign.pictureframe.portrait", new SignSize(128, 256) },
+ { "sign.pictureframe.xxl", new SignSize(1024, 512) },
+ { "sign.pictureframe.xl", new SignSize(512, 512) },
+ { "sign.small.wood", new SignSize(128, 64) },
+ { "sign.medium.wood", new SignSize(256, 128) },
+ { "sign.large.wood", new SignSize(256, 128) },
+ { "sign.huge.wood", new SignSize(512, 128) },
+ { "sign.hanging.banner.large", new SignSize(64, 256) },
+ { "sign.pole.banner.large", new SignSize(64, 256) },
+ { "sign.post.single", new SignSize(128, 64) },
+ { "sign.post.double", new SignSize(256, 256) },
+ { "sign.post.town", new SignSize(256, 128) },
+ { "sign.post.town.roof", new SignSize(256, 128) },
+ { "sign.hanging", new SignSize(128, 256) },
+ { "sign.hanging.ornate", new SignSize(256, 128) },
+ { "sign.neon.xl.animated", new SignSize(250, 250) },
+ { "sign.neon.xl", new SignSize(250, 250) },
+ { "sign.neon.125x215.animated", new SignSize(215, 125) },
+ { "sign.neon.125x215", new SignSize(215, 125) },
+ { "sign.neon.125x125", new SignSize(125, 125) },
};
private List _checkSlots = new List
@@ -249,10 +257,9 @@ private void OnServerInitialized()
private object TryCopyFromSteamId(ulong userId, string filename, string[] args, Action callback = null)
{
- var player = BasePlayer.FindByID(userId);
-
+ var player = players.FindPlayerById(userId.ToString())?.Object as BasePlayer;
if (player == null)
- return Lang("NOT_FOUND_PLAYER", userId.ToString());
+ return Lang("NOT_FOUND_PLAYER");
RaycastHit hit;
@@ -260,29 +267,29 @@ private object TryCopyFromSteamId(ulong userId, string filename, string[] args,
return Lang("NO_ENTITY_RAY", player.UserIDString);
return TryCopy(hit.point, hit.GetEntity().GetNetworkRotation().eulerAngles, filename,
- DegreeToRadian(player.GetNetworkRotation().eulerAngles.y), args, player, callback);
+ DegreeToRadian(player.GetNetworkRotation().eulerAngles.y), args, player.IPlayer, callback);
}
private object TryPasteFromSteamId(ulong userId, string filename, string[] args, Action callback = null)
{
- var player = BasePlayer.FindByID(userId);
-
+ var player = players.FindPlayerById(userId.ToString())?.Object as BasePlayer;
if (player == null)
- return Lang("NOT_FOUND_PLAYER", player.UserIDString);
+ return Lang("NOT_FOUND_PLAYER");
RaycastHit hit;
if (!Physics.Raycast(player.eyes.HeadRay(), out hit, 1000f, _rayPaste))
return Lang("NO_ENTITY_RAY", player.UserIDString);
- return TryPaste(hit.point, filename, player, DegreeToRadian(player.GetNetworkRotation().eulerAngles.y),
+ return TryPaste(hit.point, filename, player.IPlayer,
+ DegreeToRadian(player.GetNetworkRotation().eulerAngles.y),
args, callback: callback);
}
private object TryPasteFromVector3(Vector3 pos, float rotationCorrection, string filename, string[] args,
Action callback = null)
{
- return TryPaste(pos, filename, null, rotationCorrection, args, callback: callback);
+ return TryPaste(pos, filename, _consolePlayer, rotationCorrection, args, callback: callback);
}
#endregion
@@ -293,7 +300,7 @@ private object CheckCollision(HashSet> entities, Vect
{
foreach (var entityobj in entities)
{
- if (Physics.CheckSphere((Vector3) entityobj["position"], radius, _copyLayer))
+ if (Physics.CheckSphere((Vector3)entityobj["position"], radius, _copyLayer))
return Lang("BLOCKING_PASTE");
}
@@ -304,59 +311,38 @@ private bool CheckPlaced(string prefabname, Vector3 pos, Quaternion rot)
{
const float maxDiff = 0.01f;
- var ents = new List();
- Vis.Entities(pos, maxDiff, ents);
-
- foreach (var ent in ents)
+ var ents = Pool.GetList();
+ try
{
- if (ent.PrefabName != prefabname)
- continue;
-
- if (Vector3.Distance(ent.transform.position, pos) > maxDiff)
- {
- continue;
- }
+ Vis.Entities(pos, maxDiff, ents);
- if (Vector3.Distance(ent.transform.rotation.eulerAngles, rot.eulerAngles) > maxDiff)
+ foreach (var ent in ents)
{
- continue;
- }
-
- return true;
- }
-
- return false;
- }
-
- private object CmdPasteBack(BasePlayer player, string[] args)
- {
- var userIdString = player == null ? _serverId : player.UserIDString;
-
- if (args.Length < 1)
- return Lang("SYNTAX_PASTEBACK", userIdString);
-
- var success = TryPasteBack(args[0], player, args.Skip(1).ToArray());
-
- if (success is string)
- return (string) success;
-
- return true;
- }
+ if (ent.PrefabName != prefabname)
+ continue;
- private object CmdUndo(string userIdString, string[] args)
- {
- var player = BasePlayer.Find(userIdString);
- if (!_lastPastes.ContainsKey(userIdString))
- return Lang("NO_PASTED_STRUCTURE", userIdString);
+ if (Vector3.Distance(ent.transform.position, pos) > maxDiff)
+ {
+ continue;
+ }
- var entities = new HashSet(_lastPastes[userIdString].Pop().ToList());
+ if (Vector3.Distance(ent.transform.rotation.eulerAngles, rot.eulerAngles) > maxDiff)
+ {
+ continue;
+ }
- UndoLoop(entities, player);
+ return true;
+ }
- return true;
+ return false;
+ }
+ finally
+ {
+ Pool.FreeList(ref ents);
+ }
}
- private void UndoLoop(HashSet entities, BasePlayer player, int count = 0)
+ private void UndoLoop(HashSet entities, IPlayer player, int count = 0)
{
foreach (var storageContainer in entities.OfType().Where(x => !x.IsDestroyed))
{
@@ -378,6 +364,12 @@ private void UndoLoop(HashSet entities, BasePlayer player, int count
ore.CleanupBonus();
}
+ var io = p as IOEntity;
+ if (io != null)
+ {
+ io.ClearConnections();
+ }
+
if (p != null && !p.IsDestroyed)
p.Kill();
});
@@ -385,10 +377,7 @@ private void UndoLoop(HashSet entities, BasePlayer player, int count
// If it gets stuck in infinite loop break the loop.
if (count != 0 && entities.Count != 0 && entities.Count == count)
{
- if (player != null)
- SendReply(player, "Undo cancelled because of infinite loop.");
- else
- Puts("Undo cancelled because of infinite loop.");
+ player.Reply("Undo cancelled because of infinite loop.");
return;
}
@@ -396,18 +385,15 @@ private void UndoLoop(HashSet entities, BasePlayer player, int count
NextTick(() => UndoLoop(entities, player, entities.Count));
else
{
- if (player != null)
- SendReply(player, Lang("UNDO_SUCCESS", player.UserIDString));
- else
- Puts(Lang("UNDO_SUCCESS"));
+ player.Reply(Lang("UNDO_SUCCESS", player.Id));
- if (_lastPastes[player?.UserIDString ?? _serverId].Count == 0)
- _lastPastes.Remove(player?.UserIDString ?? _serverId);
+ if (_lastPastes.ContainsKey(player.Id) && _lastPastes[player.Id].Count == 0)
+ _lastPastes.Remove(player.Id);
}
}
private void Copy(Vector3 sourcePos, Vector3 sourceRot, string filename, float rotationCorrection,
- CopyMechanics copyMechanics, float range, bool saveTree, bool saveShare, bool eachToEach, BasePlayer player,
+ CopyMechanics copyMechanics, float range, bool saveTree, bool saveShare, bool eachToEach, IPlayer player,
Action callback)
{
var currentLayer = _copyLayer;
@@ -428,13 +414,13 @@ private void Copy(Vector3 sourcePos, Vector3 sourceRot, string filename, float r
SourcePos = sourcePos,
SourceRot = sourceRot,
Player = player,
+ BasePlayer = player.Object as BasePlayer,
Callback = callback
};
copyData.CheckFrom.Push(sourcePos);
NextTick(() => CopyLoop(copyData));
- ;
}
// Main loop for copy, will fetch all the data needed. Is called every tick untill copy is done (can't find any entities)
@@ -452,33 +438,43 @@ private void CopyLoop(CopyData copyData)
break;
var list = Pool.GetList();
- Vis.Entities(checkFrom.Pop(), copyData.Range, list, copyData.CurrentLayer);
-
- foreach (var entity in list)
+ try
{
- if (!houseList.Add(entity))
- continue;
+ Vis.Entities(checkFrom.Pop(), copyData.Range, list, copyData.CurrentLayer);
- if (copyMechanics == CopyMechanics.Building)
+ foreach (var entity in list)
{
- var buildingBlock = entity.GetComponentInParent();
+ if (!houseList.Add(entity))
+ continue;
- if (buildingBlock != null)
+ if (copyMechanics == CopyMechanics.Building)
{
- if (buildingId == 0)
- buildingId = buildingBlock.buildingID;
+ var buildingBlock = entity.GetComponentInParent();
- if (buildingId != buildingBlock.buildingID)
- continue;
+ if (buildingBlock != null)
+ {
+ if (buildingId == 0)
+ buildingId = buildingBlock.buildingID;
+
+ if (buildingId != buildingBlock.buildingID)
+ continue;
+ }
}
- }
- if (copyData.EachToEach)
- checkFrom.Push(entity.transform.position);
- if (entity.GetComponent() != null)
- continue;
- copyData.RawData.Add(EntityData(entity, entity.transform.position,
- entity.transform.rotation.eulerAngles / 57.29578f, copyData));
+ var transform = entity.transform;
+ if (copyData.EachToEach)
+ checkFrom.Push(transform.position);
+
+ if (entity.GetComponent() != null)
+ continue;
+
+ copyData.RawData.Add(EntityData(entity, transform.position,
+ transform.rotation.eulerAngles / 57.29578f, copyData));
+ }
+ }
+ finally
+ {
+ Pool.FreeList(ref list);
}
copyData.BuildingId = buildingId;
@@ -502,25 +498,25 @@ private void CopyLoop(CopyData copyData)
{
"position", new Dictionary
{
- {"x", sourcePos.x.ToString()},
- {"y", sourcePos.y.ToString()},
- {"z", sourcePos.z.ToString()}
+ { "x", sourcePos.x.ToString() },
+ { "y", sourcePos.y.ToString() },
+ { "z", sourcePos.z.ToString() }
}
},
- {"rotationy", copyData.SourceRot.y.ToString()},
- {"rotationdiff", copyData.RotCor.ToString()}
+ { "rotationy", copyData.SourceRot.y.ToString() },
+ { "rotationdiff", copyData.RotCor.ToString() }
};
datafile["entities"] = copyData.RawData;
datafile["protocol"] = new Dictionary
{
- {"items", 2},
- {"version", Version}
+ { "items", 2 },
+ { "version", Version }
};
Interface.Oxide.DataFileSystem.SaveDatafile(path);
- SendReply(copyData.Player, Lang("COPY_SUCCESS", copyData.Player.UserIDString, copyData.Filename));
+ copyData.Player.Reply(Lang("COPY_SUCCESS", copyData.Player.Id, copyData.Filename));
copyData.Callback?.Invoke();
@@ -530,7 +526,7 @@ private void CopyLoop(CopyData copyData)
private float DegreeToRadian(float angle)
{
- return (float) (Math.PI * angle / 180.0f);
+ return (float)(Math.PI * angle / 180.0f);
}
private Dictionary EntityData(BaseEntity entity, Vector3 entPos, Vector3 entRot,
@@ -542,28 +538,44 @@ private Dictionary EntityData(BaseEntity entity, Vector3 entPos,
var data = new Dictionary
{
- {"prefabname", entity.PrefabName},
- {"skinid", entity.skinID},
- {"flags", TryCopyFlags(entity)},
+ { "prefabname", entity.PrefabName },
+ { "skinid", entity.skinID },
+ { "flags", TryCopyFlags(entity) },
{
"pos", new Dictionary
{
- {"x", normalizedPos.x.ToString()},
- {"y", normalizedPos.y.ToString()},
- {"z", normalizedPos.z.ToString()}
+ { "x", normalizedPos.x.ToString() },
+ { "y", normalizedPos.y.ToString() },
+ { "z", normalizedPos.z.ToString() }
}
},
{
"rot", new Dictionary
{
- {"x", entRot.x.ToString()},
- {"y", entRot.y.ToString()},
- {"z", entRot.z.ToString()}
+ { "x", entRot.x.ToString() },
+ { "y", entRot.y.ToString() },
+ { "z", entRot.z.ToString() }
}
},
- {"ownerid", entity.OwnerID}
+ { "ownerid", entity.OwnerID }
};
+ var growableEntity = entity as GrowableEntity;
+ if (growableEntity != null)
+ {
+ var genes = GrowableGeneEncoding.EncodeGenesToInt(growableEntity.Genes);
+ if (genes > 0)
+ {
+ data.Add("genes", genes);
+ }
+
+ var perent = growableEntity.GetParentEntity();
+ if (perent != null)
+ {
+ data.Add("hasParent", true);
+ }
+ }
+
TryCopySlots(entity, data, copyData.SaveShare);
var buildingblock = entity as BuildingBlock;
@@ -582,12 +594,13 @@ private Dictionary EntityData(BaseEntity entity, Vector3 entPos,
{
var itemdata = new Dictionary
{
- {"condition", item.condition.ToString()},
- {"id", item.info.itemid},
- {"amount", item.amount},
- {"skinid", item.skin},
- {"position", item.position},
- {"blueprintTarget", item.blueprintTarget}
+ { "condition", item.condition.ToString() },
+ { "id", item.info.itemid },
+ { "amount", item.amount },
+ { "skinid", item.skin },
+ { "position", item.position },
+ { "blueprintTarget", item.blueprintTarget },
+ { "dataInt", item.instanceData?.dataInt ?? 0 }
};
if (!string.IsNullOrEmpty(item.text))
@@ -607,7 +620,7 @@ private Dictionary EntityData(BaseEntity entity, Vector3 entPos,
{
itemdata.Add("magazine", new Dictionary
{
- {magazine.ammoType.itemid.ToString(), magazine.contents}
+ { magazine.ammoType.itemid.ToString(), magazine.contents }
});
}
}
@@ -621,8 +634,8 @@ private Dictionary EntityData(BaseEntity entity, Vector3 entPos,
{
contents.Add(new Dictionary
{
- {"id", itemContains.info.itemid},
- {"amount", itemContains.amount}
+ { "id", itemContains.info.itemid },
+ { "amount", itemContains.amount }
});
}
@@ -644,12 +657,13 @@ private Dictionary EntityData(BaseEntity entity, Vector3 entPos,
{
var itemdata = new Dictionary
{
- {"condition", item.condition.ToString()},
- {"id", item.info.itemid},
- {"amount", item.amount},
- {"skinid", item.skin},
- {"position", item.position},
- {"blueprintTarget", item.blueprintTarget}
+ { "condition", item.condition.ToString() },
+ { "id", item.info.itemid },
+ { "amount", item.amount },
+ { "skinid", item.skin },
+ { "position", item.position },
+ { "blueprintTarget", item.blueprintTarget },
+ { "dataInt", item.instanceData?.dataInt ?? 0 }
};
if (!string.IsNullOrEmpty(item.text))
@@ -669,7 +683,7 @@ private Dictionary EntityData(BaseEntity entity, Vector3 entPos,
{
itemdata.Add("magazine", new Dictionary
{
- {magazine.ammoType.itemid.ToString(), magazine.contents}
+ { magazine.ammoType.itemid.ToString(), magazine.contents }
});
}
}
@@ -683,8 +697,8 @@ private Dictionary EntityData(BaseEntity entity, Vector3 entPos,
{
contents.Add(new Dictionary
{
- {"id", itemContains.info.itemid},
- {"amount", itemContains.amount}
+ { "id", itemContains.info.itemid },
+ { "amount", itemContains.amount }
});
}
@@ -702,12 +716,12 @@ private Dictionary EntityData(BaseEntity entity, Vector3 entPos,
{
data.Add("sign", new Dictionary
{
- {"locked", sign.IsLocked()}
+ { "locked", sign.IsLocked() }
});
- var signData = (Dictionary) data["sign"];
+ var signData = (Dictionary)data["sign"];
- for (int num = 0; num < sign.textureIDs.Length; num++)
+ for (var num = 0; num < sign.textureIDs.Length; num++)
{
var textureId = sign.textureIDs[num];
if (textureId == 0)
@@ -723,6 +737,13 @@ private Dictionary EntityData(BaseEntity entity, Vector3 entPos,
signData["amount"] = sign.textureIDs.Length;
}
+ var lights = entity as AdvancedChristmasLights;
+ if (lights != null)
+ {
+ data.Add("points", lights.points.Select(x => new { x.normal, x.point }));
+ data.Add("animationStyle", lights.animationStyle);
+ }
+
if (copyData.SaveShare)
{
var sleepingBag = entity as SleepingBag;
@@ -731,9 +752,9 @@ private Dictionary EntityData(BaseEntity entity, Vector3 entPos,
{
data.Add("sleepingbag", new Dictionary
{
- {"niceName", sleepingBag.niceName},
- {"deployerUserID", sleepingBag.deployerUserID},
- {"isPublic", sleepingBag.IsPublic()}
+ { "niceName", sleepingBag.niceName },
+ { "deployerUserID", sleepingBag.deployerUserID },
+ { "isPublic", sleepingBag.IsPublic() }
});
}
@@ -743,7 +764,7 @@ private Dictionary EntityData(BaseEntity entity, Vector3 entPos,
{
data.Add("cupboard", new Dictionary
{
- {"authorizedPlayers", cupboard.authorizedPlayers.Select(y => y.userid).ToList()}
+ { "authorizedPlayers", cupboard.authorizedPlayers.Select(y => y.userid).ToList() }
});
}
@@ -753,7 +774,7 @@ private Dictionary EntityData(BaseEntity entity, Vector3 entPos,
{
data.Add("autoturret", new Dictionary
{
- {"authorizedPlayers", autoTurret.authorizedPlayers.Select(p => p.userid).ToList()}
+ { "authorizedPlayers", autoTurret.authorizedPlayers.Select(p => p.userid).ToList() }
});
}
}
@@ -763,9 +784,9 @@ private Dictionary EntityData(BaseEntity entity, Vector3 entPos,
{
data.Add("cctv", new Dictionary
{
- {"yaw", cctvRc.yawAmount},
- {"pitch", cctvRc.pitchAmount},
- {"rcIdentifier", cctvRc.rcIdentifier}
+ { "yaw", cctvRc.yawAmount },
+ { "pitch", cctvRc.pitchAmount },
+ { "rcIdentifier", cctvRc.rcIdentifier }
});
}
@@ -779,21 +800,21 @@ private Dictionary EntityData(BaseEntity entity, Vector3 entPos,
{
sellOrders.Add(new Dictionary
{
- {"itemToSellID", vendItem.itemToSellID},
- {"itemToSellAmount", vendItem.itemToSellAmount},
- {"currencyID", vendItem.currencyID},
- {"currencyAmountPerItem", vendItem.currencyAmountPerItem},
- {"inStock", vendItem.inStock},
- {"currencyIsBP", vendItem.currencyIsBP},
- {"itemToSellIsBP", vendItem.itemToSellIsBP}
+ { "itemToSellID", vendItem.itemToSellID },
+ { "itemToSellAmount", vendItem.itemToSellAmount },
+ { "currencyID", vendItem.currencyID },
+ { "currencyAmountPerItem", vendItem.currencyAmountPerItem },
+ { "inStock", vendItem.inStock },
+ { "currencyIsBP", vendItem.currencyIsBP },
+ { "itemToSellIsBP", vendItem.itemToSellIsBP }
});
}
data.Add("vendingmachine", new Dictionary
{
- {"shopName", vendingMachine.shopName},
- {"isBroadcasting", vendingMachine.IsBroadcasting()},
- {"sellOrders", sellOrders}
+ { "shopName", vendingMachine.shopName },
+ { "isBroadcasting", vendingMachine.IsBroadcasting() },
+ { "sellOrders", sellOrders }
});
}
@@ -804,10 +825,10 @@ private Dictionary EntityData(BaseEntity entity, Vector3 entPos,
var ioData = new Dictionary();
var inputs = ioEntity.inputs.Select(input => new Dictionary
{
- {"connectedID", input.connectedTo.entityRef.uid},
- {"connectedToSlot", input.connectedToSlot},
- {"niceName", input.niceName},
- {"type", (int) input.type}
+ { "connectedID", input.connectedTo.entityRef.uid },
+ { "connectedToSlot", input.connectedToSlot },
+ { "niceName", input.niceName },
+ { "type", (int)input.type }
})
.Cast