C#:
using System;
using System.Collections.Generic;
using System.Linq;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Libraries;
using Oxide.Core.Libraries.Covalence;
using Oxide.Game.Rust.Cui;
using UnityEngine;
namespace Oxide.Plugins
{
// Creation date: 18-04-2023
// Last update date: 18-04-2020
[Info("Phases", "Orange", "1.0.1")]
[Description("https://rustworkshop.space/resources/phases.223/")]
public class Phases : RustPlugin
{
#region Vars
private PeriodEntry currentPeriod;
private int secondsLeft;
private string[] commands =
{
"period",
"periods",
"phase",
"phases"
};
private List<ulong> hiddenUI = new List<ulong>();
#endregion
#region Oxide Hooks
private void Init()
{
BuildUI();
cmd.AddChatCommand("periodUi", this, nameof(cmdControlChat));
foreach (var command in commands)
{
cmd.AddConsoleCommand(command, this, nameof(cmdControlConsole));
}
}
private void OnServerInitialized()
{
timer.Every(1f, () => CheckPeriod());
}
private void Unload()
{
foreach (var player in BasePlayer.activePlayerList)
{
CuiHelper.DestroyUi(player, elemMain);
}
}
private void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info)
{
if (info == null || currentPeriod == null)
{
return;
}
var block = false;
var attackerPlayer = info.InitiatorPlayer;
var victimPlayer = entity as BasePlayer;
var teamAttacker = attackerPlayer?.Team;
if (victimPlayer != null)
{
if (attackerPlayer == victimPlayer)
{
return;
}
if (teamAttacker != null && teamAttacker.members.Contains(victimPlayer.userID))
{
return;
}
if (currentPeriod.canPVP == true)
{
return;
}
block = true;
}
if (entity.OwnerID > 0)
{
if (attackerPlayer != null && attackerPlayer.userID == entity.OwnerID)
{
return;
}
if (teamAttacker != null && teamAttacker.members.Contains(entity.OwnerID))
{
return;
}
if (currentPeriod.canRaid == true)
{
return;
}
block = true;
}
if (block == true)
{
info.damageTypes.Clear();
Message.Send(attackerPlayer, MessageKey.ActionBlocked);
}
}
private object OnDispenserGather(ResourceDispenser dispenser, BasePlayer player, Item item)
{
if (currentPeriod == null)
{
return null;
}
if (currentPeriod.canFarm == false)
{
Message.Send(player, MessageKey.ActionBlocked);
return true;
}
return null;
}
private object CanBuild(Planner planner, Construction prefab, Construction.Target target)
{
if (currentPeriod == null)
{
return null;
}
var player = planner.GetOwnerPlayer();
var deployable = planner.GetDeployable();
var flag = deployable == null ? currentPeriod.canBuild : currentPeriod.canDeploy;
if (flag == false)
{
Message.Send(player, MessageKey.ActionBlocked);
return true;
}
return null;
}
private void OnPlayerRespawned(BasePlayer player)
{
if (currentPeriod == null || currentPeriod.defaultKit == null)
{
return;
}
Interface.CallHook("GiveKit", player, currentPeriod.defaultKit);
}
#endregion
#region Commands
private void cmdControlChat(BasePlayer player, string command, string[] args)
{
if (command == "periodUi")
{
ToggleUI(player);
}
}
private void cmdControlConsole(ConsoleSystem.Arg arg)
{
var args = arg.Args;
if (args == null || args.Length < 1)
{
SendReply(arg, "Usage: periods <start/stop>");
return;
}
var action = args[0].ToLower();
switch (action)
{
case "begin":
case "start":
if (arg.IsAdmin == true)
{
if (currentPeriod == config.warmUpPeriod)
{
var next = config.periods.FirstOrDefault();
ChangePeriod(next);
}
}
break;
case "stop":
if (arg.IsAdmin == true)
{
if (currentPeriod != config.warmUpPeriod)
{
ChangePeriod(config.warmUpPeriod);
}
}
break;
}
SendReply(arg, $"Current period is '{currentPeriod?.name}'");
}
#endregion
#region Core
private void CheckPeriod()
{
if (currentPeriod == null)
{
ChangePeriod(config.warmUpPeriod);
}
if (currentPeriod.duration == 0)
{
secondsLeft++;
RefreshUI();
return;
}
secondsLeft--;
if (secondsLeft < 0)
{
var next = config.periods.FirstOrDefault(x => x.order > currentPeriod.order);
ChangePeriod(next);
}
else
{
RefreshUI();
}
}
private void ChangePeriod(PeriodEntry entry)
{
if (entry == null)
{
Debug.LogWarning("Can't change period because entry is null!");
return;
}
if (Interface.CallHook(nameof(OnPeriodChanged), entry.name) != null)
{
return;
}
Debug.Log($"Current period was set to {entry.name}");
currentPeriod = entry;
secondsLeft = currentPeriod.duration;
RefreshUI();
Message.Broadcast(MessageKey.PeriodChanged, "{name}", currentPeriod.name);
if (currentPeriod == config.periods.FirstOrDefault())
{
TeleportPlayers();
}
foreach (var command in currentPeriod.commands)
{
Server.Command(command);
}
}
private void TeleportPlayers()
{
foreach (var player in BasePlayer.activePlayerList)
{
if (player.IsAdmin == true)
{
player.ChatMessage("Ignoring force respawn because you are an admin...");
continue;
}
var position = SpawnHandler.GetSpawnPoint().pos;
Interface.CallHook("Teleport", player, position);
if (player.IsSleeping() == false)
{
player.StartSleeping();
player.Teleport(position);
player.SendNetworkUpdateImmediate();
}
}
}
private void ToggleUI(BasePlayer player)
{
if (hiddenUI.Contains(player.userID))
{
hiddenUI.Remove(player.userID);
}
else
{
hiddenUI.Add(player.userID);
}
}
#endregion
#region Interface
private const string elemMain = "phases.main";
private const string elemTime = "phases.time";
private string uiJson;
private void BuildUI()
{
var container = new CuiElementContainer();
container.Add(new CuiElement
{
Name = elemMain,
Parent = "Under",
Components =
{
new CuiImageComponent
{
Color = "1 0 0 0.7",
},
new CuiRectTransformComponent
{
AnchorMin = "0 1",
AnchorMax = "0 1",
OffsetMin = "25 0",
OffsetMax = "25 0"
}
}
});
container.Add(new CuiButton
{
Text =
{
Text = "%TIME%",
Align = TextAnchor.MiddleCenter,
FontSize = 22
},
Button =
{
Color = "0.3 0.3 0.3 0.5",
Material = "assets/content/ui/uibackgroundblur-ingamemenu.mat"
},
RectTransform =
{
OffsetMin = "5 -46",
OffsetMax = "125 -5"
}
}, elemMain, elemTime);
container.Add(new CuiButton
{
Text =
{
Text = "%PERIOD%",
Align = TextAnchor.MiddleCenter,
FontSize = 22,
},
Button =
{
Color = "0.3 0.3 0.3 0.5",
Material = "assets/content/ui/uibackgroundblur-ingamemenu.mat"
},
RectTransform =
{
OffsetMin = "129 -46",
OffsetMax = "254 -5"
}
}, elemMain, "aezakmi");
container.Add(new CuiElement
{
Parent = elemTime,
Components =
{
new CuiImageComponent
{
Color = "1 1 1 1"
},
new CuiRectTransformComponent
{
AnchorMin = "0 0",
AnchorMax = "1 0.05",
}
}
});
container.Add(new CuiElement
{
Parent = "aezakmi",
Components =
{
new CuiImageComponent
{
Color = "1 1 1 1"
},
new CuiRectTransformComponent
{
AnchorMin = "0 0",
AnchorMax = "1 0.05",
}
}
});
container.Add(new CuiElement
{
Parent = elemTime,
Components =
{
new CuiTextComponent
{
Text = "%TEXT%",
Align = TextAnchor.UpperLeft,
FontSize = 15,
},
new CuiOutlineComponent
{
Color = "0 0 0 1",
Distance = "-1 0.1 -1 0.1"
},
new CuiRectTransformComponent
{
AnchorMin = "0 0",
AnchorMax = "0 0",
OffsetMin = "0 -150",
OffsetMax = "254 -5"
}
}
});
uiJson = container.ToString();
}
private void RefreshUI()
{
var time = $"{secondsLeft / 60}M {secondsLeft % 60}S";
var ui = uiJson.Replace("%TIME%",time).Replace("%PERIOD%", currentPeriod.name).Replace("%TEXT%", currentPeriod.description);
foreach (var player in BasePlayer.activePlayerList)
{
CuiHelper.DestroyUi(player, elemMain);
if (hiddenUI.Contains(player.userID))
{
continue;
}
CuiHelper.AddUi(player, ui);
}
}
#endregion
#region Configuration | 09.2020
private static ConfigData config = new ConfigData();
private class ConfigData
{
[JsonProperty(PropertyName = "Warmup period")]
public PeriodEntry warmUpPeriod = new PeriodEntry
{
name = "<color=#EC3B86>WARMUP</color>",
description = "Preparing to match... Inspect map and select build location!",
canBuild = false,
canDeploy = false,
canFarm = false,
canRaid = false,
canPVP = false,
defaultKit = "warmup",
};
[JsonProperty(PropertyName = "Periods")]
public PeriodEntry[] periods =
{
new PeriodEntry
{
name = "<color=#8CC83F>GRACE</color>",
order = 1,
description = "Farm & build up your base. You cannot be attacked or raided",
duration = 30,
defaultKit = "grace",
},
new PeriodEntry
{
name = "<color=#ffff00>ATTACK</color>",
order = 2,
description = "Attack and kill your enemies! You cannot be raided yet",
canPVP = true,
canFarm = false,
duration = 30,
defaultKit = "attack"
},
new PeriodEntry
{
name = "<color=#ff0000>RAID</color>",
order = 3,
description = "Are you an offender or a defender? Raid your enemies and protect your base!",
canPVP = true,
canRaid = true,
defaultKit = "attack"
},
};
}
private class PeriodEntry
{
[JsonProperty(PropertyName = "Name")]
public string name = "Period";
[JsonProperty(PropertyName = "Order")]
public int order = 0;
[JsonProperty(PropertyName = "Duration (seconds)")]
public int duration = 0;
[JsonProperty(PropertyName = "Description")]
public string description = "That is test period, you can add any message here";
[JsonProperty(PropertyName = "Default kit")]
public string defaultKit = string.Empty;
[JsonProperty(PropertyName = "Can build buildings")]
public bool canBuild = true;
[JsonProperty(PropertyName = "Can place deploy-ables")]
public bool canDeploy = true;
[JsonProperty(PropertyName = "Can gather resources")]
public bool canFarm = true;
[JsonProperty(PropertyName = "Can deal damage to players")]
public bool canPVP = false;
[JsonProperty(PropertyName = "Can deal damage to buildings")]
public bool canRaid = false;
[JsonProperty(PropertyName = "Commands that will be executed when period starts")]
public string[] commands =
{
"test1",
"test2",
"test3"
};
}
protected override void LoadConfig()
{
base.LoadConfig();
try
{
config = Config.ReadObject<ConfigData>();
if (config == null)
{
LoadDefaultConfig();
}
}
catch
{
for (var i = 0; i < 3; i++)
{
PrintError("Configuration file is corrupt! Check your config file at https://jsonlint.com/");
}
LoadDefaultConfig();
return;
}
ValidateConfig();
SaveConfig();
}
private void ValidateConfig()
{
if (Interface.Oxide.CallHook("OnConfigValidate") != null)
{
PrintWarning("Using default configuration...");
config = new ConfigData();
}
}
protected override void LoadDefaultConfig()
{
config = new ConfigData();
}
protected override void SaveConfig()
{
Config.WriteObject(config);
}
#endregion
#region Language System v2.1
protected override void LoadDefaultMessages()
{
Message.Register(lang, this);
}
private enum MessageKey
{
PeriodChanged,
ActionBlocked,
}
private class Message
{
private static Dictionary<MessageKey, object> langMessages = new Dictionary<MessageKey, object>
{
{MessageKey.PeriodChanged, "Period was changed to {name}"},
{MessageKey.ActionBlocked, "You can't do that action right now!"},
};
public enum Type
{
Normal,
Warning,
Error
}
private static RustPlugin plugin;
private static Lang lang;
public static void Register(Lang v1, RustPlugin v2)
{
lang = v1;
plugin = v2;
var dictionary = new Dictionary<string, string>();
foreach (var pair in langMessages)
{
var key = pair.Key.ToString();
var value = pair.Value.ToString();
dictionary.TryAdd(key, value);
}
lang.RegisterMessages(dictionary, plugin);
}
public static void Dispose()
{
lang = null;
plugin = null;
}
public static void Console(string message, Type type = Type.Normal)
{
message = $"[{plugin.Name}] {message}";
switch (type)
{
case Type.Normal:
Debug.Log(message);
break;
case Type.Warning:
Debug.LogWarning(message);
break;
case Type.Error:
Debug.LogError(message);
break;
}
}
public static void Send(object receiver, string message, params object[] args)
{
message = FormattedMessage(message, args);
SendMessage(receiver, message);
}
public static void Send(object receiver, MessageKey key, params object[] args)
{
var userID = (receiver as BasePlayer)?.UserIDString;
var message = GetMessage(key, userID, args);
SendMessage(receiver, message);
}
public static void Broadcast(string message, params object[] args)
{
foreach (var player in BasePlayer.activePlayerList)
{
message = FormattedMessage(message, args);
SendMessage(player.IPlayer, message);
}
}
public static void Broadcast(MessageKey key, params object[] args)
{
foreach (var player in BasePlayer.activePlayerList)
{
var message = GetMessage(key, player.UserIDString, args);
SendMessage(player.IPlayer, message);
}
}
public static string GetMessage(MessageKey key, string playerID = null, params object[] args)
{
var keyString = key.ToString();
var message = lang.GetMessage(keyString, plugin, playerID);
if (message == keyString)
{
return $"{keyString} is not defined in plugin!";
}
return FormattedMessage(message, args);
}
public static string FormattedMessage(string message, params object[] args)
{
if (args != null && args.Length > 0)
{
var organized = OrganizeArgs(args);
return ReplaceArgs(message, organized);
}
return message;
}
private static void SendMessage(object receiver, object message)
{
if (receiver == null || message == null)
{
return;
}
var messageString = message.ToString();
if (string.IsNullOrEmpty(messageString))
{
return;
}
var console = receiver as ConsoleSystem.Arg;
if (console != null)
{
// TODO: Finish me!
return;
}
var iPlayer = receiver as IPlayer ?? (receiver as BasePlayer)?.IPlayer;
if (iPlayer != null)
{
iPlayer.Message(messageString);
return;
}
}
private static Dictionary<string, object> OrganizeArgs(object[] args)
{
var dic = new Dictionary<string, object>();
for (var i = 0; i < args.Length; i += 2)
{
var value = args[i].ToString();
var nextValue = i + 1 < args.Length ? args[i + 1] : null;
dic.TryAdd(value, nextValue);
}
return dic;
}
private static string ReplaceArgs(string message, Dictionary<string, object> args)
{
if (args == null || args.Count < 1)
{
return message;
}
foreach (var pair in args)
{
var s0 = "{" + pair.Key + "}";
var s1 = pair.Key;
var s2 = pair.Value != null ? pair.Value.ToString() : "null";
message = message.Replace(s0, s2, StringComparison.InvariantCultureIgnoreCase);
message = message.Replace(s1, s2, StringComparison.InvariantCultureIgnoreCase);
}
return message;
}
}
#endregion
#region API
private string GetPeriod()
{
return currentPeriod?.name;
}
private void SetPeriod(string name)
{
var entry = config.periods.FirstOrDefault(x => x.name == name) ?? config.warmUpPeriod;
ChangePeriod(entry);
}
private static void OnPeriodChanged(string name)
{
}
#endregion
}
}