C#:
#region License (GPL v2)
/*
Loot Protection - Prevent access to player containers
Copyright (c) 2020 RFC1920 <desolationoutpostpve@gmail.com>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License v2.0.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
Optionally you can also view the license at <http://www.gnu.org/licenses/>.
*/
#endregion License (GPL v2)
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Core.Plugins;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Text.RegularExpressions;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("Loot Protection", "RFC1920", "1.0.43")]
[Description("Prevent access to player containers, locks, etc.")]
internal class LootProtect : RustPlugin
{
#region vars
private Dictionary<string, List<Share>> sharing = new();
private Dictionary<string, long> lastConnected = new();
private Dictionary<ulong, ulong> lootingBackpack = new();
private const string permLootProtAdmin = "lootprotect.admin";
private const string permLootProtAll = "lootprotect.all";
private const string permLootProtShare = "lootprotect.share";
private const string permLootProtected = "lootprotect.player";
private ConfigData configData;
private bool newsave;
[PluginReference]
private readonly Plugin ZoneManager, Friends, Clans, RustIO, NextGenPVE;
private readonly string logfilename = "log";
private bool dolog;
private bool logtofile;
private bool enabled = true;
public class Share
{
public string name;
public uint netid;
public ulong sharewith;
}
#endregion vars
#region Message
private string Lang(string key, string id = null, params object[] args) => string.Format(lang.GetMessage(key, this, id), args);
private void Message(IPlayer player, string key, params object[] args) => player.Message(Lang(key, player.Id, args));
private void LMessage(IPlayer player, string key, params object[] args) => player.Reply(Lang(key, player.Id, args));
#endregion Message
#region init
private void Init()
{
LoadConfigVariables();
AddCovalenceCommand("lp", "CmdLootProt");
AddCovalenceCommand("share", "CmdShare");
AddCovalenceCommand("unshare", "CmdUnShare");
AddCovalenceCommand("bshare", "CmdShareBuilding");
AddCovalenceCommand("bunshare", "CmdUnShareBuilding");
permission.RegisterPermission(permLootProtected, this);
permission.RegisterPermission(permLootProtAdmin, this);
permission.RegisterPermission(permLootProtAll, this);
permission.RegisterPermission(permLootProtShare, this);
if (configData.Options.useSchedule) RunSchedule(true);
}
private void OnServerInitialized() => LoadData();
private void Unload() => SaveData();
private void OnHammerHit(BasePlayer player, HitInfo hit)
{
if (!configData.Options.useHammerForShareStatus) return;
BaseEntity ent = hit.HitEntity;
if (ent != null && sharing.ContainsKey(ent.OwnerID.ToString()))
{
string ename = ent.ShortPrefabName;
if (ename.Equals("cupboard.tool.deployed"))
{
player.SendConsoleCommand("bshare ?");
}
else
{
player.SendConsoleCommand("share ?");
}
}
}
private void OnUserConnected(IPlayer player)
{
if (!sharing.ContainsKey(player.Id))
{
sharing.Add(player.Id, new List<Share>());
SaveData();
}
OnUserDisconnected(player);
}
private void OnUserDisconnected(IPlayer player)
{
long lc = 0;
lastConnected.TryGetValue(player.Id, out lc);
if (lc > 0)
{
lastConnected[player.Id] = ToEpochTime(DateTime.UtcNow);
}
else
{
lastConnected.Add(player.Id, ToEpochTime(DateTime.UtcNow));
}
SaveData();
}
// Call out from Backpacks plugin
private void OnBackpackOpened(BasePlayer looter, ulong OwnerId, ItemContainer _itemContainer)
{
if (!lootingBackpack.ContainsKey(looter.userID)) lootingBackpack.Add(looter.userID, OwnerId);
}
private void OnBackpackClosed(BasePlayer looter, ulong OwnerId, ItemContainer _itemContainer)
{
if (lootingBackpack.ContainsKey(looter.userID)) lootingBackpack.Remove(looter.userID);
}
private void OnNewSave()
{
newsave = true;
}
private void SaveData()
{
Interface.Oxide.DataFileSystem.WriteObject(Name + "/sharing", sharing);
Interface.Oxide.DataFileSystem.WriteObject(Name + "/lastconnected", lastConnected);
}
private void LoadData()
{
if (newsave)
{
newsave = false;
lastConnected = new Dictionary<string, long>();
sharing = new Dictionary<string, List<Share>>();
SaveData();
return;
}
else
{
lastConnected = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<string, long>>(Name + "/lastconnected");
sharing = Interface.Oxide.DataFileSystem.ReadObject<Dictionary<string, List<Share>>>(Name + "/sharing");
}
if (sharing == null)
{
sharing = new Dictionary<string, List<Share>>();
SaveData();
}
}
protected override void LoadDefaultMessages()
{
lang.RegisterMessages(new Dictionary<string, string>
{
["checkinglocal"] = "[LootProtect] Checking {0} local entities",
["enabled"] = "LootProtect enabled.",
["disabled"] = "LootProtect disabled.",
["status"] = "LootProtect enable is set to {0}.",
["logging"] = "Logging set to {0}",
["all"] = "all",
["friends"] = "friends",
["nonefound"] = "No entity found.",
["settings"] = "{0} Settings:\n{1}",
["shared"] = "{0} shared with {1}.",
["sharedf"] = "{0} shared with friends.",
["removeshare"] = "Sharing removed.",
["removesharefor"] = "Sharing removed for {0} entities.",
["shareinfo"] = "Share info for {0}",
["lpshareinfo"] = "[LootProtect] Share info for {0}",
["notauthorized"] = "You don't have permission to use this command.",
}, this);
}
private void RunSchedule(bool refresh = false)
{
TimeSpan ts = new();
if (configData.Options.useRealTime)
{
ts = new TimeSpan((int)DateTime.Now.DayOfWeek, 0, 0, 0).Add(DateTime.Now.TimeOfDay);
}
else
{
try
{
ts = TOD_Sky.Instance.Cycle.DateTime.TimeOfDay;
}
catch
{
DoLog("TOD_Sky failure...");
refresh = true;
}
}
Schedule parsed;
bool doenable = false;
if (ParseSchedule(configData.Schedule, out parsed))
{
foreach (int x in parsed.day)
{
DoLog($"Schedule day == {x} {parsed.dayName[0]} {parsed.starthour} to {parsed.endhour}");
if (ts.Days == x)
{
DoLog($"Day matched. Comparing {ts.Hours}:{ts.Minutes.ToString().PadLeft(2, '0')} to start time {parsed.starthour}:{parsed.startminute} and end time {parsed.endhour}:{parsed.endminute}");
if (ts.Hours >= Convert.ToInt32(parsed.starthour) && ts.Hours <= Convert.ToInt32(parsed.endhour))
{
// Hours matched for activating ruleset, check minutes
DoLog("Hours matched", 1);
if (ts.Hours == Convert.ToInt32(parsed.starthour) && ts.Minutes >= Convert.ToInt32(parsed.startminute))
{
DoLog("Matched START hour and minute.", 2);
doenable = true;
}
else if (ts.Hours == Convert.ToInt32(parsed.endhour) && ts.Minutes <= Convert.ToInt32(parsed.endminute))
{
DoLog("Matched END hour and minute.", 2);
doenable = true;
}
else if (ts.Hours > Convert.ToInt32(parsed.starthour) && ts.Hours < Convert.ToInt32(parsed.endhour))
{
DoLog("Between start and end hours.", 2);
doenable = true;
}
else
{
DoLog("Minute mismatch for START OR END.", 2);
doenable = false;
}
}
else
{
DoLog("Hours NOT matched", 1);
doenable = false;
}
}
}
}
enabled = doenable;
timer.Once(configData.Options.useRealTime ? 30f : 5f, () => RunSchedule(refresh));
}
#endregion init
#region commands
[Command("unshare")]
private void CmdUnShare(IPlayer iplayer, string command, string[] args)
{
if (iplayer == null) return;
if (!iplayer.HasPermission(permLootProtShare) && !iplayer.HasPermission(permLootProtAdmin)) { Message(iplayer, "notauthorized"); return; }
string debug = string.Join(",", args); DoLog($"{command} {debug}");
if (!sharing.ContainsKey(iplayer.Id))
{
sharing.Add(iplayer.Id, new List<Share>());
}
if (args.Length == 0)
{
BasePlayer player = iplayer.Object as BasePlayer;
RaycastHit hit;
if (Physics.Raycast(player.eyes.HeadRay(), out hit, 2.2f))
{
BaseEntity ent = hit.GetEntity();
if (ent != null)
{
if (ent.OwnerID != player.userID && !IsFriend(player.userID, ent.OwnerID)) return;
List<Share> repl = new();
foreach (Share x in sharing[iplayer.Id])
{
if (x.netid != (uint)ent.net.ID.Value)
{
repl.Add(x);
}
else
{
DoLog($"Removing {ent.net.ID} from sharing list...");
}
}
sharing[iplayer.Id] = repl;
SaveData();
LoadData();
Message(iplayer, "removeshare");
}
}
}
}
[Command("share")]
private void CmdShare(IPlayer iplayer, string command, string[] args)
{
if (iplayer == null) return;
if (!iplayer.HasPermission(permLootProtShare) && !iplayer.HasPermission(permLootProtAdmin)) { Message(iplayer, "notauthorized"); return; }
string debug = string.Join(",", args); DoLog($"{command} {debug}");
if (!sharing.ContainsKey(iplayer.Id))
{
sharing.Add(iplayer.Id, new List<Share>());
}
if (args.Length == 0)
{
BasePlayer player = iplayer.Object as BasePlayer;
RaycastHit hit;
if (Physics.Raycast(player.eyes.HeadRay(), out hit, 2.2f))
{
BaseEntity ent = hit.GetEntity();
if (ent != null)
{
if (ent.OwnerID != player.userID && !IsFriend(player.userID, ent.OwnerID)) return;
string ename = ent.ShortPrefabName;
sharing[iplayer.Id].Add(new Share { netid = (uint)ent.net.ID.Value, name = ename, sharewith = 0 });
SaveData();
Message(iplayer, "shared", ename, Lang("all"));
}
}
}
else if (args.Length == 1)
{
if (args[0] == "?")
{
BasePlayer player = iplayer.Object as BasePlayer;
RaycastHit hit;
if (Physics.Raycast(player.eyes.HeadRay(), out hit, 2.2f))
{
BaseEntity ent = hit.GetEntity();
string message = "";
if (ent != null)
{
if (ent.OwnerID != player.userID && !IsFriend(player.userID, ent.OwnerID)) return;
// SHOW SHARED BY, KEEP IN MIND WHO OWNS BUT DISPLAY IF FRIEND, ETC...
if (sharing.ContainsKey(ent.OwnerID.ToString()))
{
string ename = ent.ShortPrefabName;
message += $"{ename}({ent.net.ID}):\n";
foreach (Share x in sharing[ent.OwnerID.ToString()])
{
if (x.netid != (uint)ent.net.ID.Value) continue;
if (x.sharewith == 0)
{
message += "\t" + Lang("all") + "\n";
}
else if (x.sharewith == 1)
{
message += "\t" + Lang("friends") + "\n";
}
else
{
message += $"\t{x.sharewith}\n";
}
}
Message(iplayer, "lpshareinfo", message);
}
}
else
{
Message(iplayer, "nonefound");
}
}
}
else if (args[0] == "friends")
{
if (!configData.Options.HonorRelationships) return;
BasePlayer player = iplayer.Object as BasePlayer;
RaycastHit hit;
if (Physics.Raycast(player.eyes.HeadRay(), out hit, 2.2f))
{
BaseEntity ent = hit.GetEntity();
if (ent != null)
{
if (ent.OwnerID != player.userID && !IsFriend(player.userID, ent.OwnerID)) return;
string ename = ent.ShortPrefabName;
sharing[iplayer.Id].Add(new Share { netid = (uint)ent.net.ID.Value, name = ename, sharewith = 1 });
SaveData();
Message(iplayer, "sharedf", ename);
}
}
}
else
{
BasePlayer sharewith = FindPlayerByName(args[0]);
BasePlayer player = iplayer.Object as BasePlayer;
RaycastHit hit;
if (Physics.Raycast(player.eyes.HeadRay(), out hit, 2.2f))
{
BaseEntity ent = hit.GetEntity();
if (ent != null)
{
if (ent.OwnerID != player.userID && !IsFriend(player.userID, ent.OwnerID)) return;
string ename = ent.ShortPrefabName;
if (sharewith == null)
{
if (!configData.Options.HonorRelationships) return;
sharing[iplayer.Id].Add(new Share { netid = (uint)ent.net.ID.Value, name = ename, sharewith = 1 });
}
else
{
sharing[iplayer.Id].Add(new Share { netid = (uint)ent.net.ID.Value, name = ename, sharewith = sharewith.userID });
}
SaveData();
Message(iplayer, "shared", ename, sharewith.displayName);
}
}
}
}
}
[Command("bunshare")]
private void CmdUnShareBuilding(IPlayer iplayer, string command, string[] args)
{
if (iplayer == null) return;
if (!iplayer.HasPermission(permLootProtShare) && !iplayer.HasPermission(permLootProtAdmin)) { Message(iplayer, "notauthorized"); return; }
BasePlayer player = iplayer.Object as BasePlayer;
string debug = string.Join(",", args); DoLog($"{command} {debug}");
if (!sharing.ContainsKey(iplayer.Id))
{
sharing.Add(iplayer.Id, new List<Share>());
}
int found = 0;
Collider[] hits = Physics.OverlapSphere(player.transform.position, configData.Options.BuildingShareRange, LayerMask.GetMask("Default", "Deployed"));
List<Share> repl = new(sharing[iplayer.Id]);
DoLog($"Checking {hits.Length} local entities");
Message(iplayer, "checkinglocal", hits.Length.ToString());
for (int i = 0; i < hits.Length; i++)
{
BaseEntity ent = hits[i].GetComponentInParent<BaseEntity>();
if (ent == null) continue;
// Skip actual TC
if (ent.ShortPrefabName.Equals("cupboard.tool.deployed"))
{
continue;
}
if (ent.OwnerID != player.userID && !IsFriend(player.userID, ent.OwnerID)) continue;
if (ent.GetBuildingPrivilege() == null) continue;
foreach (Share x in sharing[iplayer.Id])
{
if (x.netid == 0) continue;
if (x.netid == (uint)ent.net.ID.Value)
{
found++;
if (repl.Contains(x)) repl.Remove(x);
DoLog($"Removing {ent.ShortPrefabName} ({ent.net.ID}) from sharing list...");
}
}
}
if (found > 0)
{
sharing[iplayer.Id] = repl;
SaveData();
LoadData();
Message(iplayer, "removesharefor", found.ToString());
}
}
private void ShareBuilding(Vector3 position, ulong owner, float range = 0)
{
if (range == 0) range = configData.Options.BuildingShareRange;
if (!sharing.ContainsKey(owner.ToString()))
{
sharing.Add(owner.ToString(), new List<Share>());
SaveData();
}
Collider[] hits = Physics.OverlapSphere(position, range, LayerMask.GetMask("Default", "Deployed"));
List<string> excludestd = new() { "cupboard.tool.deployed", "doorcloser", "rug.deployed", "shelves", "table.deployed", "spinner.wheel.deployed", "metal-ore", "sulfur-ore", "stone-ore", "loot_barrel_2", "loot-barrel-1", "trash-pile-1" };
List<string> excludelights = new() { "ceilinglight.deployed", "tunalight.deployed", "lantern.deployed" };
DoLog($"Checking {hits.Length} local entities");
int count = 0;
List<ulong> populated = new();
for (int i = 0; i < hits.Length; i++)
{
BaseEntity ent = hits[i].GetComponentInParent<BaseEntity>();
if (ent == null) continue;
if (string.IsNullOrEmpty(ent.ShortPrefabName)) continue;
if (owner > 0)
{
ent.OwnerID = owner;
}
DoLog($"Checking {ent.ShortPrefabName}, owner: {ent.OwnerID}");
if (excludestd.Contains(ent.ShortPrefabName))
{
continue;
}
else if (excludelights.Contains(ent.ShortPrefabName) && !configData.Options.BShareIncludeLights)
{
continue;
}
else if (ent.ShortPrefabName.Contains("sign") && !configData.Options.BShareIncludeSigns)
{
continue;
}
else if (ent.ShortPrefabName.Contains("electric") && !configData.Options.BShareIncludeElectrical)
{
continue;
}
count++;
if (populated.Contains((uint)ent.net.ID.Value)) continue;
populated.Add((uint)ent.net.ID.Value);
DoLog($"Adding {ent.ShortPrefabName} ({ent.net.ID}) to sharing list...");
//Message(iplayer, $"Sharing {ent.ShortPrefabName}");
// Entity under control of TC
sharing[owner.ToString()].Add(new Share { netid = (uint)ent.net.ID.Value, name = ent.ShortPrefabName, sharewith = 0 });
}
DoLog($"Shared {count} entities");
SaveData();
}
[Command("bshare")]
private void CmdShareBuilding(IPlayer iplayer, string command, string[] args)
{
if (iplayer == null) return;
if (!iplayer.HasPermission(permLootProtShare) && !iplayer.HasPermission(permLootProtAdmin)) { Message(iplayer, "notauthorized"); return; }
BasePlayer player = iplayer.Object as BasePlayer;
string debug = string.Join(",", args); DoLog($"{command} {debug}");
if (!sharing.ContainsKey(iplayer.Id))
{
sharing.Add(iplayer.Id, new List<Share>());
}
bool query = false;
if (args.Length == 1 && args[0] == "?")
{
query = true;
}
string message = "";
Collider[] hits = Physics.OverlapSphere(player.transform.position, configData.Options.BuildingShareRange, LayerMask.GetMask("Default", "Deployed"));
List<string> excludestd = new() { "cupboard.tool.deployed", "doorcloser", "rug.deployed", "shelves", "table.deployed", "spinner.wheel.deployed", "metal-ore", "sulfur-ore", "stone-ore", "loot_barrel_2", "loot-barrel-1", "trash-pile-1" };
List<string> excludelights = new() { "ceilinglight.deployed", "tunalight.deployed", "lantern.deployed" };
DoLog($"Checking {hits.Length} local entities");
Message(iplayer, "checkinglocal", hits.Length.ToString());
int count = 0;
List<ulong> populated = new();
for (int i = 0; i < hits.Length; i++)
{
BaseEntity ent = hits[i].GetComponentInParent<BaseEntity>();
if (ent == null) continue;
if (string.IsNullOrEmpty(ent.ShortPrefabName)) continue;
if (ent.OwnerID == 0) continue;
DoLog($"Checking {ent.ShortPrefabName}, owner: {ent.OwnerID}");
if (excludestd.Contains(ent.ShortPrefabName))
{
continue;
}
else if (excludelights.Contains(ent.ShortPrefabName) && !configData.Options.BShareIncludeLights)
{
continue;
}
else if (ent.ShortPrefabName.Contains("sign") && !configData.Options.BShareIncludeSigns)
{
continue;
}
else if (ent.ShortPrefabName.Contains("electric") && !configData.Options.BShareIncludeElectrical)
{
continue;
}
// If player has lootprotect admin, allow the share. Otherwise, check ownership or friend relationship.
if (!iplayer.HasPermission(permLootProtAdmin) && ent.OwnerID != player.userID && !IsFriend(player.userID, ent.OwnerID))
{
continue;
}
if (ent.GetBuildingPrivilege() == null) continue;
count++;
if (query)
{
//foreach (Share x in sharing[ent.OwnerID.ToString()])
foreach (Share x in sharing[iplayer.Id])
{
if (x.netid != (uint)ent.net.ID.Value) continue;
message += $"{count}. {ent.ShortPrefabName}: ";
if (x.sharewith == 0)
{
message += Lang("all") + "\n";
}
else
{
message += $"{x.sharewith}\n";
}
}
continue;
}
if (populated.Contains((uint)ent.net.ID.Value)) continue;
populated.Add((uint)ent.net.ID.Value);
DoLog($"Adding {ent.ShortPrefabName} ({ent.net.ID}) to sharing list...");
//Message(iplayer, $"Sharing {ent.ShortPrefabName}");
// Entity under control of TC
sharing[iplayer.Id].Add(new Share { netid = (uint)ent.net.ID.Value, name = ent.ShortPrefabName, sharewith = 0 });
}
if (query)
{
if (!string.IsNullOrEmpty(message))
{
Message(iplayer, message);
}
return;
}
Message(iplayer, $"Shared {count} entities");
SaveData();
}
[Command("lp")]
private void CmdLootProt(IPlayer iplayer, string command, string[] args)
{
if (iplayer == null) return;
if (!iplayer.HasPermission(permLootProtAdmin)) { Message(iplayer, "notauthorized"); return; }
string debug = string.Join(",", args); DoLog($"{command} {debug}");
if (args.Length == 0)
{
ShowStatus(iplayer);
return;
}
switch (args[0])
{
case "1":
case "e":
case "true":
case "enable":
enabled = true;
Message(iplayer, "enabled");
break;
case "0":
case "d":
case "false":
case "disable":
enabled = false;
Message(iplayer, "disabled");
break;
case "status":
ShowStatus(iplayer);
break;
case "l":
case "log":
case "logging":
dolog = !dolog;
Message(iplayer, "logging", dolog.ToString());
break;
}
}
#endregion commands
#region hooks
private object CanPickupEntity(BasePlayer player, BaseCombatEntity ent)
{
if (player == null || ent == null) return null;
if (player.userID.IsSteamId() != true) return null;
DoLog($"Player {player.displayName} picking up {ent?.ShortPrefabName}");
if ((player.IsAdmin || permission.UserHasPermission(player?.UserIDString, permLootProtAdmin)) && configData.Options.AdminBypass) return null;
if (CheckCupboardAccess(ent, player)) return null;
if (CanAccess(ent?.ShortPrefabName, player.userID, ent.OwnerID)) return null;
if (CheckShare(ent, player.userID)) return null;
return configData.Options.useNextGenPVE && CanLootPVP(ent) ? null : (object)false;
}
private object CanPickupLock(BasePlayer player, BaseLock ent)
{
if (player == null || ent == null) return null;
if (player.userID.IsSteamId() != true) return null;
DoLog($"Player {player.displayName} picking up {ent?.ShortPrefabName}");
if ((player.IsAdmin || permission.UserHasPermission(player?.UserIDString, permLootProtAdmin)) && configData.Options.AdminBypass) return null;
if (CheckCupboardAccess(ent, player)) return null;
if (CanAccess(ent?.ShortPrefabName, player.userID, ent.OwnerID)) return null;
return CheckShare(ent, player.userID) ? null : (object)true;
}
private object CanUpdateSign(BasePlayer player, PhotoFrame sign)
{
if (player == null || sign == null) return null;
if (player.userID.IsSteamId() != true) return null;
BaseEntity ent = sign.GetComponentInParent<BaseEntity>();
DoLog($"Player {player.displayName} painting PhotoFrame {ent?.ShortPrefabName}");
if ((player.IsAdmin || permission.UserHasPermission(player?.UserIDString, permLootProtAdmin)) && configData.Options.AdminBypass) return null;
if (CheckCupboardAccess(ent, player)) return null;
if (CanAccess(ent?.ShortPrefabName, player.userID, ent.OwnerID)) return null;
if (CheckShare(ent, player.userID)) return null;
return configData.Options.useNextGenPVE && CanLootPVP(ent as BaseCombatEntity) ? null : (object)false;
}
private object CanUpdateSign(BasePlayer player, Signage sign)
{
if (player == null || sign == null) return null;
if (player.userID.IsSteamId() != true) return null;
BaseEntity ent = sign.GetComponentInParent<BaseEntity>();
DoLog($"Player {player.displayName} painting SIGN {ent?.ShortPrefabName}");
if ((player.IsAdmin || permission.UserHasPermission(player?.UserIDString, permLootProtAdmin)) && configData.Options.AdminBypass) return null;
if (CheckCupboardAccess(ent, player)) return null;
if (CanAccess(ent?.ShortPrefabName, player.userID, ent.OwnerID)) return null;
if (CheckShare(ent, player.userID)) return null;
return configData.Options.useNextGenPVE && CanLootPVP(ent as BaseCombatEntity) ? null : (object)false;
}
private object CanLootEntity(BasePlayer player, VendingMachine container)
{
if (player == null || container == null) return null;
if (player.userID.IsSteamId() != true) return null;
BaseEntity ent = container.GetComponentInParent<BaseEntity>();
if (container.PlayerInfront(player))
{
DoLog($"Player {player.displayName} looting front of {ent?.ShortPrefabName} - allowed");
return null;
}
DoLog($"Player {player.displayName} looting VM {ent?.ShortPrefabName}");
if ((player.IsAdmin || permission.UserHasPermission(player?.UserIDString, permLootProtAdmin)) && configData.Options.AdminBypass) return null;
if (CheckCupboardAccess(ent, player)) return null;
if (CanAccess(ent?.ShortPrefabName, player.userID, ent.OwnerID)) return null;
if (CheckShare(ent, player.userID)) return null;
return configData.Options.useNextGenPVE && CanLootPVP(ent as BaseCombatEntity) ? null : (object)true;
}
private object CanLootEntity(BasePlayer player, ContainerIOEntity container)
{
if (player == null || container == null) return null;
if (player.userID.IsSteamId() != true) return null;
BaseEntity ent = container?.GetComponentInParent<BaseEntity>();
if (ent == null) return null;
DoLog($"Player {player.displayName} looting ContainerIOEntity {ent.ShortPrefabName} owned by {ent.OwnerID}");
if ((player.IsAdmin || permission.UserHasPermission(player?.UserIDString, permLootProtAdmin)) && configData.Options.AdminBypass)
{
DoLog("Admin Bypass");
return null;
}
if (CheckCupboardAccess(ent, player)) return null;
if (CanAccess(ent?.ShortPrefabName, player.userID, ent.OwnerID)) return null;
if (CheckShare(ent, player.userID)) return null;
return configData.Options.useNextGenPVE && CanLootPVP(ent as BaseCombatEntity) ? null : (object)true;
}
private object CanLootEntity(BasePlayer player, StorageContainer container)
{
if (player == null || container == null) return null;
if (player.userID.IsSteamId() != true) return null;
BaseEntity ent = container?.GetComponentInParent<BaseEntity>();
if (ent == null) return null;
DoLog($"Player {player.displayName} looting StorageContainer {ent.ShortPrefabName} owned by {ent.OwnerID}");
if ((player.IsAdmin || permission.UserHasPermission(player?.UserIDString, permLootProtAdmin)) && configData.Options.AdminBypass)
{
DoLog("Admin Bypass");
return null;
}
if (CheckCupboardAccess(ent, player)) return null;
if (CanAccess(ent?.ShortPrefabName, player.userID, ent.OwnerID)) return null;
if (CheckShare(ent, player.userID)) return null;
return configData.Options.useNextGenPVE && CanLootPVP(ent as BaseCombatEntity) ? null : (object)true;
}
private bool CanLootPVP(BaseCombatEntity entity)
{
object pve = NextGenPVE?.CallHook("IsInPVEZone", entity);
return pve != null && pve is bool && !(bool)pve ? configData.Options.allowLootingInPVPAreas : false;
}
private object CanLootEntity(BasePlayer player, DroppedItemContainer container)
{
if (player == null || container == null) return null;
if (player.userID.IsSteamId() != true) return null;
BaseEntity ent = container.GetComponentInParent<BaseEntity>();
DoLog($"Player {player.displayName} looting DroppedItemContainer {ent?.ShortPrefabName}:{container.playerSteamID}");
if ((player.IsAdmin || permission.UserHasPermission(player?.UserIDString, permLootProtAdmin)) && configData.Options.AdminBypass) return null;
if (!container.OwnerID.IsSteamId()) return null;
if (CanAccess(ent?.ShortPrefabName, player.userID, container.playerSteamID)) return null;
return configData.Options.useNextGenPVE && CanLootPVP(ent as BaseCombatEntity) ? null : (object)true;
}
private object CanLootEntity(BasePlayer player, LootableCorpse corpse)
{
if (player == null || corpse == null) return null;
if (player.userID.IsSteamId() != true) return null;
DoLog($"Player {player.displayName}:{player.UserIDString} looting corpse {corpse.name}:{corpse.playerSteamID}");
if ((player.IsAdmin || permission.UserHasPermission(player?.UserIDString, permLootProtAdmin)) && configData.Options.AdminBypass) return null;
if (CanAccess(corpse?.ShortPrefabName, player.userID, corpse.playerSteamID)) return null;
return configData.Options.useNextGenPVE && CanLootPVP(corpse) ? null : (object)true;
}
private object CanRenameBed(BasePlayer player, SleepingBag bag, string bedName)
{
if (player == null || bag == null) return null;
if (player.userID.IsSteamId() != true) return null;
DoLog($"Player {player.displayName}:{player.UserIDString} renaming SleepingBag {bag.name}:{bag.OwnerID}");
if ((player.IsAdmin || permission.UserHasPermission(player?.UserIDString, permLootProtAdmin)) && configData.Options.AdminBypass) return null;
return CanAccess(bag?.ShortPrefabName, player.userID, bag.OwnerID) ? null : (object)true;
}
private object CanAssignBed(BasePlayer player, SleepingBag bag, ulong targetPlayerId)
{
if (player == null || bag == null) return null;
if (player.userID.IsSteamId() != true) return null;
DoLog($"Player {player.displayName}:{player.UserIDString} assigning SleepingBag {bag.name}:{bag.OwnerID}");
if ((player.IsAdmin || permission.UserHasPermission(player?.UserIDString, permLootProtAdmin)) && configData.Options.AdminBypass) return null;
return CanAccess(bag?.ShortPrefabName, player.userID, bag.OwnerID) ? null : (object)true;
}
private object CanSetBedPublic(BasePlayer player, SleepingBag bag)
{
if (player == null || bag == null) return null;
if (player.userID.IsSteamId() != true) return null;
DoLog($"Player {player.displayName}:{player.UserIDString} setting SleepingBag {bag.name}:{bag.OwnerID} public");
if ((player.IsAdmin || permission.UserHasPermission(player?.UserIDString, permLootProtAdmin)) && configData.Options.AdminBypass) return null;
return CanAccess(bag?.ShortPrefabName, player.userID, bag.OwnerID) ? null : (object)true;
}
private object CanLootPlayer(BasePlayer target, BasePlayer player)
{
if (player == null || target == null) return null;
if (player.userID.IsSteamId() != true) return null;
if (player.userID == target.userID) return null;
DoLog($"Player {player.displayName}:{player.UserIDString} looting Player {target.displayName}:{target.UserIDString}");
if ((player.IsAdmin || permission.UserHasPermission(player?.UserIDString, permLootProtAdmin)) && configData.Options.AdminBypass) return null;
if (CanAccess(target?.ShortPrefabName, player.userID, target.userID)) return null;
return configData.Options.useNextGenPVE && CanLootPVP(target) ? null : (object)false;
}
private object OnOvenToggle(BaseOven oven, BasePlayer player)
{
if (player == null || oven == null) return null;
if (player.userID.IsSteamId() != true) return null;
DoLog($"Player {player.displayName} toggling {oven?.ShortPrefabName}");
if (configData.Options.OverrideOven) return null;
if ((player.IsAdmin || permission.UserHasPermission(player?.UserIDString, permLootProtAdmin)) && configData.Options.AdminBypass) return null;
if (CheckCupboardAccess(oven, player)) return null;
if (CanAccess(oven?.ShortPrefabName, player.userID, oven.OwnerID)) return null;
return CheckShare(oven, player.userID) ? null : (object)true;
}
private object OnButtonPress(PressButton button, BasePlayer player)
{
if (player == null || button == null) return null;
if (player.userID.IsSteamId() != true) return null;
DoLog($"Player {player.displayName} toggling button {button.ShortPrefabName}:{button.OwnerID}");
if ((player.IsAdmin || permission.UserHasPermission(player?.UserIDString, permLootProtAdmin)) && configData.Options.AdminBypass) return null;
if (!button.OwnerID.IsSteamId()) return null;
return CanAccess(button?.ShortPrefabName, player.userID, button.OwnerID) ? null : (object)true;
}
private object CanLock(BasePlayer player, BaseLock baseLock)
{
if (player == null || baseLock == null) return null;
if (player.userID.IsSteamId() != true) return null;
DoLog($"Player {player.displayName} toggling IOEntity {baseLock.ShortPrefabName}:{baseLock.OwnerID}");
if ((player.IsAdmin || permission.UserHasPermission(player?.UserIDString, permLootProtAdmin)) && configData.Options.AdminBypass) return null;
if (!baseLock.OwnerID.IsSteamId()) return null;
return CanAccess(baseLock?.ShortPrefabName, player.userID, baseLock.OwnerID) ? null : (object)true;
}
private object CanChangeCode(BasePlayer player, CodeLock codeLock, string newCode, bool isGuestCode)
{
if (player == null || codeLock == null) return null;
if (player.userID.IsSteamId() != true) return null;
DoLog($"Player {player.displayName} toggling IOEntity {codeLock.ShortPrefabName}:{codeLock.OwnerID}");
if ((player.IsAdmin || permission.UserHasPermission(player?.UserIDString, permLootProtAdmin)) && configData.Options.AdminBypass) return null;
if (!codeLock.OwnerID.IsSteamId()) return null;
return CanAccess(codeLock?.ShortPrefabName, player.userID, codeLock.OwnerID) ? null : (object)true;
}
private object OnSwitchToggle(IOEntity entity, BasePlayer player)
{
if (player == null || entity == null) return null;
if (player.userID.IsSteamId() != true) return null;
DoLog($"Player {player.displayName} toggling IOEntity {entity.ShortPrefabName}:{entity.OwnerID}");
if ((player.IsAdmin || permission.UserHasPermission(player?.UserIDString, permLootProtAdmin)) && configData.Options.AdminBypass) return null;
if (!entity.OwnerID.IsSteamId()) return null;
return CanAccess(entity?.ShortPrefabName, player.userID, entity.OwnerID) ? null : (object)true;
}
private object CanTakeCutting(BasePlayer player, GrowableEntity plant)
{
if (player == null || plant == null) return null;
if (player.userID.IsSteamId() != true) return null;
DoLog($"Player {player.displayName}:{player.UserIDString} looting plant cutting {plant.ShortPrefabName}:{plant.OwnerID}");
if ((player.IsAdmin || permission.UserHasPermission(player?.UserIDString, permLootProtAdmin)) && configData.Options.AdminBypass) return null;
if (CanAccess(plant?.ShortPrefabName, player.userID, plant.OwnerID)) return null;
return configData.Options.useNextGenPVE && CanLootPVP(plant) ? null : (object)true;
}
private object OnRemoveDying(GrowableEntity plant, BasePlayer player)
{
if (player == null || plant == null) return null;
if (player.userID.IsSteamId() != true) return null;
DoLog($"Player {player.displayName}:{player.UserIDString} looting dying plant {plant.ShortPrefabName}:{plant.OwnerID}");
if ((player.IsAdmin || permission.UserHasPermission(player?.UserIDString, permLootProtAdmin)) && configData.Options.AdminBypass) return null;
if (CanAccess(plant?.ShortPrefabName, player.userID, plant.OwnerID)) return null;
return configData.Options.useNextGenPVE && CanLootPVP(plant) ? null : (object)true;
}
private object OnGrowableGather(GrowableEntity plant, BasePlayer player)
{
if (player == null || plant == null) return null;
if (player.userID.IsSteamId() != true) return null;
DoLog($"Player {player.displayName}:{player.UserIDString} looting plant {plant.ShortPrefabName}:{plant.OwnerID}");
if ((player.IsAdmin || permission.UserHasPermission(player?.UserIDString, permLootProtAdmin)) && configData.Options.AdminBypass) return null;
if (CanAccess(plant?.ShortPrefabName, player.userID, plant.OwnerID)) return null;
return configData.Options.useNextGenPVE && CanLootPVP(plant) ? null : (object)true;
}
private object OnCupboardAuthorize(BuildingPrivlidge privilege, BasePlayer player)
{
if (player == null || privilege == null) return null;
if (player.userID.IsSteamId() != true) return null;
DoLog($"Player {player.displayName} attempting to authenticate to a TC.");
if (configData.Options.OverrideTC) return null;
if ((player.IsAdmin || permission.UserHasPermission(player?.UserIDString, permLootProtAdmin)) && configData.Options.AdminBypass) return null;
if (CanAccess(privilege?.ShortPrefabName, player.userID, privilege.OwnerID)) return null;
if (CheckShare(privilege, player.userID)) return null;
return configData.Options.useNextGenPVE && CanLootPVP(privilege) ? null : (object)true;
}
#endregion hooks
#region helpers
// Accept external zone config from DynamicPVP
private bool AddOrUpdateMapping(string key, string rulesetname)
{
if (configData.DisabledZones == null || configData.DisabledZones?.Length == 0)
{
List<string> newzones = new() { key };
configData.DisabledZones = newzones.ToArray();
SaveConfig(configData);
return true;
}
if (!configData.DisabledZones.Contains(key))
{
List<string> newzones = new()
{
configData.DisabledZones.ToArray()[0],
key
};
configData.DisabledZones = newzones.ToArray();
SaveConfig(configData);
return true;
}
return false;
}
// Accept external zone config from DynamicPVP
private bool RemoveMapping(string key)
{
if (configData.DisabledZones == null || configData.DisabledZones?.Length == 0)
{
return true;
}
if (configData.DisabledZones?.Length > 0 && configData.DisabledZones.Contains(key))
{
List<string> newzones = new();
foreach (string zone in configData.DisabledZones)
{
if (zone == key) continue;
newzones.Add(zone);
}
configData.DisabledZones = newzones.ToArray();
SaveConfig(configData);
return true;
}
return true;
}
// From PlayerDatabase
private long ToEpochTime(DateTime dateTime)
{
DateTime date = dateTime.ToUniversalTime();
long ticks = date.Ticks - new DateTime(1970, 1, 1, 0, 0, 0, 0).Ticks;
return ticks / TimeSpan.Ticks
// ... [Code preview truncated due to length. Full source in attached file] ...