C#:
// Requires: ArenaUI
using CompanionServer;
using Facepunch;
using Network;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Configuration;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEngine;
using UI = Oxide.Plugins.ArenaUI.UI;
using UI4 = Oxide.Plugins.ArenaUI.UI4;
///Скачано с дискорд сервера Rust Edit [PRO+]
///discord.gg/9vyTXsJyKR
namespace Oxide.Plugins
{
using ArenaEx;
[Info("Arena", "discord.gg/9vyTXsJyKR", "2.0.24"), Description("The core mechanics for arena combat games")]
public class Arena : RustPlugin
{
#region Fields
[PluginReference]
internal Plugin Economics, Kits, NoEscape, RotatingPickups, ServerRewards, Spawns, ZoneManager;
private int scrapItemId;
private static Regex hexFilter;
private static DropOnDeath dropOnDeath = DropOnDeath.Nothing;
public Hash<string, IEventPlugin> EventModes { get; set; } = new Hash<string, IEventPlugin>();
public Hash<string, BaseEventGame> ActiveEvents { get; set; } = new Hash<string, BaseEventGame>();
public EventData Events { get; private set; }
private RestoreData Restore { get; set; }
private LobbyHandler Lobby { get; set; }
public static Arena Instance { get; private set; }
public static ConfigData Configuration { get; set; }
public static bool IsUnloading { get; private set; }
internal const string ADMIN_PERMISSION = "arena.admin";
internal const string BLACKLISTED_PERMISSION = "arena.blacklisted";
private const string RESPAWN_BAG_CMD = "respawn_sleepingbag";
private const string REMOVE_BAG_CMD = "respawn_sleepingbag_remove";
private const string RESPAWN_CMD = "respawn";
private const uint LOBBY_BAG_ID = 113;
#endregion
#region Oxide Hooks
private void Loaded()
{
LoadData();
permission.RegisterPermission(ADMIN_PERMISSION, this);
permission.RegisterPermission(BLACKLISTED_PERMISSION, this);
hexFilter = new Regex("^([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$");
Instance = this;
IsUnloading = false;
}
protected override void LoadDefaultMessages() => lang.RegisterMessages(Messages, this);
private void OnServerInitialized()
{
if (!CheckDependencies())
return;
if (Configuration.Server.DisableServerEvents)
ConVar.Server.events = false;
if (!Configuration.Server.UseChat)
Unsubscribe(nameof(OnPlayerChat));
if (!Configuration.Event.AddToTeams)
{
Unsubscribe(nameof(OnTeamLeave));
Unsubscribe(nameof(OnTeamDisband));
Unsubscribe(nameof(OnTeamInvite));
Unsubscribe(nameof(OnTeamCreate));
}
Lobby = new LobbyHandler(Configuration.Lobby.LobbySpawnfile);
scrapItemId = ItemManager.FindItemDefinition("scrap").itemid;
dropOnDeath = ParseType<DropOnDeath>(Configuration.Event.DropOnDeath);
foreach (BasePlayer player in BasePlayer.activePlayerList)
OnPlayerConnected(player);
Debug.Log($"[Arena] - Loading event games in 5 seconds...");
timer.In(5, InitializeEvents);
}
private void Unload()
{
IsUnloading = true;
SaveRestoreData();
foreach (BaseEventGame baseEventGame in ActiveEvents.Values)
UnityEngine.Object.Destroy(baseEventGame);
BaseEventPlayer[] eventPlayers = UnityEngine.Object.FindObjectsOfType<BaseEventPlayer>();
for (int i = 0; i < eventPlayers?.Length; i++)
UnityEngine.Object.DestroyImmediate(eventPlayers[i]);
DestroyTeleporters();
hexFilter = null;
Configuration = null;
Instance = null;
}
private void OnServerSave() => SaveRestoreData();
#endregion
#region Player Connect/Disconnect
private void OnPlayerConnected(BasePlayer player)
{
if (Configuration.Server.RestorePlayers)
TryRestorePlayer(player);
if (Lobby.ForceLobbyRespawn && player.IsDead())
{
NextTick(() => Lobby.SendRespawnOptions(player));
return;
}
if (Lobby.ForceLobbyRespawn && Configuration.Lobby.KeepPlayersInLobby && !player.IsAdmin && !permission.UserHasPermission(player.UserIDString, ADMIN_PERMISSION))
{
if (ZoneManager && !ZoneManager.Call<bool>("IsPlayerInZone", Configuration.Lobby.LobbyZoneID, player))
Lobby.TeleportToLobby(player);
}
}
private void OnPlayerDisconnected(BasePlayer player)
{
BaseEventPlayer eventPlayer = GetUser(player);
if (eventPlayer)
eventPlayer.Event.LeaveEvent(player);
}
private void OnPlayerRespawned(BasePlayer player)
{
if (Configuration.Server.RestorePlayers)
TryRestorePlayer(player);
}
private void TryRestorePlayer(BasePlayer player)
{
if (player.IsSleeping() || player.HasPlayerFlag(BasePlayer.PlayerFlags.ReceivingSnapshot))
{
timer.Once(1f, () => OnPlayerConnected(player));
return;
}
UnlockClothingSlots(player);
if (Restore.HasRestoreData(player.userID))
Restore.RestorePlayer(player);
}
private object OnDefaultItemsReceive(PlayerInventory playerInventory) => Lobby.ForceLobbyRespawn && !Configuration.Server.RestorePlayers ? (object)true : null;
#endregion
#region Damage
private void OnEntityTakeDamage(BaseEntity entity, HitInfo hitInfo)
{
if (!entity || hitInfo == null)
return;
BasePlayer player = entity.ToPlayer();
if (player != null)
{
BaseEventPlayer eventPlayer = GetUser(player);
if (eventPlayer)
{
eventPlayer.Event.OnPlayerTakeDamage(eventPlayer, hitInfo);
}
}
else
{
BaseEventPlayer attacker = GetUser(hitInfo.InitiatorPlayer);
if (attacker != null)
{
if (attacker.Event.CanDealEntityDamage(attacker, entity, hitInfo))
return;
ClearDamage(hitInfo);
}
}
}
// TruePVE bypass
private object CanEntityTakeDamage(BaseCombatEntity baseCombatEntity, HitInfo hitInfo)
{
if (!baseCombatEntity || !(baseCombatEntity is BasePlayer))
return null;
return GetUser((baseCombatEntity as BasePlayer)) != null ? (object)true : null;
}
private object CanBeWounded(BasePlayer player, HitInfo hitInfo)
{
BaseEventPlayer eventPlayer = GetUser(player);
if (eventPlayer)
return false;
return null;
}
private object OnPlayerDeath(BasePlayer player, HitInfo hitInfo)
{
if (player != null)
{
BaseEventPlayer eventPlayer = GetUser(player);
if (eventPlayer)
{
if (!eventPlayer.IsDead)
eventPlayer.Event.PrePlayerDeath(eventPlayer, hitInfo);
return false;
}
}
return null;
}
private void OnEntityDeath(BasePlayer player, HitInfo hitInfo)
{
if (Lobby.ForceLobbyRespawn)
NextTick(() => Lobby.SendRespawnOptions(player));
}
#endregion
#region Spectate
private object CanSpectateTarget(BasePlayer player, string name)
{
BaseEventPlayer eventPlayer = player.GetComponent<BaseEventPlayer>();
if (eventPlayer && eventPlayer.Player.IsSpectating())
{
eventPlayer.UpdateSpectateTarget();
return false;
}
return null;
}
#endregion
#region Spawned Entities
private void OnEntityBuilt(Planner planner, GameObject gameObject)
{
BasePlayer player = planner?.GetOwnerPlayer();
if (!player)
return;
BaseCombatEntity baseCombatEntity = gameObject?.ToBaseEntity() as BaseCombatEntity;
if (baseCombatEntity == null)
return;
BaseEventPlayer eventPlayer = GetUser(player);
if (eventPlayer)
eventPlayer.Event.OnEntityDeployed(baseCombatEntity);
}
private void OnItemDeployed(Deployer deployer, BaseCombatEntity baseCombatEntity)
{
BasePlayer player = deployer.GetOwnerPlayer();
if (!player)
return;
BaseEventPlayer eventPlayer = GetUser(player);
if (eventPlayer)
eventPlayer.Event.OnEntityDeployed(baseCombatEntity);
}
private object OnCreateWorldProjectile(HitInfo hitInfo, Item item)
{
if (hitInfo == null)
return null;
if (hitInfo.InitiatorPlayer != null)
{
BaseEventPlayer eventPlayer = GetUser(hitInfo.InitiatorPlayer);
if (eventPlayer)
return false;
}
if (hitInfo.HitEntity?.ToPlayer() != null)
{
BaseEventPlayer eventPlayer = GetUser(hitInfo.HitEntity.ToPlayer());
if (eventPlayer)
return false;
}
return null;
}
private void OnItemDropped(Item item, WorldItem worldItem)
{
BasePlayer player = item.GetOwnerPlayer();
if (player != null)
{
BaseEventPlayer eventPlayer = GetUser(player);
if (eventPlayer)
{
eventPlayer.Event.OnWorldItemDropped(worldItem);
}
}
}
#endregion
#region Items
private object CanDropActiveItem(BasePlayer player)
{
BaseEventPlayer eventPlayer = GetUser(player);
if (eventPlayer && (!eventPlayer.Event.CanDropActiveItem() || player.health <= 0f))
return false;
return null;
}
private string CanOpenBackpack(BasePlayer player, ulong backpackOwnerID)
{
BaseEventPlayer eventPlayer = GetUser(player);
if (eventPlayer)
return "You can not open your backpack during an event";
return null;
}
#endregion
#region Command Blacklist
private object OnPlayerCommand(BasePlayer player, string command, string[] args)
{
BaseEventPlayer eventPlayer = GetUser(player);
if (!player || player.IsAdmin || !eventPlayer)
return null;
if (Configuration.Event.CommandBlacklist.Any(x => x.StartsWith("/") ? x.Substring(1).Equals(command, StringComparison.OrdinalIgnoreCase) : x.Equals(command, StringComparison.OrdinalIgnoreCase)))
{
SendReply(player, Message("Error.CommandBlacklisted", player.userID));
return false;
}
return null;
}
private object OnServerCommand(ConsoleSystem.Arg arg)
{
BasePlayer player = arg.Player();
if (!player || !player.IsConnected)
return null;
if (Lobby.ForceLobbyRespawn && (player.IsDead() || player.IsSpectating()))
{
if (arg.cmd.Name == RESPAWN_CMD)
{
Lobby.RespawnAtLobby(player);
return false;
}
if (arg.cmd.Name == REMOVE_BAG_CMD)
{
uint num = arg.GetUInt(0, 0);
if (num == LOBBY_BAG_ID)
return false;
}
if (arg.cmd.Name == RESPAWN_BAG_CMD)
{
uint num = arg.GetUInt(0, 0);
if (num == LOBBY_BAG_ID)
{
Lobby.RespawnAtLobby(player);
return false;
}
}
}
BaseEventPlayer eventPlayer = GetUser(player);
if (player.IsAdmin || !eventPlayer || arg.Args == null)
return null;
if (Configuration.Event.CommandBlacklist.Any(x => arg.cmd.FullName.Equals(x, StringComparison.OrdinalIgnoreCase)))
{
SendReply(player, Message("Error.CommandBlacklisted", player.userID));
return false;
}
return null;
}
#endregion
#region Chat Handler
private object OnPlayerChat(BasePlayer player, string message, ConVar.Chat.ChatChannel channel)
{
if (!player || player.IsAdmin || permission.UserHasPermission(player.UserIDString, "arena.admin"))
return null;
BaseEventPlayer eventPlayer = GetUser(player);
if (eventPlayer)
{
eventPlayer.Event.BroadcastToPlayers(player, message);
}
else
{
foreach (BasePlayer otherPlayer in BasePlayer.activePlayerList)
{
if (!GetUser(otherPlayer))
otherPlayer.SendConsoleCommand("chat.add", new object[] { 0, player.UserIDString, $"<color={(player.IsAdmin ? "#aaff55" : player.IsDeveloper ? "#fa5" : "#55AAFF")}>{player.displayName}</color>: {message}" });
}
}
return false;
}
#endregion
#region Teams
private object OnTeamLeave(RelationshipManager.PlayerTeam playerTeam, BasePlayer player)
{
BaseEventPlayer eventPlayer = GetUser(player);
if (!eventPlayer)
return null;
if (eventPlayer.Event.Plugin.IsTeamEvent)
return true;
return null;
}
private object OnTeamDisband(RelationshipManager.PlayerTeam playerTeam)
{
foreach (BaseEventGame baseEventGame in ActiveEvents.Values)
{
if (baseEventGame.IsEventTeam(playerTeam.teamID))
return true;
}
return null;
}
private object OnTeamInvite(BasePlayer player, BasePlayer other)
{
BaseEventPlayer eventPlayer = GetUser(player);
if (eventPlayer)
return true;
return null;
}
private object OnTeamCreate(BasePlayer player)
{
BaseEventPlayer eventPlayer = GetUser(player);
if (eventPlayer)
return true;
return null;
}
#endregion
#region Event Construction
public static void RegisterEvent(string eventName, IEventPlugin plugin) => Instance.EventModes[eventName] = plugin;
public static void UnregisterEvent(string eventName)
{
Instance.EventModes.Remove(eventName);
for (int i = Instance.ActiveEvents.Count - 1; i >= 0; i--)
{
KeyValuePair<string, BaseEventGame> kvp = Instance.ActiveEvents.ElementAt(i);
if (kvp.Value.Config.EventType.Equals(eventName))
{
kvp.Value.EndEvent();
UnityEngine.Object.Destroy(kvp.Value);
Instance.ActiveEvents.Remove(kvp.Key);
}
}
}
private void InitializeEvents()
{
foreach (string eventName in Events.events.Keys)
{
object success = OpenEvent(eventName);
if (success is string)
Debug.LogWarning($"[Arena] - {(string)success}");
}
}
public object OpenEvent(string eventName)
{
EventConfig eventConfig;
if (Events.events.TryGetValue(eventName, out eventConfig))
{
if (!string.IsNullOrEmpty(eventConfig.Permission) && !permission.PermissionExists(eventConfig.Permission))
permission.RegisterPermission(eventConfig.Permission, this);
if (eventConfig.IsDisabled)
return $"The event {eventName} is disabled";
IEventPlugin iEventPlugin;
if (!EventModes.TryGetValue(eventConfig.EventType, out iEventPlugin) || iEventPlugin == null)
return $"Unable to find event plugin for game mode: {eventConfig.EventType}";
object success = ValidateEventConfig(eventConfig);
if (success is string)
return $"Failed to open event {eventName} : {(string)success}";
if (!iEventPlugin.InitializeEvent(eventConfig))
return $"The event {eventName} is already active";
return null;
}
else return "Failed to find a event with the specified name";
}
public static bool InitializeEvent<T>(IEventPlugin plugin, EventConfig config) where T : BaseEventGame
{
if (Instance.ActiveEvents.ContainsKey(config.EventName))
return false;
BaseEventGame eventGame = new GameObject(config.EventName).AddComponent<T>();
eventGame.InitializeEvent(plugin, config);
Instance.ActiveEvents[config.EventName] = eventGame;
return true;
}
public static void ShutdownEvent(string eventName)
{
BaseEventGame baseEventGame;
if (Instance.ActiveEvents.TryGetValue(eventName, out baseEventGame))
{
Instance.ActiveEvents.Remove(eventName);
UnityEngine.Object.Destroy(baseEventGame);
}
}
#endregion
#region Functions
public BaseEventGame FindEvent(string name)
{
BaseEventGame baseEventGame;
ActiveEvents.TryGetValue(name, out baseEventGame);
return baseEventGame;
}
public IEventPlugin GetPlugin(string name)
{
IEventPlugin eventPlugin;
if (EventModes.TryGetValue(name, out eventPlugin))
return eventPlugin;
return null;
}
private bool CheckDependencies()
{
if (!Spawns)
{
PrintError("Unable to load Arena - Spawns database not found.Please download Spawns database to continue");
rust.RunServerCommand("oxide.unload", "Arena");
return false;
}
if (!ZoneManager)
PrintError("ZoneManager is not installed! Unable to restrict event players to zones");
if (!Kits)
PrintError("Kits is not installed! Unable to issue any weapon kits");
return true;
}
internal void TeleportPlayer(BasePlayer player, string spawnFile, bool sleep = false)
{
ResetMetabolism(player);
object spawnPoint = Spawns?.Call("GetRandomSpawn", spawnFile);
if (spawnPoint is Vector3)
TeleportPlayer(player, (Vector3)spawnPoint, sleep);
}
private static void Broadcast(string key, params object[] args)
{
foreach (BasePlayer player in BasePlayer.activePlayerList)
player?.SendConsoleCommand("chat.add", 0, Configuration.Message.ChatIcon, string.Format(Message(key, player.userID), args));
}
internal static void GetEventsOfType(string eventType, List<BaseEventGame> list)
{
foreach (BaseEventGame eventGame in Instance.ActiveEvents.Values)
{
if (eventGame.Config.EventType.Equals(eventType, StringComparison.OrdinalIgnoreCase))
list.Add(eventGame);
}
}
internal static bool HasActiveEventsOfType(string eventType)
{
foreach (BaseEventGame eventGame in Instance.ActiveEvents.Values)
{
if (eventGame.Config.EventType.Equals(eventType, StringComparison.OrdinalIgnoreCase))
return true;
}
return false;
}
internal static void GetRegisteredEvents(List<IEventPlugin> list)
{
list.AddRange(Instance.EventModes.Values);
list.Sort((IEventPlugin a, IEventPlugin b) =>
{
return a.EventName.CompareTo(b.EventName);
});
}
internal static bool IsValidHex(string s) => hexFilter.IsMatch(s);
#endregion
#region Classes and Components
public abstract class BaseEventGame : MonoBehaviour
{
internal IEventPlugin Plugin { get; private set; }
internal EventConfig Config { get; private set; }
public EventStatus Status { get; protected set; }
protected GameTimer Timer { get; set; }
internal RewardType RewardType { get; private set; }
protected CuiElementContainer scoreContainer = null;
internal List<BaseEventPlayer> eventPlayers = Pool.GetList<BaseEventPlayer>();
internal List<BaseEventPlayer> joiningSpectators = Pool.GetList<BaseEventPlayer>();
internal List<ScoreEntry> scoreData = Pool.GetList<ScoreEntry>();
private List<BaseCombatEntity> _deployedObjects = Pool.GetList<BaseCombatEntity>();
private List<DroppedItemContainer> _droppedInventories = Pool.GetList<DroppedItemContainer>();
private List<WorldItem> _droppedItems = Pool.GetList<WorldItem>();
private List<PlayerCorpse> _droppedCorpses = Pool.GetList<PlayerCorpse>();
private readonly Hash<string, List<KeyValuePair<string, ulong>>> _kitBeltItems = new Hash<string, List<KeyValuePair<string, ulong>>>();
protected readonly HashSet<BaseEventPlayer> spectateTargets = new HashSet<BaseEventPlayer>();
internal HashSet<BaseEventPlayer> SpectateTargets { get { return spectateTargets; } }
private EventTeleporter _eventTeleporter;
private bool _isClosed = false;
protected int _roundNumber = 0;
internal int RoundNumber => _roundNumber;
internal EventTeam TeamA { get; private set; }
internal EventTeam TeamB { get; private set; }
public bool GodmodeEnabled { get; protected set; } = true;
public EventResults LastEventResult { get; private set; } = new EventResults();
internal string EventInformation
{
get
{
string str = string.Format(Message("Info.Event.Current"), Config.EventName, Config.EventType);
str += string.Format(Message("Info.Event.Player"), eventPlayers.Count, Config.MaximumPlayers);
return str;
}
}
internal string EventStatus => string.Format(Message("Info.Event.Status"), Status);
#region Initialization and Destruction
protected virtual void OnDestroy()
{
CleanupEntities();
StopAllSpectating();
for (int i = eventPlayers.Count - 1; i >= 0; i--)
{
BaseEventPlayer eventPlayer = eventPlayers[i];
LeaveEvent(eventPlayer);
}
for (int i = joiningSpectators.Count - 1; i >= 0; i--)
{
BaseEventPlayer eventPlayer = joiningSpectators[i];
LeaveEvent(eventPlayer);
}
Pool.FreeList(ref scoreData);
Pool.FreeList(ref _deployedObjects);
Pool.FreeList(ref _droppedItems);
Pool.FreeList(ref _droppedInventories);
Pool.FreeList(ref _droppedCorpses);
Pool.FreeList(ref eventPlayers);
Pool.FreeList(ref joiningSpectators);
spectateTargets.Clear();
TeamA?.Destroy();
TeamB?.Destroy();
Timer?.StopTimer();
DestroyTeleporter();
Destroy(gameObject);
}
internal virtual void InitializeEvent(IEventPlugin plugin, EventConfig config)
{
this.Config = config;
this.Plugin = this.Config.Plugin = plugin;
TeamA = new EventTeam(Team.A, config.TeamConfigA.Color, config.TeamConfigA.Clothing, new SpawnSelector(config.TeamConfigA.Spawnfile));
if (plugin.IsTeamEvent)
TeamB = new EventTeam(Team.B, config.TeamConfigB.Color, config.TeamConfigB.Clothing, new SpawnSelector(config.TeamConfigB.Spawnfile));
Timer = new GameTimer(this);
GodmodeEnabled = true;
RewardType = ParseType<RewardType>(Config.Rewards.Type);
Status = Arena.EventStatus.Open;
CreateTeleporter();
}
internal List<KeyValuePair<string, ulong>> GetItemsForKit(string kit)
{
List<KeyValuePair<string, ulong>> list;
if (!_kitBeltItems.TryGetValue(kit, out list))
{
JObject obj = Instance.Kits?.Call<JObject>("GetKitObject", kit);
if (obj == null)
{
Debug.LogError($"[Arena] - Kits failed to return data for kit : {kit}.Is this a valid kit name?");
return null;
}
list = _kitBeltItems[kit] = new List<KeyValuePair<string, ulong>>();
JArray jArray = obj["BeltItems"] as JArray;
foreach (JObject itemObj in jArray)
list.Add(new KeyValuePair<string, ulong>((string)itemObj["Shortname"], (ulong)itemObj["SkinID"]));
}
return list;
}
#endregion
#region Event Management
internal virtual void CloseEvent()
{
_isClosed = true;
BroadcastToPlayers("Notification.EventClosed");
}
protected virtual void StartEvent()
{
if (joiningSpectators.Count > 0)
{
joiningSpectators.ForEach((BaseEventPlayer eventPlayer) => eventPlayers.Add(eventPlayer));
joiningSpectators.Clear();
}
if (!HasMinimumRequiredPlayers())
{
BroadcastToPlayers("Notification.NotEnoughToStart");
EndEvent();
return;
}
//if (Config.UseEventBots && Config.MaximumBots > 0 && eventPlayers.Count < Config.MaximumPlayers)
// SpawnEventBots();
_roundNumber = 0;
LastEventResult.UpdateFromEvent(this);
Timer.StopTimer();
UpdateScoreboard();
Status = Arena.EventStatus.Started;
StartNextRound();
SetZoneOccupied(this, true);
}
protected virtual void StartNextRound()
{
if (!HasMinimumRequiredPlayers())
{
BroadcastToPlayers("Notification.NotEnoughToContinue");
EndEvent();
return;
}
CleanupEntities();
_roundNumber += 1;
if (Config.TimeLimit > 0)
Timer.StartTimer(Config.TimeLimit, string.Empty, EndRound);
GodmodeEnabled = false;
if (CanEnterBetweenRounds())
{
joiningSpectators.ForEach((BaseEventPlayer eventPlayer) => eventPlayers.Add(eventPlayer));
joiningSpectators.Clear();
}
//if (Config.UseEventBots && Config.MaximumBots > 0)
//{
// if (eventPlayers.Count > Config.MaximumPlayers)
// RemoveExcessBots();
// else if (eventPlayers.Count < Config.MaximumPlayers)
// SpawnEventBots();
//}
eventPlayers.ForEach((BaseEventPlayer eventPlayer) =>
{
if (!eventPlayer || !eventPlayer.Player)
return;
if (CanRespawnPlayer(eventPlayer))
{
if (eventPlayer.IsDead)
RespawnPlayer(eventPlayer);
else
{
ResetPlayer(eventPlayer.Player);
OnPlayerRespawn(eventPlayer);
}
}
});
RebuildSpectateTargets();
UpdateSpectatorTargets();
UpdateScoreboard();
}
protected virtual bool CanRespawnPlayer(BaseEventPlayer baseEventPlayer) => true;
protected virtual void EndRound()
{
UpdateScoreboard();
if (_roundNumber >= Config.RoundsToPlay)
{
BroadcastToPlayers("Notification.EventFinished");
InvokeHandler.Invoke(this, EndEvent, 1f);
}
else
{
GodmodeEnabled = true;
Timer.StopTimer();
LastEventResult.UpdateFromEvent(this);
if (Plugin.ProcessWinnersBetweenRounds)
ProcessWinners();
eventPlayers.ForEach((BaseEventPlayer eventPlayer) =>
{
if (!eventPlayer || !eventPlayer.Player)
return;
eventPlayer.ResetStatistics();
if (!CanRespawnPlayer(eventPlayer))
return;
if (eventPlayer.IsDead)
{
eventPlayer.OnRoundFinished();
RespawnPlayer(eventPlayer);
}
ArenaStatistics.Data.OnGamePlayed(eventPlayer.Player, Config.EventType);
});
ArenaStatistics.Data.OnGamePlayed(Config.EventType);
if (CanEnterBetweenRounds())
{
joiningSpectators.ForEach((BaseEventPlayer eventPlayer) =>
{
eventPlayers.Add(eventPlayer);
ResetPlayer(eventPlayer.Player);
OnPlayerRespawn(eventPlayer);
});
joiningSpectators.Clear();
}
RebuildSpectateTargets();
UpdateSpectatorTargets();
BroadcastToPlayers("Notification.NextRoundStartsIn", _roundNumber, Configuration.Timer.RoundInterval);
Timer.StartTimer(Configuration.Timer.RoundInterval, Message("Timer.NextRoundStartsIn"), StartNextRound);
}
}
internal virtual void EndEvent()
{
Timer.StopTimer();
bool wasPlaying = Status == Arena.EventStatus.Started;
Status = Arena.EventStatus.Finished;
GodmodeEnabled = true;
LastEventResult.UpdateFromEvent(this);
CleanupEntities();
SetZoneOccupied(this, true);
if (!IsUnloading && wasPlaying)
ProcessWinners();
StopAllSpectating();
eventPlayers.ForEach((BaseEventPlayer eventPlayer) =>
{
if (!eventPlayer || !eventPlayer.Player)
return;
eventPlayer.ResetStatistics();
if (eventPlayer is NPCEventPlayer)
{
eventPlayer.Player.Kill(BaseNetworkable.DestroyMode.None);
return;
}
if (eventPlayer.IsDead)
RespawnPlayer(eventPlayer);
if (!IsUnloading)
ArenaStatistics.Data.OnGamePlayed(eventPlayer.Player, Config.EventType);
});
if (!IsUnloading)
{
ArenaStatistics.Data.OnGamePlayed(Config.EventType);
if (Configuration.Event.StartOnFinish)
{
BroadcastToPlayers("Notification.NextEventStartsIn", Configuration.Timer.RoundInterval);
Timer.StartTimer(Configuration.Timer.RoundInterval, Message("UI.NextGameStartsIn"), StartEvent);
}
else
{
EjectAllPlayers();
if (joiningSpectators.Count > 0)
InsertJoiningSpectators();
}
RebuildSpectateTargets();
}
}
#endregion
#region Player Management
internal bool CanJoinEvent(BasePlayer player)
{
if ((GetActualPlayerCount() + joiningSpectators.Count) >= Config.MaximumPlayers)
{
player.ChatMessage(Message("Notification.MaximumPlayers", player.userID));
return false;
}
if (!string.IsNullOrEmpty(Config.Permission) && !Instance.permission.UserHasPermission(player.UserIDString, Config.Permission))
{
player.ChatMessage(Message("Error.NoPermission", player.userID));
return false;
}
string str = CanJoinEvent();
if (!string.IsNullOrEmpty(str))
{
player.ChatMessage(str);
return false;
}
return true;
}
protected virtual string CanJoinEvent()
{
return string.Empty;
}
protected virtual bool CanEnterBetweenRounds() => true;
protected virtual bool CanEnterDuringRound() => !_isClosed;
internal virtual void JoinEvent(BasePlayer player, Team team = Team.None)
{
if (Status == Arena.EventStatus.Started && !CanEnterDuringRound())
CreateSpectatorPlayer(player, team);
else CreateEventPlayer(player, team);
if (Configuration.Message.BroadcastJoinersGlobal)
BroadcastToServer("Notification.PlayerJoined", player.displayName, Config.EventName);
if (Configuration.Message.BroadcastJoiners)
BroadcastToPlayers("Notification.PlayerJoined", player.displayName, Config.EventName);
if ((Status == Arena.EventStatus.Open || Status == Arena.EventStatus.Finished))
{
if (HasMinimumRequiredPlayers())
{
Status = Arena.EventStatus.Prestarting;
Timer.StartTimer(Configuration.Timer.Prestart, Message("Notification.RoundStartsIn"), StartEvent);
}
else BroadcastToPlayers("Notification.WaitingForPlayers", Config.MinimumPlayers - eventPlayers.Count);
}
}
internal virtual void LeaveEvent(BasePlayer player)
{
BaseEventPlayer eventPlayer = GetUser(player);
if (!eventPlayer)
return;
if (eventPlayer is NPCEventPlayer)
{
LeaveEvent(eventPlayer as NPCEventPlayer);
}
else
{
LeaveEvent(eventPlayer);
if (Configuration.Message.BroadcastLeaversGlobal)
BroadcastToServer("Notification.PlayerLeft", player.displayName, Config.EventName);
if (Configuration.Message.BroadcastLeavers)
BroadcastToPlayers("Notification.PlayerLeft", player.displayName, Config.EventName);
}
}
internal void LeaveEvent(NPCEventPlayer eventPlayer)
{
eventPlayers.Remove(eventPlayer);
StripInventory(eventPlayer.Player);
DestroyImmediate(eventPlayer);
}
internal virtual void LeaveEvent(BaseEventPlayer eventPlayer)
{
BasePlayer player = eventPlayer.Player;
if (eventPlayer.IsDead || player.IsSpectating())
{
ResetPlayer(eventPlayer.Player);
TeleportPlayer(player, eventPlayer.Team == Team.B ? TeamB.Spawns.GetSpawnPoint() : TeamA.Spawns.GetSpawnPoint(), false);
}
StripInventory(player);
ResetMetabolism(player);
if (!string.IsNullOrEmpty(Config.ZoneID))
Instance?.ZoneManager?.Call("RemovePlayerFromZoneWhitelist", Config.ZoneID, player);
if (Plugin.IsTeamEvent && Plugin.CanUseRustTeams && Configuration.Event.AddToTeams)
{
EventTeam eventTeam = eventPlayer.Team == Team.A ? TeamA : TeamB;
eventTeam.RemoveFromTeam(player);
}
eventPlayers.Remove(eventPlayer);
joiningSpectators.Remove(eventPlayer);
RebuildSpectateTargets();
UpdateSpectatorTargets(eventPlayer);
DestroyImmediate(eventPlayer);
if (!player.IsConnected || player.IsSleeping() || IsUnloading)
player.Die();
else
{
if (Configuration.Server.RestorePlayers)
Instance?.Restore.RestorePlayer(player);
}
if (Status != Arena.EventStatus.Finished && (!HasMinimumRequiredPlayers() || GetActualPlayerCount() == 0))
{
BroadcastToPlayers("Notification.NotEnoughToContinue");
EndEvent();
}
}
internal void InsertJoiningSpectators()
{
joiningSpectators.ForEach((BaseEventPlayer eventPlayer) =>
{
eventPlayers.Add(eventPlayer);
if (Configuration.Message.BroadcastJoinersGlobal)
BroadcastToServer("Notification.PlayerJoined", eventPlayer.Player.displayName, Config.EventName);
if (Configuration.Message.BroadcastJoiners)
BroadcastToPlayers("Notification.PlayerJoined", eventPlayer.Player.displayName, Config.EventName);
if (eventPlayer.Player.IsSpectating())
{
ResetPlayer(eventPlayer.Player);
OnPlayerRespawn(eventPlayer);
}
});
joiningSpectators.Clear();
if (HasMinimumRequiredPlayers())
{
Status = Arena.EventStatus.Prestarting;
Timer.StartTimer(Configuration.Timer.Prestart, Message("Notification.RoundStartsIn"), StartEvent);
}
}
protected virtual void CreateEventPlayer(BasePlayer player, Team team = Team.None)
{
if (!player)
return;
BaseEventPlayer eventPlayer = AddPlayerComponent(player);
eventPlayer.ResetPlayer();
eventPlayer.Event = this;
eventPlayer.Team = team;
if (Plugin.IsTeamEvent && Plugin.CanUseRustTeams && Configuration.Event.AddToTeams)
{
EventTeam eventTeam = team == Team.A ? TeamA : TeamB;
eventTeam.AddToTeam(player);
}
eventPlayers.Add(eventPlayer);
if (!Config.AllowClassSelection || GetAvailableKits(eventPlayer.Team).Count == 1)
eventPlayer.Kit = GetAvailableKits(eventPlayer.Team).First();
SpawnPlayer(eventPlayer, Configuration.Event.GiveKitsWhileWaiting || Status == Arena.EventStatus.Started, true);
if (!string.IsNullOrEmpty(Config.ZoneID))
Instance.ZoneManager?.Call("AddPlayerToZoneWhitelist", Config.ZoneID, player);
}
protected virtual Team GetSpectatingTeam(Team currentTeam) => currentTeam == Team.A ? Team.A : Team.B;
protected virtual void CreateSpectatorPlayer(BasePlayer player, Team team = Team.None)
{
if (!player)
return;
BaseEventPlayer eventPlayer = AddPlayerComponent(player);
eventPlayer.ResetPlayer();
eventPlayer.Event = this;
eventPlayer.Team = team;
if (Plugin.IsTeamEvent && Plugin.CanUseRustTeams && Configuration.Event.AddToTeams)
{
EventTeam eventTeam = GetSpectatingTeam(team) == Team.A ? TeamA : TeamB;
eventTeam.AddToTeam(player);
}
joiningSpectators.Add(eventPlayer);
if (!Config.AllowClassSelection || GetAvailableKits(eventPlayer.Team).Count == 1)
eventPlayer.Kit = GetAvailableKits(team).First();
eventPlayer.Player.GetMounted()?.AttemptDismount(eventPlayer.Player);
if (eventPlayer.Player.HasParent())
eventPlayer.Player.SetParent(null, true, true);
StripInventory(player);
ResetMetabolism(player);
TeleportPlayer(player, eventPlayer.Team == Team.B ? TeamB.Spawns.GetSpawnPoint() : TeamA.Spawns.GetSpawnPoint(), false);
if (!string.IsNullOrEmpty(Config.ZoneID))
Instance.ZoneManager?.Call("AddPlayerToZoneWhitelist", Config.ZoneID, player);
eventPlayer.BeginSpectating();
UpdateScoreboard(eventPlayer);
BroadcastToPlayer(eventPlayer, Message("Notification.JoinerSpectate", player.userID));
ArenaUI.ShowHelpText(eventPlayer);
}
protected virtual Team GetPlayerTeam() => Team.None;
protected virtual BaseEventPlayer AddPlayerComponent(BasePlayer player) => player.gameObject.GetComponent<BaseEventPlayer>() ?? player.gameObject.AddComponent<BaseEventPlayer>();
internal virtual void OnPlayerRespawn(BaseEventPlayer baseEventPlayer)
{
SpawnPlayer(baseEventPlayer, Configuration.Event.GiveKitsWhileWaiting || Status == Arena.EventStatus.Started);
}
internal void SpawnPlayer(BaseEventPlayer eventPlayer, bool giveKit = true, bool sleep = false)
{
if (!eventPlayer|| !eventPlayer.Player)
return;
if (eventPlayer.Player.IsSpectating())
eventPlayer.FinishSpectating();
eventPlayer.Player.GetMounted()?.AttemptDismount(eventPlayer.Player);
if (eventPlayer.Player.HasParent())
eventPlayer.Player.SetParent(null, true);
StripInventory(eventPlayer.Player);
ResetMetabolism(eventPlayer.Player);
TeleportPlayer(eventPlayer.Player, eventPlayer.Team == Team.B ? TeamB.Spawns.GetSpawnPoint() : TeamA.Spawns.GetSpawnPoint(), sleep);
if (string.IsNullOrEmpty(eventPlayer.Kit) && !(eventPlayer is NPCEventPlayer))
{
eventPlayer.ForceSelectClass();
ArenaUI.DisplayDeathScreen(eventPlayer, Message("UI.SelectClass", eventPlayer.Player.userID), true);
return;
}
UpdateScoreboard(eventPlayer);
if (giveKit)
{
Instance.NextTick(() =>
{
if (eventPlayer && CanGiveKit(eventPlayer))
{
GiveKit(eventPlayer.Player, eventPlayer.Kit);
OnKitGiven(eventPlayer);
}
});
}
eventPlayer.ApplyInvincibility();
OnPlayerSpawned(eventPlayer);
RebuildSpectateTargets();
UpdateSpectatorTargets();
ArenaUI.ShowHelpText(eventPla
// ... [Code preview truncated due to length. Full source in attached file] ...