C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
/*
* <----- End-User License Agreement ----->
* Copyright © 2024 Iftebinjan
* Devoloper: Iftebinjan (Contact: https://discord.gg/HFaGs8YwsH)
*
* You may not copy, modify, merge, publish, distribute, sublicense, or sell copies of This Software without the Developer’s consent
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.*
*/
using System;
using System.Linq;
using System.Collections.Generic;
using Oxide.Core;
using UnityEngine;
using VLB;
using System.Collections;
using Newtonsoft.Json;
using Oxide.Game.Rust.Cui;
using Oxide.Core.Plugins;
using Oxide.Core.Libraries.Covalence;
using UnityEngine.UI;
using Network;
using System.Text.RegularExpressions;
namespace Oxide.Plugins {
[Info("Glass Bridge", "https://discord.gg/TrJ7jnS233", "1.7.1")]
[Description("The Glass Bridge game")]
class GlassBridge : RustPlugin {
#region Variables
[PluginReference]
Plugin ImageLibrary;
static GlassBridge plugin;
private const string glassPrefab = "assets/prefabs/building/wall.window.reinforcedglass/wall.window.glass.reinforced.prefab";
private const string foundationPrefab = "assets/prefabs/building core/foundation/foundation.prefab";
private const string entitiesName = "[GlassBridge] Entity";
private GameObject currentEvent = null;
private enum EventStatus {
Spawning, Waiting, Started, Finishing,
}
;
#endregion Variables
#region Hooks
private void Init() {
plugin = this;
permission.RegisterPermission(config.permissionName, this);
foreach (var command in config.commands) {
cmd.AddChatCommand(command, this, nameof(GlassBridgeCommand));
cmd.AddConsoleCommand(command, this, nameof(GlassBridgeConsoleCommand));
}
}
private void Unload() {
if (currentEvent != null) {
UnityEngine.Object.Destroy(currentEvent);
}
}
private void OnServerInitialized() {
if (config.eventSettings.autoStartCooldown > 0) {
timer.Every(config.eventSettings.autoStartCooldown, () => {
if (GetCurrentEvent() != null) {
var timespan = TimeSpan.FromSeconds(config.eventSettings.autoStartCooldown);
Interface.Oxide.LogDebug($"Unable to start an event automatically because there is already an event currently active.Trying again in {(int)timespan.TotalMinutes}:{timespan.Seconds:00}");
return;
}
StartGlassBridgeEvent();
}
);
}
}
private void OnPlayerDisconnected(BasePlayer player, string reason) {
var @event = GetCurrentEvent();
if (@event != null && @event.HasPlayer(player)) {
@event.RemovePlayer(player);
}
}
private object OnEntityMarkHostile(BaseCombatEntity entity, float duration) {
if (!(entity is BasePlayer)) return null;
if (IsPlaying((entity as BasePlayer).userID)) return false;
return null;
}
/* TruePVE hook */
private object CanEntityTakeDamage(BasePlayer victim, HitInfo info) {
if (victim != null && victim.userID.IsSteamId() && IsPlaying(victim.userID)) {
return true;
}
return null;
}
private object OnEntityTakeDamage(BaseEntity entity, HitInfo info) {
var @event = GetCurrentEvent();
if (@event != null) {
if (entity is BasePlayer) {
var player = entity as BasePlayer;
if (!@event.HasPlayer(player)) {
return null;
}
if (!config.eventSettings.pvpEnabled) {
var initiator = info.InitiatorPlayer;
if (initiator != null && initiator.userID.IsSteamId()) {
info.damageTypes.ScaleAll(0f);
return true;
}
}
var damageType = info.damageTypes.GetMajorityDamageType();
if (damageType == Rust.DamageType.Fall) {
info.damageTypes.ScaleAll(0f);
return false;
}
if (@event.Status() != EventStatus.Started) {
info.damageTypes.ScaleAll(0f);
return false;
}
}
if (@event.HasGlass(entity)) {
info.damageTypes.ScaleAll(0f);
return true;
}
}
return null;
}
private void OnRunPlayerMetabolism(PlayerMetabolism metabolism, BasePlayer player) {
GlassBridgeEvent @event = GetCurrentEvent();
if (@event == null || !@event.HasPlayer(player)) return;
if (metabolism.bleeding.value < 1) return;
metabolism.bleeding.value = 0;
}
private object OnPlayerDeath(BasePlayer player, HitInfo info) {
var @event = GetCurrentEvent();
if (@event == null || !@event.HasPlayer(player)) {
return null;
}
if (config.eventSettings.rollbackWhenDie) {
@event.RollbackPlayer(player);
}
else {
info.damageTypes.ScaleAll(0f);
info.DidHit = false;
info.PointStart = Vector3.zero;
@event.RemovePlayer(player);
}
return true;
}
private object OnPlayerWound(BasePlayer player, HitInfo info) => OnPlayerDeath(player, info);
private object OnUserCommand(IPlayer _player, string command, string[] args) {
if (config.commands.Contains(command)) {
return null;
}
var player = BasePlayer.Find(_player.Id);
if (player == null || !IsPlaying(player.userID)) {
return null;
}
if (config.blockedChatCommands.Contains("*") || config.blockedChatCommands.Contains(command)) {
SendMessage(player, "CommandBlocked");
return true;
}
return null;
}
private object OnServerCommand(ConsoleSystem.Arg arg) {
var player = arg?.Player();
if (player == null || !IsPlaying(player.userID)) {
return null;
}
if (config.allowedConsoleCommands.Contains("*")) {
return null;
}
var command = arg.cmd.Name;
var allowedCommands = config.allowedConsoleCommands.Append("glassbridge_ui");
if (!allowedCommands.Contains(command)) {
arg.ReplyWith(Lang("CommandBlocked", player.UserIDString));
return true;
}
return null;
}
#endregion Hooks
#region Commands
private void GlassBridgeCommand(BasePlayer player, string command, string[] args) {
if (args.Length < 1) {
SendMessage(player, "SyntaxError", command);
return;
}
switch (args[0]) {
case "start" : {
if (!HasPermission(player)) {
SendMessage(player, "NotAllowed");
return;
}
if (currentEvent != null) {
SendMessage(player, "AlreadyActive");
return;
}
StartGlassBridgeEvent();
SendMessage(player, "YouStartedAnEvent");
return;
}
case "stop" : {
if (!HasPermission(player)) {
SendMessage(player, "NotAllowed");
return;
}
var @event = GetCurrentEvent();
if (@event == null) {
SendMessage(player, "NoActiveEvent");
return;
}
if (@event.Status() == GlassBridge.EventStatus.Finishing) {
SendMessage(player, "AlreadyBeingFinalized");
return;
}
@event.Finalize(GlassBridgeEvent.FinalizationType.Stop);
SendMessage(player, "YouStoppedTheEvent");
return;
}
case "join" : {
var @event = GetCurrentEvent();
if (@event == null) {
SendMessage(player, "NoActiveEvent");
return;
}
if (@event.HasPlayer(player)) {
SendMessage(player, "IsAlreadyAtTheEvent");
return;
}
if (@event.Status() == EventStatus.Started) {
SendMessage(player, "AlreadyStarted");
return;
}
if (@event.Status() != EventStatus.Waiting) {
SendMessage(player, "NoActiveEvent");
return;
}
if (player.IsDead() || player.IsWounded()) {
SendMessage(player, "DeadOrWounded");
return;
}
if (!player.IsOnGround()) {
SendMessage(player, "NotOnGround");
return;
}
player.inventory.crafting.CancelAll();
@event.AddPlayer(player);
SendMessage(player, "Joined");
return;
}
case "leave" : {
var @event = GetCurrentEvent();
if (@event == null || (@event.Status() != EventStatus.Started && @event.Status() != EventStatus.Waiting)) {
SendMessage(player, "NoActiveEvent");
return;
}
if (!@event.HasPlayer(player)) {
SendMessage(player, "NotParticipating");
return;
}
@event.RemovePlayer(player);
SendMessage(player, "Leave");
return;
}
default : SendMessage(player, "SyntaxError", command);
break;
}
}
private void GlassBridgeConsoleCommand(ConsoleSystem.Arg arg) {
if (arg == null) return;
BasePlayer player = arg.Player();
if (!arg.HasArgs()) {
arg.ReplyWith(HumanizedLang("ConsoleSyntaxError", player, arg.cmd.Name));
return;
}
switch (arg.Args[0]) {
case "start" : {
if (player != null && !HasPermission(player)) {
arg.ReplyWith(HumanizedLang("NotAllowed", player));
return;
}
if (currentEvent != null) {
arg.ReplyWith(HumanizedLang("AlreadyActive", player));
return;
}
StartGlassBridgeEvent();
arg.ReplyWith(HumanizedLang("YouStartedAnEvent", player));
return;
}
case "stop" : {
if (player != null && !HasPermission(player)) {
arg.ReplyWith(HumanizedLang("NotAllowed", player));
return;
}
var @event = GetCurrentEvent();
if (@event == null) {
arg.ReplyWith(HumanizedLang("NoActiveEvent", player));
return;
}
if (@event.Status() == GlassBridge.EventStatus.Finishing) {
arg.ReplyWith(HumanizedLang("AlreadyBeingFinalized", player));
return;
}
@event.Finalize(GlassBridgeEvent.FinalizationType.Stop);
arg.ReplyWith(HumanizedLang("YouStoppedTheEvent", player));
return;
}
default : arg.ReplyWith(HumanizedLang("ConsoleSyntaxError", player, arg.cmd.Name));
break;
}
}
[ConsoleCommand("glassbridge_ui")]
private void consoleCommandGlassBridgeJoin(ConsoleSystem.Arg arg) {
var player = arg?.Player();
if (player == null || !arg.HasArgs(1)) {
return;
}
var subcommand = arg.Args[0];
player.SendConsoleCommand($"chat.say", $"/{config.commands.FirstOrDefault()} {subcommand}");
}
#endregion Commands
#region Methods
public void StartGlassBridgeEvent() {
if (GetCurrentEvent() != null) {
return;
}
var sphere = GameObject.CreatePrimitive(PrimitiveType.Sphere);
sphere.transform.position = config.eventSettings.position;
var collider = sphere.GetComponent<SphereCollider>();
collider.radius = config.glassesSettings.rows * config.glassesSettings.columns + 50;
var trigger = sphere.GetOrAddComponent<TriggerBase>();
trigger.interestLayers = LayerMask.GetMask("Player (Server)");
trigger.enabled = true;
var @event = sphere.AddComponent<GlassBridgeEvent>();
currentEvent = sphere;
}
private GlassBridgeEvent GetCurrentEvent() {
return currentEvent?.GetComponent<GlassBridgeEvent>();
}
public Item GiveItem(ItemContainer container, string name, int amount, int loadedAmmo = 0, ulong skinId = 0L, string customName = "") {
var item = ItemManager.CreateByName(name, amount, skinId);
if (item != null) {
if (loadedAmmo > 0) {
var projectile = item.GetHeldEntity()?.GetComponent<BaseProjectile>();
if (projectile != null) {
projectile.primaryMagazine.contents = Math.Min((int)loadedAmmo, projectile.primaryMagazine.capacity);
}
}
if (!string.IsNullOrEmpty(customName)) {
item.name = customName;
}
item.MoveToContainer(container, allowStack : false, ignoreStackLimit : true);
}
return item;
}
private void BroadcastMessage(string message, params object[] args) {
foreach (var player in BasePlayer.activePlayerList) {
SendMessage(player, message, args);
}
}
private void SendMessage(BasePlayer player, string message, params object[] args) => rust.SendChatMessage(player, Lang("ChatName", player.UserIDString), string.Format(Lang(message, player.UserIDString), args) );
#endregion Methods
#region API
private bool IsActive() => GetCurrentEvent() != null;
private bool IsPlaying(string playerId) {
var @event = GetCurrentEvent();
if (@event != null) {
return @event.HasPlayer(playerId);
}
return false;
}
private bool IsPlaying(ulong playerId) => IsPlaying(playerId.ToString());
private void RemovePlayer(string playerId) {
var @event = GetCurrentEvent();
if (@event != null) {
@event.RemovePlayer(playerId);
}
}
private void RemovePlayer(ulong playerId) => RemovePlayer(playerId.ToString());
private List<BasePlayer> PlayingList() {
var playing = new List<BasePlayer>();
foreach (var player in BasePlayer.activePlayerList) {
if (IsPlaying(player.userID)) {
playing.Add(player);
}
}
return playing;
}
#endregion API
#region ImageLibrary
private bool AddImage(string url, string name) => (bool)ImageLibrary?.Call("AddImage", url, name);
private string GetImage(string name) => ImageLibrary?.Call<string>("GetImage", name);
private bool HasImage(string name) => (bool)ImageLibrary?.Call("HasImage", name);
#endregion ImageLibrary
#region Helpers
private bool HasPermission(BasePlayer player) => player.IsAdmin || permission.UserHasPermission(player.UserIDString, config.permissionName);
private int[] GetRandomNumbersBetweenRange(int start, int end, int amount) {
if (end - start < amount) {
return new int[] {
}
;
}
var result = new int[amount];
for (int i = 0; i < amount; i++) {
int num = UnityEngine.Random.Range(start, end + 1);
if (!result.Contains(num)) {
result[i] = num;
continue;
}
i--;
}
return result;
}
private long DateNow() {
return (long)(DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1)).TotalSeconds;
}
#endregion Helpers
#region UI
private void CreateJoinLeaveUI(BasePlayer player) {
var container = new CuiElementContainer();
var @event = GetCurrentEvent();
if (@event == null || @event.Status() != EventStatus.Waiting) {
CuiHelper.DestroyUi(player, "JoinLeavePanel");
return;
}
var settings = config.UI.joinLeave;
var isPlaying = IsPlaying(player.UserIDString);
UIBuilder.CreatePanel(ref container, "Overlay", settings.color, settings.anchor, settings.offset, name : "JoinLeavePanel", destroyUi : "JoinLeavePanel");
UIBuilder.CreatePanel(ref container, "JoinLeavePanel", "0 1 1 1", "0 1 1 1", "0 -2 0 0");
// Title
UIBuilder.CreateLabel(ref container, "JoinLeavePanel", Lang("GlassBridgeTitle", player.UserIDString), "0 1 1 1", "0 -56 0 0", align : TextAnchor.MiddleCenter);
// Button
UIBuilder.CreatePanel(ref container, "JoinLeavePanel", isPlaying ? settings.button.leaveColor : settings.button.joinColor, "0 0 1 0", "4 4 -4 36", name : "JoinLeaveButton");
UIBuilder.CreateLabel(ref container, "JoinLeaveButton", Lang(isPlaying ? "LeaveButton" : "JoinButton", player.UserIDString), "0 0 1 1", "", align : TextAnchor.MiddleCenter);
container.Add(new CuiButton {
RectTransform = {
AnchorMin = "0 0", AnchorMax = "1 1"
}
, Button = {
Color = "0 0 0 0", Command = $"glassbridge_ui {(isPlaying ? "leave" : "join")}"
}
}
, "JoinLeaveButton" );
UIBuilder.CreatePanel(ref container, "JoinLeavePanel", "1 1 1.1", "0 0 1 0", "4 68 -4 92", name : "JoinLeaveInfoPlayers");
UIBuilder.CreatePanel(ref container, "JoinLeaveInfoPlayers", null, "0.5 0.5", "4 -7 18 7", image : "https://i.ibb.co/0msdX54/image.png");
UIBuilder.CreateLabel(ref container, "JoinLeaveInfoPlayers", $"<size=12><b>{@event?.GetRemainingPlayersAmount() ?? 0}</b></size>", "0 0 1 1", "0 0 0 0", align : TextAnchor.MiddleCenter);
TimeSpan timespan = TimeSpan.FromSeconds(@event.waitStartedAt != null ? Math.Max(config.eventSettings.waitDuration - (DateNow() - (int)@event.waitStartedAt), 0) : 0);
UIBuilder.CreatePanel(ref container, "JoinLeavePanel", "1 1 1.1", "0 0 1 0", "4 40 -4 64", name : "JoinLeaveInfoTime");
UIBuilder.CreatePanel(ref container, "JoinLeaveInfoTime", null, "0.5 0.5", "4 -7 18 7", image : "https://i.ibb.co/Fb5WsqH/image.png");
UIBuilder.CreateLabel(ref container, "JoinLeaveInfoTime", $"<size=12><b>{(int)timespan.TotalMinutes}:{timespan.Seconds:00}</b></size>", "0 0 1 1", "0 0 0 0", align : TextAnchor.MiddleCenter);
CuiHelper.AddUi(player, container);
}
private void UpdateEventStatusUI(BasePlayer player, int remainingPlayers, long remainingTime = 0) {
var container = new CuiElementContainer();
var timespan = TimeSpan.FromSeconds(remainingTime);
var minutes = $"{(config.eventSettings.autoStopAfter > 0 ? ((int)timespan.TotalMinutes).ToString() : "--")}";
var seconds = $"{(config.eventSettings.autoStopAfter > 0 ? timespan.Seconds.ToString() : "--")}";
UIBuilder.CreateLabel(ref container, "EventStatusRemainingPlayersBox", string.Format(Lang("EventStatusRemainingPlayersText", player.UserIDString), remainingPlayers), "0 0 1 1", "4 0 -4 0", align : TextAnchor.MiddleCenter, name : "EventStatusRemainingPlayersText", destroyUi : "EventStatusRemainingPlayersText");
UIBuilder.CreateLabel(ref container, "EventStatusRemainingTimeBox", string.Format(Lang("EventStatusRemainingTimeText", player.UserIDString), minutes, seconds.PadLeft(2, '0')), "0 0 1 1", "4 0 -4 0", align : TextAnchor.MiddleCenter, name : "EventStatusRemainingTimeText", destroyUi : "EventStatusRemainingTimeText");
CuiHelper.AddUi(player, container);
}
private void CreateEventStatusUI(BasePlayer player, int remainingPlayers, long remainingTime = 0) {
var container = new CuiElementContainer();
var UISettings = config.UI.eventStatus;
UIBuilder.CreatePanel(ref container, "Hud", "0 0 0 0", UISettings.anchor, UISettings.offset, name : "EventStatus", destroyUi : "EventStatus");
UIBuilder.CreatePanel(ref container, "EventStatus", UISettings.remainingPlayers.color, UISettings.remainingPlayers.anchor, UISettings.remainingPlayers.offset, name : "EventStatusRemainingPlayersBox");
UIBuilder.CreatePanel(ref container, "EventStatus", UISettings.remainingTime.color, UISettings.remainingTime.anchor, UISettings.remainingTime.offset, name : "EventStatusRemainingTimeBox");
UIBuilder.CreatePanel(ref container, "EventStatusRemainingPlayersBox", "1 1 1 1", UISettings.remainingPlayers.iconAnchor, UISettings.remainingPlayers.iconOffset, image : UISettings.remainingPlayers.iconUrl);
CuiHelper.AddUi(player, container);
UpdateEventStatusUI(player, remainingPlayers, remainingTime);
}
private void CreateStartCountdownUI(BasePlayer player, string text, bool isLast = false) {
var container = new CuiElementContainer();
UIBuilder.CreateLabel(ref container, "Hud", text, "0 0 1 1", "", .1f, .3f, TextAnchor.MiddleCenter, "StartCountdown", "StartCountdown");
Effect.server.Run(isLast ? "assets/prefabs/locks/keypad/effects/lock.code.unlock.prefab" : "assets/prefabs/locks/keypad/effects/lock.code.lock.prefab", player, 0, new Vector3(), player.transform.position, null, false);
CuiHelper.AddUi(player, container);
}
private void CreateGiveTimeWarnUI(BasePlayer player, string text, string color) {
var container = new CuiElementContainer();
UIBuilder.CreatePanel(ref container, "Hud", "0 0 0.65", "0.5 0 0.5 0", "-128 100 128 136", .3f, .3f, name : "GiveTimeWarn", destroyUi : "GiveTimeWarn", material : "assets/content/ui/uibackgroundblur-ingamemenu.mat");
UIBuilder.CreatePanel(ref container, "GiveTimeWarn", color, "0 0 0 1", "0 0 3 0");
UIBuilder.CreatePanel(ref container, "GiveTimeWarn", color, "1 0 1 1", "-3 0 0 0");
UIBuilder.CreateLabel(ref container, "GiveTimeWarn", text, "0 0 1 1", $"12 0 -12 0", align : TextAnchor.MiddleCenter, fontSize : 12);
CuiHelper.AddUi(player, container);
}
private class UIBuilder {
public static void CreatePanel(ref CuiElementContainer container, string parent, string color, string anchor, string offset, float fadeIn = 0f, float fadeOut = 0f, string image = null, int itemId = 0, string name = null, string destroyUi = null, string material = null) {
var _anchor = ParseMinMax(anchor);
var _offset = ParseMinMax(offset);
if (string.IsNullOrEmpty(image)) {
container.Add(new CuiPanel {
FadeOut = fadeOut, RectTransform = {
AnchorMin = _anchor[0], AnchorMax = _anchor[1], OffsetMin = _offset[0], OffsetMax = _offset[1],
}
, Image = {
Color = color, ItemId = itemId, FadeIn = fadeIn, Material = material,
}
}
, parent, name, destroyUi );
}
else {
if (!plugin.HasImage(image)) {
plugin.AddImage(image, image);
}
container.Add(new CuiElement {
Name = name, Parent = parent, DestroyUi = destroyUi, FadeOut = fadeOut, Components = {
new CuiRectTransformComponent {
AnchorMin = _anchor[0], AnchorMax = _anchor[1], OffsetMin = _offset[0], OffsetMax = _offset[1],
}
, new CuiRawImageComponent {
Url = plugin.HasImage(image) ? null : image, Png = plugin.HasImage(image) ? plugin.GetImage(image) : null, FadeIn = fadeIn,
}
}
}
);
}
}
public static void CreateLabel(ref CuiElementContainer container, string parent, string text, string anchor, string offset, float fadeIn = 0f, float fadeOut = 0f, TextAnchor align = TextAnchor.MiddleLeft, string name = null, string destroyUi = null, int fontSize = 14) {
var _anchor = ParseMinMax(anchor);
var _offset = ParseMinMax(offset);
container.Add(new CuiLabel {
FadeOut = fadeOut, RectTransform = {
AnchorMin = _anchor[0], AnchorMax = _anchor[1], OffsetMin = _offset[0], OffsetMax = _offset[1],
}
, Text = {
Color = "1 1 1 1", Text = text, FadeIn = fadeIn, Align = align, FontSize = fontSize, Font = "robotocondensed-regular.ttf"
}
}
, parent, name, destroyUi );
}
private static string[] ParseMinMax(string value) {
var array = value.Split(' ');
return new string[] {
string.Join(" ", array.Take(2)), string.Join(" ", array.Skip(2)),
}
;
}
}
#endregion UI
#region Structures
private class Glass : MonoBehaviour {
public bool isBroken = false;
private BaseEntity entity;
private BoxCollider collider;
private void Awake() {
entity = GetComponent<BaseEntity>();
if (entity == null) {
Destroy(this);
return;
}
entity.name = "[GlassBridge] Glass Entity";
var stability = GetComponent<StabilityEntity>();
stability.grounded = true;
collider = this.GetOrAddComponent<BoxCollider>();
collider.isTrigger = true;
collider.center = entity.bounds.center;
collider.size = entity.bounds.size + new Vector3(3f, 0f, 0f);
gameObject.layer = (int)Rust.Layer.Reserved1;
gameObject.name = "[GlassBridge] Glass";
;
}
private void OnTriggerEnter(Collider col) {
var player = col.GetComponent<BasePlayer>();
if (player == null || !player.userID.IsSteamId()) {
return;
}
if (isBroken) {
var @event = plugin.GetCurrentEvent();
if (!@event) {
Destroy(this);
return;
}
if (@event.Status() == EventStatus.Started && @event.HasPlayer(player)) {
@event.DestroyGlass(this);
}
}
}
private void OnDestroy() {
if (entity != null && !entity.IsDestroyed) {
entity.AdminKill();
}
}
}
private class EventPlayer : MonoBehaviour {
public BasePlayer player {
get;
private set;
}
private PlayerBackup backup;
private int startCountdown = 3;
private bool isFreeze = false;
private Vector3? freezePosition = null;
private bool isWinner = false;
private void Awake() {
player = GetComponent<BasePlayer>();
}
private void Update() {
var @event = plugin.GetCurrentEvent();
if (!@event) {
Destroy(this);
return;
}
if (@event.Status() == EventStatus.Started) {
if (isFreeze && freezePosition != null) {
player.Teleport(freezePosition.Value);
}
if (@event.GetPlayerEventPosition(player) == GlassBridgeEvent.PlayerEventPosition.Arrival) {
@event.Finalize(GlassBridgeEvent.FinalizationType.Winner, player);
return;
}
}
if (transform.position.y < plugin.config.eventSettings.position.y - 20f) {
if (plugin.config.eventSettings.loseWhenFall && @event.Status() == EventStatus.Started && @event.startedAt != null) {
@event.RemovePlayer(player);
return;
}
player.Teleport(@event.GetRandomSpawnPoint());
}
}
private void OnDestroy() {
CancelInvoke(nameof(ShowStartCountdown));
CancelInvoke(nameof(DestroyCountdown));
CancelInvoke(nameof(UpdateEventStatusUI));
DestroyAllUI();
Restore();
}
private void Restore() {
player.metabolism.Reset();
player.SetHealth(backup.metabolism.health);
player.metabolism.bleeding.value = backup.metabolism.bleeding;
player.metabolism.calories.value = backup.metabolism.calories;
player.metabolism.hydration.value = backup.metabolism.hydration;
player.metabolism.oxygen.value = backup.metabolism.oxygen;
player.metabolism.poison.value = backup.metabolism.poison;
player.metabolism.radiation_level.value = backup.metabolism.radiation_level;
player.metabolism.radiation_poison.value = backup.metabolism.radiation_poison;
player.metabolism.wetness.value = backup.metabolism.wetness;
player.metabolism.temperature.value = backup.metabolism.temperature;
player.inventory.Strip();
backup.RestorePlayer();
Teleport(backup.position);
backup = null;
if (isWinner) {
/* Give winner items */
foreach (var item in plugin.config.prizeSettings.items) {
var container = player.inventory.containerMain.itemList.Count() < 24 ? player.inventory.containerMain : player.inventory.containerBelt;
plugin.GiveItem(container, item.shortname, item.amount, 0, item.skinId, item.customName);
}
/* Execute server commnads */
foreach (var command in plugin.config.prizeSettings.commands) {
var args = command.Replace("{winner_id}", player.UserIDString).Replace("{winner_name}", player.displayName).Split(' ');
plugin.Server.Command(args[0], args.Skip(1));
}
}
}
public void SetWinner() {
isWinner = true;
}
public void Teleport(Vector3 position) {
if (!player.IsValid()) return;
try {
player.UpdateActiveItem(new ItemId(0u));
player.EnsureDismounted();
if (player.HasParent()) player.SetParent(null, true, true);
if (player.IsConnected) {
player.EndLooting();
if (!player.IsSleeping()) {
player.SetPlayerFlag(BasePlayer.PlayerFlags.Sleeping, true);
player.sleepStartTime = Time.time;
BasePlayer.sleepingPlayerList.Add(player);
player.CancelInvoke("InventoryUpdate");
player.CancelInvoke("TeamUpdate");
}
}
player.RemoveFromTriggers();
player.Teleport(position);
if (player.IsConnected && !Net.sv.visibility.IsInside(player.net.group, position)) {
player.SetPlayerFlag(BasePlayer.PlayerFlags.ReceivingSnapshot, true);
player.ClientRPCPlayer(null, player, "StartLoading");
player.SendEntityUpdate();
player.UpdateNetworkGroup();
player.SendNetworkUpdateImmediate(false);
}
}
finally {
player.ForceUpdateTriggers();
}
}
public void SetFreeze(bool freeze) {
if (freeze) {
isFreeze = true;
freezePosition = player.transform.position;
}
else {
isFreeze = false;
freezePosition = null;
}
}
public void Heal() {
player.SetHealth(player._maxHealth);
player.metabolism.bleeding.value = 0;
player.metabolism.calories.min = 0;
player.metabolism.calories.value = 500;
player.metabolism.hydration.min = 0;
player.metabolism.hydration.value = 250;
player.metabolism.oxygen.value = 1;
player.metabolism.poison.value = 0;
player.metabolism.radiation_level.value = 0;
player.metabolism.radiation_poison.value = 0;
player.metabolism.wetness.value = 0;
player.metabolism.temperature.min = 32;
player.metabolism.temperature.max = 32;
player.metabolism.temperature.value = 32;
player.metabolism.SendChangesToClient();
}
public void CreateBackup() {
backup = new PlayerBackup(player);
}
public void ShowGiveTimeWarn(string text, string color) {
if (IsInvoking(nameof(DestroyGiveTimeWarn))) {
CancelInvoke(nameof(DestroyGiveTimeWarn));
}
plugin.CreateGiveTimeWarnUI(player, text, color);
Invoke(nameof(DestroyGiveTimeWarn), 6f);
}
public void ShowStartCountdown() {
plugin.CreateStartCountdownUI(player, plugin.Lang($"StartCountdown_{startCountdown}", player.UserIDString), !(startCountdown > 0));
Invoke(nameof(DestroyCountdown), .7f);
if (startCountdown > 0) {
startCountdown--;
Invoke(nameof(ShowStartCountdown), 1f);
}
}
public void ShowEventStatus(int remainingPlayers, long remainingTime = 0) {
plugin.CreateEventStatusUI(player, remainingPlayers, remainingTime);
InvokeRepeating(nameof(UpdateEventStatusUI), 1f, 1f);
}
public void UpdateEventStatusUI() {
var @event = plugin.GetCurrentEvent();
if (!@event) {
Destroy(this);
return;
}
long remainingTime = plugin.config.eventSettings.autoStopAfter;
if (@event.startedAt != null && plugin.config.eventSettings.autoStopAfter > 0) {
var elapsed = plugin.DateNow() - @event.startedAt;
remainingTime = Math.Max(plugin.config.eventSettings.autoStopAfter - (int)elapsed, 0);
}
plugin.UpdateEventStatusUI(player, @event.GetRemainingPlayersAmount(), remainingTime );
}
private void DestroyGiveTimeWarn() {
CuiHelper.DestroyUi(player, "GiveTimeWarn");
}
private void DestroyCountdown() {
CuiHelper.DestroyUi(player, "StartCountdown");
}
private void DestroyEventStatus() {
}
private void DestroyAllUI() {
DestroyGiveTimeWarn();
DestroyCountdown();
CuiHelper.DestroyUi(player, "EventStatus");
}
}
private class GlassBridgeEvent : MonoBehaviour {
private EventStatus status = EventStatus.Spawning;
private List<EventPlayer> players = new List<EventPlayer>();
private List<Glass> glasses = new List<Glass>();
private List<BaseEntity> foundations = new List<BaseEntity>();
private List<BaseEntity> arrivalFoundations = new List<BaseEntity>();
public long? startedAt {
get;
private set;
}
public long? waitStartedAt {
get;
private set;
}
public enum PlayerEventPosition {
Lobby, Bridge, Arrival,
}
;
public enum FinalizationType {
Winner, Stop, AutoStop, NoPlayers, MinPlayers,
}
;
private void Awake() {
gameObject.layer = (int)Rust.Layer.Reserved1;
gameObject.name = "[GlassBridge] Event";
var sphere = GetComponent<SphereCollider>();
sphere.isTrigger = true;
}
private void Start() {
StartCoroutine(CreateLobby());
}
private void OnTriggerEnter(Collider col) {
var player = col?.GetComponent<BasePlayer>();
if (player == null || !player.userID.IsSteamId()) {
return;
}
if (!IsSafePlayer(player)) {
player.Invoke(() => player.Hurt(1000f, Rust.DamageType.Explosion, null, false), 0.25f);
}
}
private void OnTriggerExit(Collider col) {
var player = col?.GetComponent<BasePlayer>();
if (player == null || !HasPlayer(player)) {
return;
}
var eventPlayer = player.GetComponent<EventPlayer>();
players.Remove(eventPlayer);
Destroy(eventPlayer);
plugin.SendMessage(player, "LeftFromEventArea");
if (players.Count < 1 && status == EventStatus.Started) {
Finalize(FinalizationType.NoPlayers);
}
}
private void OnDestroy() {
CancelInvoke(nameof(ShowPlayersJoinLeaveUI));
DestroyPlayersJoinLeaveUI();
foreach (var eventPlayer in players) {
Destroy(eventPlayer);
}
foreach (var glass in glasses) {
Destroy(glass);
}
foreach (var foundation in foundations) {
foundation?.AdminKill();
}
foreach (var foundation in arrivalFoundations) {
foundation?.AdminKill();
}
plugin.currentEvent = null;
}
private IEnumerator StartEvent() {
status = EventStatus.Waiting;
waitStartedAt = plugin.DateNow();
Interface.CallHook("OnGlassBridgeEventStarted");
plugin.BroadcastMessage("EventStarted", plugin.config.commands[0]);
InvokeRepeating(nameof(ShowPlayersJoinLeaveUI), 0, 1f);
yield return new WaitForSeconds(plugin.config.eventSettings.waitDuration);
CancelInvoke(nameof(ShowPlayersJoinLeaveUI));
DestroyPlayersJoinLeaveUI();
status = EventStatus.Started;
waitStartedAt = null;
if (players.Count < Math.Max(plugin.config.eventSettings.minPlayers, 1)) {
Finalize(FinalizationType.MinPlayers);
yield break;
}
foreach (var eventPlayer in players) {
var player = eventPlayer.player;
player.Teleport(GetRandomSpawnPoint());
eventPlayer.SetFreeze(true);
eventPlayer.ShowStartCountdown();
eventPlayer.ShowEventStatus(players.Count, plugin.config.eventSettings.autoStopAfter);
}
yield return new WaitForSeconds(4f);
startedAt = plugin.DateNow();
foreach (var eventPlayer in players) {
eventPlayer.SetFreeze(false);
}
if (plugin.config.eventSettings.autoStopAfter > 0) {
Invoke(nameof(AutoStop), plugin.config.eventSettings.autoStopAfter);
}
InvokeRepeating(nameof(TryGiveTime), 0f, 1f);
}
public void Finalize(FinalizationType type, BasePlayer winner = null) {
status = EventStatus.Finishing;
CancelInvoke(nameof(AutoStop));
CancelInvoke(nameof(TryGiveTime));
Interface.CallHook("OnGlassBridgeEventEnded", winner);
switch (type) {
case FinalizationType.Winner : {
Destroy(this, 5f);
if (winner != null && HasPlayer(winner)) {
winner.GetComponent<EventPlayer>().SetWinner();
plugin.BroadcastMessage("WinnerBroadcast", winner.displayName);
foreach (var eventPlayer in players) {
var player = eventPlayer.player;
plugin.SendMessage(player, "WaitForTeleport");
}
}
break;
}
case FinalizationType.Stop : {
Destroy(this);
plugin.BroadcastMessage("Stopped");
break;
}
case FinalizationType.AutoStop : {
Destroy(this);
plugin.BroadcastMessage("AutoStopped");
break;
}
case FinalizationType.NoPlayers : {
Destroy(this);
plugin.BroadcastMessage("NoPlayers");
break;
}
case FinalizationType.MinPlayers : {
Destroy(this);
plugin.BroadcastMessage("MinPlayers", Math.Max(plugin.config.eventSettings.minPlayers, 1));
break;
}
}
}
public void AutoStop() => Finalize(FinalizationType.AutoStop);
private void TryGiveTime() {
var elapsed = plugin.DateNow() - startedAt;
if (elapsed == null) {
return;
}
var gives = plugin.config.eventSettings.giveTimes.Where((x) => x.time == elapsed);
foreach (var give in gives) {
foreach (var eventPlayer in players) {
var player = eventPlayer.player;
var container = give.container == "belt" ? player.inventory.containerBelt : give.container == "wear" ? player.inventory.containerWear : player.inventory.containerMain;
Item item = plugin.GiveItem(container, give.shortname, give.amount, give.loadedAmmo, give.skinId);
if (give.showWarn && item != null) {
eventPlayer.ShowGiveTimeWarn(string.Format(plugin.Lang(give.langKey, player.UserIDString), give.amount, item.info.displayName.english), give.warnBgColor);
}
}
}
}
public EventStatus Status() => status;
private IEnumerator CreateLobby() {
var columns = plugin.config.glassesSettings.columns;
for (int i = 0; i < (3.5 * columns / 3);
i++) {
for (int j = 0; j < 4; j++) {
var entity = GameManager.server.CreateEntity(foundationPrefab, plugin.config.eventSettings.position + new Vector3(i * 3, 0, j * 3));
entity.name = entitiesName;
entity.Spawn();
var build = entity.GetComponent<BuildingBlock>();
// ... [Code preview truncated due to length. Full source in attached file] ...