C#:
using Facepunch;
using HarmonyLib;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Plugins;
using Rust;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using static RelationshipManager;
/*
*
*/
/* 1.0.20
* Updated for August forced wipe
*/
namespace Oxide.Plugins {
[Info("EventHelper", "imthenewguy", "1.0.20")]
[Description("A plugin that devs can use to help get players into events.")]
class EventHelper : RustPlugin {
#region Config
private Configuration config;
public class Configuration {
[JsonProperty("A list of items that cannot be taken into an event")]
public List<string> black_listed_items = new List<string>() {
"cassette", " cassette.medium", "cassette.short", "fun.casetterecorder", "boombox"
}
;
[JsonProperty("The command to recover items")]
public string redeem_items_command = "recoveritems";
[JsonProperty("How often should we cycle through events")]
public float event_cycle_timer = 7200f;
[JsonProperty("Set to true if the server is giving players a kit on respawn and you want players to receive their saved items back automatically")]
public bool auto_rekit = false;
[JsonProperty("Unban players on server wipe?")]
public bool unban_players = true;
[JsonProperty("Allow players to vote for games manually?")]
public bool voting_enabled = true;
[JsonProperty("Command to initiate a vote for an event")]
public string vote_start_cmd = "eventvote";
[JsonProperty("Command to vote for an event")]
public string vote_cmd = "vote";
[JsonProperty("Max vote time (seconds)")]
public int max_vote_time = 300;
[JsonProperty("Percentage of players required for a vote to pass [1.0 = 100% of players]")]
public float vote_percentage = 0.3f;
[JsonProperty("Minimum temperature while at an event")]
public float temperature_min = 25f;
[JsonProperty("Maximum temperature while at an event")]
public float temperature_max = 25f;
[JsonProperty("How often should players be reminded of the voting feature (seconds)? [0 = off]")]
public float voting_reminder_time = 1200f;
[JsonProperty("Minimum online players before voting is allowed? [0 = no limit]")]
public int minimum_players_online_vote = 0;
[JsonProperty("Minimum online players before automatic arenas start? [0 = no limit]")]
public int minimum_players_online_auto_start = 0;
[JsonProperty("Remove entities that are stuck to the player on entry to the event?")]
public bool clear_stuck_entities = true;
[JsonProperty("Prevent players who are flagged with the NoEscape plugin from joining the event?")]
public bool prevent_no_escape_joins = true;
[JsonProperty("Announce in chat when a player joins an event?")]
public bool announce_player_join = true;
[JsonProperty("Settings for Discord plugin")]
public DiscordSettings discordSettings = new DiscordSettings();
public string ToJson() => JsonConvert.SerializeObject(this);
public Dictionary<string, object> ToDictionary() => JsonConvert.DeserializeObject<Dictionary<string, object>>(ToJson());
}
public class DiscordSettings {
[JsonProperty("Webhook URL")]
public string webhook;
[JsonProperty("Send a discord notification when an event starts?")]
public bool send_on_event = true;
}
protected override void LoadDefaultConfig() => config = new Configuration();
protected override void LoadConfig() {
base.LoadConfig();
try {
config = Config.ReadObject<Configuration>();
if (config == null) {
throw new JsonException();
}
if (!config.ToDictionary().Keys.SequenceEqual(Config.ToDictionary(x => x.Key, x => x.Value).Keys)) {
PrintToConsole("Configuration appears to be outdated; updating and saving");
SaveConfig();
}
}
catch {
PrintToConsole($"Configuration file {Name}.json is invalid; using defaults");
LoadDefaultConfig();
}
}
protected override void SaveConfig() {
PrintToConsole($"Configuration changes saved to {Name}.json");
Config.WriteObject(config, true);
}
#endregion
#region classes
public Dictionary<string, EventInfo> Events = new Dictionary<string, EventInfo>(StringComparer.OrdinalIgnoreCase);
public Dictionary<string, bool> EventRunning = new Dictionary<string, bool>(StringComparer.OrdinalIgnoreCase);
List<ulong> BagPreventDropList = new List<ulong>();
public class EventInfo {
public bool automatic_start;
public bool strip_items;
public bool leaves_event_on_death;
public bool full_health_on_join;
public bool give_items_back_automatically;
public bool full_metabolism_on_join;
public bool restricted_temp;
public Vector3 teleport_destination;
public List<BasePlayer> participants = new List<BasePlayer>();
public bool manually_started;
public bool allow_Teams;
public string[] black_listed_commands;
public ExternalPluginSettings external_plugin_settings = new ExternalPluginSettings(false, false, false, false, false, false);
public EventInfo(bool automatic_start, bool strip_items, bool leaves_event_on_death, bool full_health_on_join, bool give_items_back_automatically, bool full_metabolism_on_join, Vector3 teleport_destination, bool restricted_temp = true, bool allow_Teams = true) {
this.automatic_start = automatic_start;
this.strip_items = strip_items;
this.leaves_event_on_death = leaves_event_on_death;
this.full_health_on_join = full_health_on_join;
this.give_items_back_automatically = give_items_back_automatically;
this.full_metabolism_on_join = full_metabolism_on_join;
this.teleport_destination = teleport_destination;
this.restricted_temp = restricted_temp;
this.allow_Teams = allow_Teams;
}
public class ExternalPluginSettings {
public bool canDropBackpack;
public bool canEraseBackpack;
public bool canOpenBackpack;
public bool canBackpackAcceptItem;
public bool canRedeemKit;
public bool CanLoseXP;
public ExternalPluginSettings(bool canDropBackpack, bool canEraseBackpack, bool canOpenBackpack, bool canBackpackAcceptItem, bool canRedeemKit, bool CanLoseXP) {
this.canDropBackpack = canDropBackpack;
this.canEraseBackpack = canEraseBackpack;
this.canOpenBackpack = canOpenBackpack;
this.canBackpackAcceptItem = canBackpackAcceptItem;
this.canRedeemKit = canRedeemKit;
this.CanLoseXP = CanLoseXP;
}
}
}
public enum ContainerType {
Main, Belt, Wear, None
}
public class ItemInfo {
public string shortname;
public ulong skin;
public int amount;
public float condition;
public float maxCondition;
public int ammo;
public string ammotype;
public ContainerType container;
public int position;
public int frequency;
public Item.Flag flags;
public KeyInfo instanceData;
public class KeyInfo {
public int dataInt;
public int blueprintTarget;
public int blueprintAmount;
}
public int contentsSlots;
public List<ItemInfo> item_contents;
public string text;
public string name;
public List<ItemOwnershipShare> ownershipShares;
public int armorSlots;
}
#endregion
#region Data
PlayerEntity pcdData;
private DynamicConfigFile PCDDATA;
const string perm_admin = "eventhelper.admin";
void Init() {
WasAtEvent = new Dictionary<ulong, string>();
PCDDATA = Interface.Oxide.DataFileSystem.GetFile(this.Name);
LoadData();
permission.RegisterPermission(perm_admin, this);
cmd.AddChatCommand(config.vote_cmd, this, "VoteForEvent");
cmd.AddChatCommand(config.vote_start_cmd, this, "StartEventVote");
Temperature_Min = config.temperature_min;
Temperature_Max = config.temperature_max;
if (config.voting_reminder_time > 0 && config.voting_enabled) {
timer.Every(config.voting_reminder_time, () => {
PrintToChat(string.Format(lang.GetMessage("VotingReminder", this), config.vote_start_cmd));
}
);
}
}
void Unload() {
cmd.RemoveChatCommand(config.redeem_items_command, this);
cmd.RemoveChatCommand(config.vote_cmd, this);
cmd.RemoveChatCommand(config.vote_start_cmd, this);
foreach (var kvp in pcdData.pEntity) {
kvp.Value.AtEvent = false;
kvp.Value.Event = null;
}
foreach (var e in Events.ToList()) {
EMRemoveEvent(e.Key);
}
SaveData();
foreach (var player in BasePlayer.activePlayerList) {
DestroyTempRestriction(player);
}
WasAtEvent.Clear();
WasAtEvent = null;
}
void SaveData() {
PCDDATA.WriteObject(pcdData);
}
void LoadData() {
try {
pcdData = Interface.Oxide.DataFileSystem.ReadObject<PlayerEntity>(this.Name);
}
catch {
Puts(lang.GetMessage("NoPlayerDataLoading", this));
pcdData = new PlayerEntity();
}
}
class PlayerEntity {
public Dictionary<ulong, PCDInfo> pEntity = new Dictionary<ulong, PCDInfo>();
public Dictionary<string, List<ulong>> banned_players = new Dictionary<string, List<ulong>>();
}
class PCDInfo {
public string Event;
public float Health;
public string Modifiers;
public string Metabolism;
public bool AtEvent;
public Vector3 Location;
public List<ItemInfo> Items = new List<ItemInfo>();
public bool StripOnItemRestore;
public bool RestoreOnWake;
[NonSerialized]
public bool RestoringItems;
}
[PluginReference]
private Plugin Backpacks, NoEscape, RestoreUponDeath;
#endregion;
#region Localization
protected override void LoadDefaultMessages() {
lang.RegisterMessages(new Dictionary<string, string> {
["AtEvent"]
= "You are already at an event.", ["ItemsStored"] = "You have items stored that must be claimed before joining another event. Type /{0} to recover your items (doing this will delete your current inventory).", ["NoCrafting"] = "You must stop crafting in order to join this event.", ["EscapeBlocked"] = "You cannot join the game while you are escape blocked.", ["BlackListedItem"] = "You cannot bring a {0} into a minigame.", ["BlackListedItemSub"] = "You cannot bring a {0} into a minigame. This was found inside of your {1}", ["AlreadyEnrolled"] = "You are already enrolled in this event.", ["FailedToStrip"] = "Failed to strip your items.", ["ManualItemRecovery"] = "You must type /{0} to recover them (doing this will delete your current inventory).", ["NoRecovery"] = "You cannot recover your items until you leave the event.", ["NoCommand"] = "You cannot use the {0} command at this event.", ["UnclaimedItems"] = "You have unclaimed items. Type /{0} to recover them.", ["SkipStart"] = "Skipping event start due to manual start.", ["ManualStart"] = "Manually started event {0}", ["RemovedEvent"] = "Removed Event: {0}", ["SetupEvent"] = "Setup Event: {0}", ["EndedEvent"] = "Ended the event", ["NotSetup"] = "{0} has not been setup.", ["EventNotSetupExternalPluginSettings"] = "Event: {0} has not been setup. Must call EMCreateEvent before EMExternalPluginSettings.", ["EventNotSetupBlackList"] = "Event: {0} has not been setup. Must call EMCreateEvent before EMBlackListCommands.", ["RegisteredCommands"] = "Registered {0} black listed commands.", ["NoPlayerDataLoading"] = "Couldn't load player data, creating new Playerfile", ["NoEventData"] = "You have no event data stored.", ["MorePlayersFound"] = "More than one player found: {0}", ["NoMatch"] = "No player was found that matched: {0}", ["EHBanUsage"] = "Usage: /ehban <player name/id>", ["BannedPlayer"] = "Banned {0} from all EventHelper events.", ["EHUnbanUsage"] = "Usage: /ehunban <player name/id>", ["UnbannedPlayer"] = "Unbanned {0} from all EventHelper events.", ["NoBan"] = "{0} does not have any bans.", ["VotingReminder"] = "You can vote to start your favourite event by typing <color=#ffec00>/{0} <event name></color>", ["EventNotRegistered"] = "Failed to join - Event: {0} has not been registered!", ["PreventTeamCreation"] = "The event you are in does not allow team creation.", ["DiscordMessageEventStarted"] = ":globe_with_meridians: Event Started: {0}.", ["JointAnnounceMsg_1"] = "<color=#00fff7>{0}</color> has decided to join the action at the <color=#00ff83>{1}</color> event!", ["JointAnnounceMsg_2"] = "<color=#00fff7>{0}</color> has joined the <color=#00ff83>{1}</color> event and is ready to take some names!", ["JointAnnounceMsg_3"] = "Oh no, <color=#00fff7>{0}</color> has joined the <color=#00ff83>{1}</color> event!",
}
, this);
}
#endregion
#region Methods
bool IsPlayerBanned(BasePlayer player, string eventName) {
if (pcdData.banned_players.ContainsKey(eventName) && pcdData.banned_players[eventName].Contains(player.userID)) return true;
if (pcdData.banned_players.ContainsKey("global") && pcdData.banned_players["global"].Contains(player.userID)) return true;
return false;
}
bool CanJoinEvent(BasePlayer player, string eventName, PCDInfo playerData) {
if (playerData.RestoringItems) {
PrintToChat(player, $"You must wait for your items to restore before joining this game.");
return false;
}
if (IsPlayerBanned(player, eventName)) {
PrintToChat(player, $"You are banned from the event and cannot join.");
return false;
}
if (playerData.AtEvent) {
PrintToChat(player, lang.GetMessage("AtEvent", this, player.UserIDString));
return false;
}
if (HasItemsStored(player.userID) && !playerData.AtEvent) {
PrintToChat(player, string.Format(lang.GetMessage("ItemsStored", this, player.UserIDString), config.redeem_items_command));
return false;
}
if (player.inventory.crafting.queue.Count != 0) {
PrintToChat(player, lang.GetMessage("NoCrafting", this, player.UserIDString));
return false;
}
if (NoEscape != null && config.prevent_no_escape_joins && Convert.ToBoolean(NoEscape.Call("IsEscapeBlocked", player.UserIDString))) {
PrintToChat(player, lang.GetMessage("EscapeBlocked", this, player.UserIDString));
return false;
}
if (HasProhibitedItems(player)) return false;
if (Interface.CallHook("EMOnEventJoin", player, eventName) != null) {
PrintToChat(player, "Another plugin preventing you from joining");
return false;
}
var hook = Interface.CallHook("OnEventJoin", player, eventName);
if (hook != null) {
if (hook is string) PrintToChat(player, hook as string);
else PrintToChat(player, "An external plugin has preventing you from joining the event.");
return false;
}
return true;
}
object OnEventJoin(BasePlayer player, string eventName) {
var playerData = GetPlayer(player.userID, false);
if (playerData == null) return null;
if (playerData.AtEvent) return $"You must leave the {playerData.Event} event before attempting to join a new one.";
return null;
}
bool StorePlayerItems(BasePlayer player, PCDInfo playerData) {
playerData.Items.AddRange(GetItems(player, player.inventory.containerWear));
playerData.Items.AddRange(GetItems(player, player.inventory.containerMain));
playerData.Items.AddRange(GetItems(player, player.inventory.containerBelt));
player.inventory.Strip();
SaveData();
return true;
}
List<ItemInfo> GetItems(BasePlayer player, ItemContainer container) {
string messageText = $"\n\n------------\nGetItems for {player.displayName} [{player.userID}]\n";
List<ItemInfo> result = new List<ItemInfo>();
foreach (var item in container.itemList) {
messageText += $"- Adding item: {item.name ?? item.info.shortname}. Container: {(container == player.inventory.containerWear ? "Worn items" : container == player.inventory.containerBelt ? "Belt items" : container == player.inventory.containerMain ? "Main items" : "Item contents")}\n";
result.Add(new ItemInfo() {
shortname = item.info.shortname, position = item.position, container = GetContainer(player, container), amount = item.amount, ammo = item.GetHeldEntity() is BaseProjectile ? (item.GetHeldEntity() as BaseProjectile).primaryMagazine.contents : item.GetHeldEntity() is FlameThrower ? (item.GetHeldEntity() as FlameThrower).ammo : item.GetHeldEntity() is Chainsaw ? (item.GetHeldEntity() as Chainsaw).ammo : 0, ammotype = (item.GetHeldEntity() as BaseProjectile)?.primaryMagazine.ammoType.shortname ?? null, skin = item.skin, condition = item.condition, maxCondition = item.maxCondition, flags = item.flags, instanceData = item.instanceData != null ? new ItemInfo.KeyInfo() {
dataInt = item.instanceData.dataInt, blueprintTarget = item.instanceData.blueprintTarget, blueprintAmount = item.instanceData.blueprintAmount,
}
: null, name = item.name ?? null, text = item.text ?? null, item_contents = item.contents?.itemList != null ? GetItems(player, item.contents) : null, contentsSlots = item.contents?.capacity ?? 0, ownershipShares = item.ownershipShares
}
);
}
LogToFile("GetItems", messageText, this, true, true);
return result;
}
Item GetRestoreItem(BasePlayer player, ItemContainer container, ItemInfo savedItem) {
var item = ItemManager.CreateByName(savedItem.shortname, savedItem.amount, savedItem.skin);
if (savedItem.name != null) item.name = savedItem.name;
if (savedItem.text != null) item.text = savedItem.text;
item.condition = savedItem.condition;
item.maxCondition = savedItem.maxCondition;
if (savedItem.contentsSlots > 0 && item.info.isWearable && item.info.TryGetComponent<ItemModContainerArmorSlot>(out var aSlots)) {
aSlots.CreateAtCapacity(savedItem.contentsSlots, item);
}
BaseEntity heldEntity = item.GetHeldEntity();
item.flags = savedItem.flags;
if (savedItem.instanceData != null) {
item.instanceData = new ProtoBuf.Item.InstanceData();
item.instanceData.ShouldPool = false;
item.instanceData.dataInt = savedItem.instanceData.dataInt;
item.instanceData.blueprintTarget = savedItem.instanceData.blueprintTarget;
item.instanceData.blueprintAmount = savedItem.instanceData.blueprintAmount;
}
if (savedItem.item_contents != null && savedItem.item_contents.Count > 0) {
if (item.contents == null) {
item.contents = new ItemContainer();
item.contents.ServerInitialize(null, savedItem.item_contents.Count);
item.contents.GiveUID();
item.contents.parent = item;
}
foreach (var _item in savedItem.item_contents) {
GetRestoreItem(player, item.contents, _item);
}
}
if (savedItem.ownershipShares != null && savedItem.ownershipShares.Count > 0) item.ownershipShares = savedItem.ownershipShares;
BaseProjectile weapon = heldEntity as BaseProjectile;
if (weapon != null) {
weapon.DelayedModsChanged();
if (!string.IsNullOrEmpty(savedItem.ammotype)) weapon.primaryMagazine.ammoType = ItemManager.FindItemDefinition(savedItem.ammotype);
weapon.primaryMagazine.contents = savedItem.ammo;
}
else if (savedItem.ammo > 0) {
FlameThrower flameThrower = heldEntity as FlameThrower;
if (flameThrower != null) flameThrower.ammo = savedItem.ammo;
else {
Chainsaw chainsaw = heldEntity as Chainsaw;
if (chainsaw != null) chainsaw.ammo = savedItem.ammo;
}
}
item.MarkDirty();
if (!item.MoveToContainer(container, savedItem.position)) player.GiveItem(item);
return item;
}
void StorePlayerMods(BasePlayer player, PCDInfo playerData) {
playerData.Modifiers = SaveModifiers(player);
player.modifiers.RemoveAll();
player.modifiers.SendChangesToClient();
}
void StorePlayerMetabolism(BasePlayer player, PCDInfo playerData) {
playerData.Metabolism = SaveMetabolism(player);
playerData.Health = player.health;
player.metabolism.Reset();
player.metabolism.calories.SetValue(player.metabolism.calories.max);
player.metabolism.hydration.SetValue(player.metabolism.hydration.max);
player.metabolism.SendChanges();
player.SetHealth(player.MaxHealth());
}
string SaveModifiers(BasePlayer player) {
ProtoBuf.PlayerModifiers snapshot = player.modifiers.Save(true);
byte[] bytes = snapshot.ToProtoBytes();
return Convert.ToBase64String(bytes);
// encode byte array to utf8 string
}
string SaveMetabolism(BasePlayer player) {
ProtoBuf.PlayerMetabolism snapshot = player.metabolism.Save();
byte[] bytes = snapshot.ToProtoBytes();
return Convert.ToBase64String(bytes);
// encode byte array to utf8 string
}
ContainerType GetContainer(BasePlayer player, ItemContainer container) {
if (container.uid == player.inventory.containerBelt.uid) return ContainerType.Belt;
else if (container.uid == player.inventory.containerWear.uid) return ContainerType.Wear;
else if (container.uid == player.inventory.containerMain.uid) return ContainerType.Main;
else return ContainerType.None;
}
bool HasProhibitedItems(BasePlayer player) {
var items = AllItems(player);
try {
if (config.black_listed_items == null || config.black_listed_items.Count == 0 || items.Count == 0) return false;
foreach (var item in items) {
if (config.black_listed_items.Contains(item.info.shortname)) {
PrintToChat(player, string.Format(lang.GetMessage("BlackListedItem", this, player.UserIDString), item.info.displayName.english));
return true;
}
if (item.contents != null && item.contents.itemList != null && item.contents.itemList.Count > 1) {
foreach (var sub_item in item.contents.itemList) {
if (config.black_listed_items.Contains(sub_item.info.shortname)) {
PrintToChat(player, string.Format(lang.GetMessage("BlackListedItemSub", this, player.UserIDString), item.info.displayName.english, item.info.displayName.english));
return true;
}
}
}
}
}
finally {
Pool.FreeUnmanaged(ref items);
}
return false;
}
private bool HasItemsStored(ulong id) {
var playerData = GetPlayer(id);
if (playerData.Items.Count == 0) return false;
return true;
}
bool IsPlayerSetup(ulong id) {
return pcdData.pEntity.ContainsKey(id);
}
PCDInfo GetPlayer(ulong id, bool create = true) {
PCDInfo result;
if (pcdData.pEntity.TryGetValue(id, out result)) return result;
if (!create) return null;
pcdData.pEntity.Add(id, result = new PCDInfo());
return result;
}
void RestoreStats(BasePlayer player, PCDInfo playerData) {
if (player.IsDead() || !player.IsConnected) return;
bool madeChange = false;
if (LoadMetabolism(player, playerData)) madeChange = true;
if (playerData.Health > 0) {
player.health = playerData.Health;
playerData.Health = 0;
madeChange = true;
}
if (playerData.Location != Vector3.zero) {
TeleportToEvent(player, playerData.Location, false);
playerData.Location = Vector3.zero;
madeChange = true;
}
if (madeChange) {
player.State.unHostileTimestamp = Network.TimeEx.currentTimestamp;
player.MarkHostileFor(0);
}
DestroyTempRestriction(player);
}
bool LoadMetabolism(BasePlayer player, PCDInfo playerData) {
if (string.IsNullOrEmpty(playerData.Metabolism)) return false;
if (player.IsWounded()) player.RecoverFromWounded();
byte[] bytes = Convert.FromBase64String(playerData.Metabolism);
ProtoBuf.PlayerMetabolism snapshot = ProtoBuf.PlayerMetabolism.Deserialize(bytes);
player.metabolism.Load(snapshot);
playerData.Metabolism = null;
return true;
}
void LoadModifiers(BasePlayer player, PCDInfo playerData) {
if (string.IsNullOrEmpty(playerData.Modifiers)) return;
byte[] bytes = Convert.FromBase64String(playerData.Modifiers);
ProtoBuf.PlayerModifiers snapshot = ProtoBuf.PlayerModifiers.Deserialize(bytes);
player.modifiers.Load(snapshot, true);
playerData.Modifiers = null;
}
void StorePlayerInfo(BasePlayer player, bool StoreHealth, bool StoreStats, bool StoreTemp) {
var playerData = GetPlayer(player.userID);
StorePlayerMods(player, playerData);
StorePlayerMetabolism(player, playerData);
player.metabolism.bleeding.SetValue(0);
player.metabolism.radiation_level.SetValue(0);
player.metabolism.radiation_poison.SetValue(0);
player.SetHealth(100f);
if (StoreTemp) AddTempRestriction(player);
playerData.Location = player.transform.position;
}
void TeleportToEvent(BasePlayer player, Vector3 loc, bool toLobby) {
if (loc == Vector3.zero) return;
player.SetParent(null, worldPositionStays : true);
Player.Teleport(player, loc);
player.ForceUpdateTriggers();
player.ClientRPC(RpcTarget.Player("StartLoading_Quick", player), arg1 : true);
player.UpdateNetworkGroup();
player.SetPlayerFlag(BasePlayer.PlayerFlags.ReceivingSnapshot, true);
BasePlayer.ResetAntiHack(player, AntiHack.PlayerStates, AntiHack.PlayerNoclipStates, AntiHack.PlayerSpeedhackStates, AntiHack.PlayerFlyhackStates);
player.PauseFlyHackDetection(3f);
player.PauseSpeedHackDetection(3f);
player.ApplyStallProtection(4f);
if (!toLobby) player.StartSleeping();
if (config.clear_stuck_entities) {
if (player.children != null) {
List<BaseEntity> stuck = Pool.Get<List<BaseEntity>>();
foreach (var child in player.children) {
if (child.PrefabName == "assets/prefabs/misc/burlap sack/generic_world.prefab") {
var item = child.GetItem();
if (item != null) {
var heldEntity = item.GetHeldEntity();
if ((heldEntity != null && heldEntity is BaseMelee) || item.info.shortname.StartsWith("arrow.") || item.info.shortname.Equals("ammo.nailgun.nails")) stuck.Add(child);
}
}
}
foreach (var child in stuck) {
child.KillMessage();
}
Pool.FreeUnmanaged(ref stuck);
}
}
}
void RemoveFromEvent(BasePlayer player, string eventName) {
if (!IsPlayerSetup(player.userID)) return;
var playerData = GetPlayer(player.userID);
playerData.AtEvent = false;
EventInfo ei;
if (eventName != null) Events.TryGetValue(eventName, out ei);
else ei = null;
ei.participants.Remove(player);
}
BasePlayer FindPlayerByID(string id, BasePlayer searchingPlayer = null) {
if (!id.IsSteamId()) return null;
var player = BasePlayer.allPlayerList.Where(x => x.UserIDString == id).FirstOrDefault();
if (player == null) {
if (searchingPlayer != null) PrintToChat(searchingPlayer, string.Format(lang.GetMessage("NoMatch", this), id));
else Puts(string.Format(lang.GetMessage("NoMatch", this), id));
}
return player ?? null;
}
private BasePlayer FindPlayerByName(string Playername, BasePlayer SearchingPlayer = null) {
var lowered = Playername.ToLower();
var targetList = BasePlayer.allPlayerList.Where(x => x.displayName.ToLower().Contains(lowered)).OrderBy(x => x.displayName.Length);
if (targetList.Count() == 1) {
return targetList.First();
}
if (targetList.Count() > 1) {
if (targetList.First().displayName.Equals(Playername, StringComparison.OrdinalIgnoreCase)) {
return targetList.First();
}
if (SearchingPlayer != null) {
PrintToChat(SearchingPlayer, string.Format(lang.GetMessage("MorePlayersFound", this, SearchingPlayer.UserIDString), String.Join(",", targetList.Select(x => x.displayName))));
}
else Puts(string.Format(lang.GetMessage("MorePlayersFound", this), String.Join(",", targetList.Select(x => x.displayName))));
return null;
}
if (targetList.Count() == 0) {
if (SearchingPlayer != null) {
PrintToChat(SearchingPlayer, string.Format(lang.GetMessage("NoMatch", this, SearchingPlayer.UserIDString), Playername));
}
else Puts(string.Format(lang.GetMessage("NoMatch", this), Playername));
return null;
}
return null;
}
public bool AddBan(BasePlayer player, string event_name) {
if (!pcdData.banned_players.ContainsKey(event_name)) pcdData.banned_players.Add(event_name, new List<ulong>());
if (!pcdData.banned_players[event_name].Contains(player.userID)) {
pcdData.banned_players[event_name].Add(player.userID);
SaveData();
return true;
}
return false;
}
public bool RemoveBan(BasePlayer player, string event_name) {
if (!pcdData.banned_players.ContainsKey(event_name) || !pcdData.banned_players[event_name].Contains(player.userID)) return false;
pcdData.banned_players[event_name].Remove(player.userID);
SaveData();
return true;
}
#endregion
#region Event Stuff
string LastEvent;
List<string> automatic_Events = new List<string>();
void StartNextEvent() {
if (config.minimum_players_online_auto_start > 0 && BasePlayer.activePlayerList?.Count < config.minimum_players_online_auto_start) {
Puts($"Attmempted to start a game, but there are not enough players online [{BasePlayer.activePlayerList?.Count}/{config.minimum_players_online_auto_start}].");
return;
}
if (Events == null || Events.Count == 0 || automatic_Events.Count == 0) return;
foreach (var _event in Events) if (_event.Value.manually_started) {
Puts($"Attempted to start a new event, but {_event.Key} is still flagged as manually started.");
return;
}
if (LastEvent != null && Events.ContainsKey(LastEvent) && !Events[LastEvent].manually_started) {
Interface.CallHook("EMEndGame", LastEvent);
EMEndEvent(LastEvent);
}
if (LastEvent == null) {
Interface.CallHook("EMStartNextEvent", automatic_Events.First());
Puts($"Attempting to start: {automatic_Events.First()}. Events: {string.Join(", ", automatic_Events)}");
LastEvent = automatic_Events.First();
SendDiscordMsg(string.Format(lang.GetMessage("DiscordMessageEventStarted", this), automatic_Events.First().TitleCase()));
}
else {
var foundLastEvent = false;
var setNewEvent = false;
foreach (var e in automatic_Events) {
if (Events[e].manually_started) continue;
if (foundLastEvent) {
Interface.CallHook("EMStartNextEvent", e);
Puts($"Attempting to start: {e}. Events: {string.Join(", ", automatic_Events)}");
LastEvent = e;
setNewEvent = true;
SendDiscordMsg(string.Format(lang.GetMessage("DiscordMessageEventStarted", this), e.TitleCase()));
break;
}
else if (e == LastEvent) foundLastEvent = true;
}
if (!setNewEvent) {
var e = automatic_Events.First();
if (!Events[e].manually_started) {
Interface.CallHook("EMStartNextEvent", e);
Puts($"Attempting to start: {e}. Events: {string.Join(", ", automatic_Events)}");
LastEvent = e;
}
else Puts(lang.GetMessage("SkipStart", this));
}
}
}
[HookMethod("EMWasManuallyStarted")]
public bool EMWasManuallyStarted(string eventName) {
EventInfo ei;
if (Events.TryGetValue(eventName, out ei)) {
return ei.manually_started;
}
return false;
}
[HookMethod("EMManuallyStarted")]
public void EMManuallyStarted(string eventName) {
EventInfo ei;
if (Events.TryGetValue(eventName, out ei)) {
ei.manually_started = true;
Puts(string.Format(lang.GetMessage("ManualStart", this), eventName));
}
}
[HookMethod("EMEventEnded")]
public void EMEventEnded(string eventName) {
if (!Events.TryGetValue(eventName, out var ei)) return;
ei.manually_started = false;
}
[HookMethod("EMRemoveEvent")]
public void EMRemoveEvent(string eventName) {
Interface.CallHook("EMEndGame", eventName);
EventInfo ei;
if (Events.TryGetValue(eventName, out ei)) {
if (ei.participants.Count > 0) {
foreach (var player in ei.participants.ToList()) {
EMPlayerLeaveEvent(player, eventName);
}
}
if (ei.automatic_start) automatic_Events.Remove(eventName);
}
Events.Remove(eventName);
Puts(string.Format(lang.GetMessage("RemovedEvent", this), eventName));
}
[HookMethod("EMCreateEvent")]
private void EMCreateEvent(string eventName, bool automatic_start, bool stripItems, bool leaves_event_on_death, bool full_health_on_join, bool give_items_back_on_respawn, bool full_metabolism_on_join, Vector3 teleport_destination, bool restricted_metabolism = true, bool allow_teams = true) {
if (Events.ContainsKey(eventName)) EMRemoveEvent(eventName);
EventInfo ei;
Events.Add(eventName, ei = new EventInfo(automatic_start, stripItems, leaves_event_on_death, full_health_on_join, give_items_back_on_respawn, full_metabolism_on_join, teleport_destination, restricted_metabolism, allow_teams));
Puts(lang.GetMessage("SetupEvent", this), eventName);
if (automatic_start && !automatic_Events.Contains(eventName)) {
automatic_Events.Add(eventName);
}
}
[HookMethod("EMUpdateLobby")]
private void EMUpdateLobby(string eventName, Vector3 pos) {
EventInfo ei;
if (!Events.TryGetValue(eventName, out ei)) return;
ei.teleport_destination = pos;
}
[HookMethod("EMStartEvent")]
private void EMStartEvent(string eventName) {
EventInfo ei;
if (!Events.TryGetValue(eventName, out ei)) return;
if (!EventRunning.ContainsKey(eventName)) EventRunning.Add(eventName, true);
else EventRunning[eventName] = true;
SendDiscordMsg(string.Format(lang.GetMessage("DiscordMessageEventStarted", this), eventName.TitleCase()));
}
[HookMethod("EMEndEvent")]
private void EMEndEvent(string eventName) {
if (EventRunning.ContainsKey(eventName)) {
EventInfo ei;
if (eventName == null || !Events.TryGetValue(eventName, out ei)) return;
if (ei.participants.Count > 0) {
foreach (var player in ei.participants.ToList()) {
EMPlayerLeaveEvent(player, eventName);
}
}
ei.participants.Clear();
ei.manually_started = false;
if (!ei.allow_Teams) {
HandleEndGameRestoration();
SetLeaders();
ClearTeamCache();
}
EventRunning.Remove(eventName);
//Interface.CallHook("EMEndGame", eventName);
Puts(lang.GetMessage("EndedEvent", this));
}
}
[HookMethod("EMEnrollPlayer")]
private bool EMEnrollPlayer(BasePlayer player, string eventName) {
EventInfo ei;
if (!Events.TryGetValue(eventName, out ei)) {
Puts(string.Format(lang.GetMessage("EventNotRegistered", this), eventName));
return false;
}
if (ei.participants.Contains(player)) {
PrintToChat(player, lang.GetMessage("AlreadyEnrolled", this, player.UserIDString));
return false;
}
var playerData = GetPlayer(player.userID);
if (!CanJoinEvent(player, eventName, playerData)) return false;
if (ei.strip_items && !StorePlayerItems(player, playerData)) {
ulong userID = player.userID;
ServerMgr.Instance.Invoke(() => {
if (RestoreItems(player, playerData)) {
Interface.Oxide.CallHook("OnPlayerItemsRestored", player);
pcdData.pEntity.Remove(player.userID);
}
}
, 1);
PrintToChat(player, lang.GetMessage("FailedToStrip", this, player.UserIDString));
return false;
}
StorePlayerInfo(player, ei.full_health_on_join, ei.full_metabolism_on_join, ei.restricted_temp);
if (!ei.allow_Teams) HandleTeam(player, true);
ei.participants.Add(player);
TeleportToEvent(player, ei.teleport_destination, true);
playerData.AtEvent = true;
playerData.Event = eventName;
Interface.CallHook("EMOnEventJoined", player, eventName);
if (config.announce_player_join) AnnouncePlayerJoin(player, eventName);
return true;
}
void AnnouncePlayerJoin(BasePlayer player, string eventName) {
string prefix = Convert.ToString(Interface.CallHook("EMGetAnnounceJoinPrefix", player, eventName));
string message = ValidJoinMessages.Count > 0 ? ValidJoinMessages.GetRandom() : "JointAnnounceMsg_1";
var eventTitle = eventName.TitleCase();
foreach (var p in BasePlayer.activePlayerList) PrintToChat(p, (!string.IsNullOrEmpty(prefix) ? prefix + " " : null) + string.Format(lang.GetMessage(message, this, p.UserIDString), player.displayName, eventTitle));
}
List<string> ValidJoinMessages = new List<string>();
[HookMethod("EMPlayerLeaveEvent")]
private void EMPlayerLeaveEvent(BasePlayer player, string eventName = null, bool manually_left = false) {
if (!IsPlayerSetup(player.userID)) {
if (manually_left) PrintToChat(player, lang.GetMessage("NoEventData", this, player.UserIDString));
return;
}
var playerData = GetPlayer(player.userID);
EventInfo ei;
if (eventName != null) Events.TryGetValue(eventName, out ei);
else ei = null;
WasAtEvent[player.userID] = playerData.Event;
RemoveFromEvent(player, playerData.Event);
timer.Once(1f, () => WasAtEvent.Remove(player.userID));
RestoreStats(player, playerData);
playerData.StripOnItemRestore = true;
if (ei == null || ei.give_items_back_automatically) playerData.RestoreOnWake = true;
playerData.AtEvent = false;
if (!ei.give_items_back_automatically && playerData.Items.Count > 0) PrintToChat(player, string.Format(lang.GetMessage("ManualItemRecovery", this, player.UserIDString), config.redeem_items_command));
if (!ei.allow_Teams) HandleTeam(player, false);
Interface.CallHook("EMOnEventLeft", player, eventName);
}
//Related to chat commandf
void RestoreItemsCMD(BasePlayer player) {
HandleFromCMD(player);
}
void HandleFromCMD(BasePlayer player) {
var playerData = GetPlayer(player.userID, false);
if (playerData == null) {
PrintToChat(player, "No data.");
return;
}
bool needsTP = playerData.Location != Vector3.zero;
RestoreStats(player, playerData);
playerData.StripOnItemRestore = false;
PrintToChat(player, "Restoring items.");
if (!needsTP) player.Invoke(() => HandleItemRestore(player, playerData), 1);
else playerData.RestoreOnWake = true;
}
#endregion
#region API Stuff
List<Item> AllItems(BasePlayer player) {
List<Item> result = Pool.Get<List<Item>>();
if (player.inventory.containerMain?.itemList != null) result.AddRange(player.inventory.containerMain.itemList);
if (player.inventory.containerBelt?.itemList != null) result.AddRange(player.inventory.containerBelt.itemList);
if (player.inventory.containerWear?.itemList != null) result.AddRange(player.inventory.containerWear.itemList);
return result;
}
[HookMethod("EMPlayerDiedAtEvent")]
public bool EMPlayerDiedAtEvent(BasePlayer player) {
if (EMAtEvent(player.userID)) return true;
return WasAtEvent.ContainsKey(player.userID);
}
[HookMethod("EMPlayerDiedAtSpecificEvent")]
public bool EMPlayerDiedAtSpecificEvent(BasePlayer player, string eventName) {
if (EMIsParticipating(player, eventName)) return true;
string wasEvent;
if (WasAtEvent.TryGetValue(player.userID, out wasEvent) && wasEvent.Equals(eventName, StringComparison.OrdinalIgnoreCase)) return true;
return false;
}
object STOnPouchOpen(BasePlayer player) {
if (EMAtEvent(player.userID)) return true;
return null;
}
[HookMethod("EMExternalPluginSettings")]
void EMExternalPluginSettings(string eventName, bool canDropBackpack = false, bool canEraseBackpack = false, bool canOpenBackpack = false, bool canBackpackAcceptItem = false, bool canRedeemKit = false, bool CanLoseXP = false) {
EventInfo ei;
if (!Events.TryGetValue(eventName, out ei)) {
Puts(string.Format(lang.GetMessage("EventNotSetupExternalPluginSettings", this), eventName));
return;
}
Puts($"Setting up external plugin settings: eventName: {eventName}. canDropBackpack: {canDropBackpack}. canEraseBackpack: {canEraseBackpack}. canOpenBackpack: {canOpenBackpack}. canBackpackAcceptItem: {canBackpackAcceptItem}. canRedeemKit: {canRedeemKit}. CanLoseXP: {CanLoseXP}.");
ei.external_plugin_settings = new EventInfo.ExternalPluginSettings(canDropBackpack, canEraseBackpack, canOpenBackpack, canBackpackAcceptItem, canRedeemKit, CanLoseXP);
}
[HookMethod("EMBlackListCommands")]
void EMBlackListCommands(string eventName, string[] commands) {
// ... [Code preview truncated due to length. Full source in attached file] ...