C#:
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using Oxide.Core.Plugins;
using System.Reflection;
using System;
using Oxide.Core;
using System.Text;
using Newtonsoft.Json;
using System.Diagnostics;
using Oxide.Game.Rust.Cui;
using Network;
using System.Collections;
using System.ComponentModel;
using System.Text.RegularExpressions;
using Pool = Facepunch.Pool;
namespace Oxide.Plugins {
[Info("Deathmatch", "Shady", "2.1.1221")]
internal class Deathmatch : RustPlugin {
/*
* Copyright 2024 PRISM
*
* This file is part of PRISM's plugins.*
* PRISM's plugins is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.*
* PRISM's plugins is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the
* GNU General Public License for more details.*
* You should have received a copy of the GNU General Public License
* along with PRISM's plugins.If not, see <https://www.gnu.org/licenses/>.*/
/*
* The below is not a license (that can be found above), but simply a notice to the reader of this code:
* The development of PRISM has been gradual and started in 2014.* Some of the code provided in this repository may be outdated and may not be the best representation of the author's current coding practices.* Some of the code provided in this repository may have been initially developed in 2014.* Files not containing the above license are not uniquely part of PRISM's plugins and are subject to the license of the original plugin, where applicable.* No copyright infringement is ever intended and the author of PRISM's plugins will comply with any requests to remove code.* PRISM's plugins are provided as is and no functionality is guaranteed.* Many of these plugins will not work without significant changes as there are numerous instances of hard-coded functions and may rely on external API calls that are not a part of this project itself.*
*
* With those notices out of the way, I, Shady, the author of this plugin, would like you to read and acknowledge the following:
* These plugins are part of a decade long passion project where we, PRISM, created a unique experience to all players on our Rust servers.* This was a significant part of my life.I dedicated a decade to developing and maintaining these plugins and the servers themselves.* I implore you that, should you use any of the code or plugins provided in this repository, where it belongs solely to PRISM, that you respect the time and effort put into it.* Please remember that I, a single human, invested a significant amount of time and effort into these plugins and the servers they were used on.* Please feel free to critique my code as it is written; I am aware it is not perfect.Much of it is old, and I'm capable of doing far better now.* Moreover, I ask, sincerely, that you do not use these plugins or code without acknowledging that someone dedicated themselves to this passion project.* In asking that, it is my simple desire that you do not let these plugins be used in a way that is inconsistent with my own desires and love.* Please do not use them and claim them as your own.I wish for you to use them on your server and make that server something of your own.* Something unique and beautiful.However, I ask that you do not use these plugins and claim them as your own work.* Should you make changes to them, you are, of course, the author of those changes.But, if your code is based on one of PRISM's original plugins, please do not claim it as your own.* I also request that you do not use the plugins in a way that would be detrimental to the Rust community or the community of server owners.* In doing so, I ask that you please do not monetize the functions within these plugins with any changes you should make.* Should you use any of PRISM's plugins or its code, please do not lock anything behind a paywall or in a way that is unfair to the community of Rust.* My origin is that of one where I saw, daily, very young players who only wished to enjoy a few hours of their life on a video game and in many cases had little or no expendable income.* For many people, even purchasing the game is significantly difficult.It is, in my eyes, unfair to create fun, custom content, and suggest that you care about the community while also charging for it or creating an unfair environment where players who pay are significantly advantaged compared to those who cannot afford to do so.* I cannot control what you do with this code, but I ask that you respect the spirit in which it was created:
* That is one of sincere love, care, and appreciation for the people who played on PRISM's servers.* Our community, much like yours, is your entire server.Your people matter, just as you matter.Please remember that *everyone* deserves a fair, fun environment.* I ask that should you use these plugins, you do so with the same love and care that I put into them.I ask that you do so with the same respect, love, care, and appreciation for the people who will play on your server.*
* One of my greatest helps over the years was MBR.He has been a wonderful person, friend, and developer; I am beyond grateful for his contributions to us, but moreover, his friendship.* Some of these plugins were authored solely by him, or with his help.Where this has occurred, it should be noted in the author field at the top of the plugin.* Worthy of note is that he is solely responsible for our top-tier Discord integration.* If you so wish to see his GitHub page, here it is linked below:
* https://github.com/MBR-0001
*
*
* Should you wish to support the work that I have put into this project of the past decade, please consider doing so here:
* https://www.buymeacoffee.com/shady757
*
* I neither expect nor anticipate any such donations.You are by no means obligated, it is truly a donation.It should be done out of the kindness of your heart, if you so choose.*
* PRISM, as a community, has not ceased and continues to exist.We have no plans of ceasing our community.We have, however, ceased our Rust servers and thus made these plugins open source.* If you ever wish to contact me, or simply join our community and become one of our beloved members, please join us here:
* https://discord.gg/DUCnZhZ
*
* To quote Rush: "There is magic at your fingers".* With love,
* Shady and all of PRISM.Thank you for everything, always.*
*/
public string PluginNamePrefix {
get {
return Name + ":";
}
}
private bool init = false;
#region Statics
private const int PLAYER_LAYER = 131072;
//LayerMask.GetMask(new string[] { "Player (Server)" });
private readonly int _groundWorldConstLayer = LayerMask.GetMask("World", "Default", "Terrain", "Construction", "Deployable", "Prevent Building", "Deployed");
private float boundary;
private static readonly System.Random randomSpawn = new System.Random();
private static readonly System.Random randomSkins = new System.Random();
public static Deathmatch DMMain;
public static EnvSync envSync;
#endregion
private readonly HashSet<string> _forbiddenTags = new HashSet<string> {
"</color>", "</size>", "<b>", "</b>", "<i>", "</i>"
}
;
private readonly Regex _colorRegex = new Regex("(<color=.+?>)", RegexOptions.Compiled);
private readonly Regex _sizeRegex = new Regex("(<size=.+?>)", RegexOptions.Compiled);
private Coroutine _saveCoroutine = null;
[PluginReference]
private readonly Plugin Vanish;
[PluginReference]
private readonly Plugin Godmode;
[PluginReference]
private readonly Plugin NoEscape;
[PluginReference]
private readonly Plugin FindGround;
[PluginReference]
private readonly Plugin PUBG;
[PluginReference]
private readonly Plugin AAESPBlocker;
private ArenaData arenaData;
private List<ArenaInfo> Arenas {
get {
return arenaData?.arenas != null ? arenaData.arenas : new List<ArenaInfo>();
}
set {
if (arenaData != null) arenaData.arenas = value;
}
}
private class ArenaData {
public List<ArenaInfo> arenas = new List<ArenaInfo>();
public ArenaData() {
}
}
public enum StrikeType {
Rockets, Cannons, Nuke
}
;
public enum GunType {
Pistol, AssaultRifle, Rifle, Shotgun, SMG, LMG, RPG, None
}
;
public static GunType GetGunType(string shortName) {
if (string.IsNullOrEmpty(shortName)) return GunType.None;
var findDef = ItemManager.FindItemDefinition(shortName);
if (findDef == null || findDef.category != ItemCategory.Weapon) return GunType.None;
if (shortName.Contains("smg")) return GunType.SMG;
if (shortName.Contains("rifle.ak") || shortName.Contains("300")) return GunType.AssaultRifle;
if (shortName.Contains("bolt") || shortName.Contains("rifle.semi")) return GunType.Rifle;
if (shortName.Contains("lmg")) return GunType.LMG;
if (shortName.Contains("pistol")) return GunType.Pistol;
if (shortName.Contains("shotgun")) return GunType.Shotgun;
if (shortName.Contains("launcher")) return GunType.RPG;
return GunType.None;
}
private class DMData {
public Dictionary<string, string> lastPlayerPositions = new Dictionary<string, string>();
public Dictionary<string, string> lastDMTime = new Dictionary<string, string>();
public Dictionary<string, string> lastDMName = new Dictionary<string, string>();
public Dictionary<string, ArenaInfo.Team> lastDMTeam = new Dictionary<string, ArenaInfo.Team>();
public DMData() {
}
}
private DMData dmData;
#region Dictionaries
private readonly Dictionary<ulong, int> strikeAmounts = new Dictionary<ulong, int>();
private readonly Dictionary<ulong, float> lastFiredWeaponTime = new Dictionary<ulong, float>();
private readonly Dictionary<ulong, float> lastAttackTime = new Dictionary<ulong, float>();
private readonly Dictionary<Item, ulong> DMowners = new Dictionary<Item, ulong>();
private BuildingBlock strikeFoundation;
private readonly Dictionary<ulong, float> lastStrikeTime = new Dictionary<ulong, float>();
private readonly Dictionary<ulong, float> dmJoinTime = new Dictionary<ulong, float>();
private readonly Dictionary<string, Vector3> lastDeath = new Dictionary<string, Vector3>();
private readonly Dictionary<string, float> lastDeathTime = new Dictionary<string, float>();
private readonly Dictionary<string, int> heliHitTimes = new Dictionary<string, int>();
private readonly Dictionary<ulong, Dictionary<string, float>> oldMetabolism = new Dictionary<ulong, Dictionary<string, float>>();
private readonly Dictionary<ulong, int> killsWithoutDying = new Dictionary<ulong, int>();
private readonly Dictionary<int, Dictionary<int, ulong>> itemSkins = new Dictionary<int, Dictionary<int, ulong>>();
private readonly Dictionary<string, float> lastCheckTime = new Dictionary<string, float>();
private readonly Dictionary<string, float> lastNoteTime = new Dictionary<string, float>();
private readonly Dictionary<ulong, int> highPingTimes = new Dictionary<ulong, int>();
private readonly Dictionary<ItemId, float> grenadeCook = new Dictionary<ItemId, float>();
private readonly Dictionary<ulong, float> lastCookTime = new Dictionary<ulong, float>();
#endregion
#region FieldInfos
public static FieldInfo _curList = typeof(InvokeHandler).GetField("curList", BindingFlags.Instance | BindingFlags.NonPublic);
#endregion
#region References
[PluginReference]
private readonly Plugin ZoneManager;
[PluginReference]
private readonly Plugin Playtimes;
[PluginReference]
private readonly Plugin HeliControl;
[PluginReference]
private readonly Plugin Airstrike;
[PluginReference]
private readonly Plugin AttackPlanes;
#endregion
#region Hooks
private void OnLoseCondition(Item item, float amount) {
if (item == null || amount <= 0.0f) return;
var player = item?.GetOwnerPlayer() ?? null;
player = player ?? item?.parent?.entityOwner?.GetComponent<BaseProjectile>()?.GetOwnerPlayer() ?? null;
if (player == null) return;
if (InAnyDM(player.UserIDString)) NextTick(() => item?.RepairCondition(item?.maxCondition ?? 0f));
}
private void OnActiveItemChanged(BasePlayer player, Item oldItem, Item newItem) {
if (player == null || newItem == null) return;
var getDM = GetPlayerDM(player);
if (getDM != null && getDM.Airstrikes && newItem.info.shortname == "tool.binoculars") {
ShowPopup(player.UserIDString, "<color=#ff3d81>Aim your binoculars and click to call an airstrike on that position!</color>");
}
}
private void OnLootSpawn(LootContainer container) {
if (container == null) return;
var prefabName = container?.ShortPrefabName ?? string.Empty;
if (!prefabName.Contains("tier3")) return;
var pos = container?.transform?.position ?? Vector3.zero;
timer.Once(0.5f, () => {
if (container == null || container.IsDestroyed) return;
var findGun = container?.inventory?.itemList?.Where(p => p.info.category == ItemCategory.Weapon && (p?.GetHeldEntity()?.GetComponent<BaseProjectile>() != null))?.FirstOrDefault() ?? null;
if (findGun == null) {
PrintWarning("No gun for: " + container.ShortPrefabName + ", " + pos);
return;
}
if (findGun != null) {
var type = GetGunType(findGun.info.shortname);
var oldAmmo = findGun?.GetHeldEntity()?.GetComponent<BaseProjectile>()?.primaryMagazine?.ammoType ?? null;
var rarity = findGun.info.rarity;
var rngReplace = UnityEngine.Random.Range(0, 101);
var rngNeed = (type == GunType.SMG && findGun.info.shortname.Contains("mp5")) ? 10 : (type == GunType.SMG) ? 30 : (type == GunType.AssaultRifle) ? 40 : (type == GunType.Shotgun && findGun.info.shortname.Contains("spas")) ? 12 : (type == GunType.Shotgun) ? 25 : (type == GunType.Rifle && findGun.info.shortname.Contains("bolt")) ? 10 : (type == GunType.Rifle) ? 30 : (type == GunType.RPG) ? 65 : 40;
if (rngReplace <= rngNeed) {
//PrintWarning("rngReplace <= rngNeed: " + rngReplace + " <= " + rngNeed + ", for: " + findGun.info.shortname + ", " + rarity);
var replace = ItemManager.itemList?.Where(p => p != null && p.shortname != findGun.info.shortname && ((type == GunType.RPG && GetGunType(p.shortname) != GunType.None) || GetGunType(p.shortname) == type) && (p.rarity == rarity || (rarity != Rust.Rarity.None && p.rarity >= rarity)))?.ToList()?.GetRandom() ?? null;
if (replace == null) {
PrintWarning("replace is null!! original: " + findGun?.info?.displayName?.english);
return;
}
//PrintWarning("Got replace: " + replace.shortname);
var oldPos = findGun?.position ?? -1;
var oldParent = findGun?.parent ?? null;
RemoveFromWorld(findGun);
var replaceItem = ItemManager.Create(replace, 1);
if (replaceItem == null) {
PrintWarning("replaceItem null somehow?!");
return;
}
if (!replaceItem.MoveToContainer(oldParent, oldPos) && !replaceItem.MoveToContainer(oldParent)) {
RemoveFromWorld(replaceItem);
PrintWarning("replaceItem couldn't be moved!!");
return;
}
var proj = replaceItem?.GetHeldEntity()?.GetComponent<BaseProjectile>() ?? null;
if (proj == null) {
PrintWarning("baseprojectile is null: " + replace?.shortname);
return;
}
var newAmmo = proj?.primaryMagazine?.ammoType ?? null;
var capacity = proj?.primaryMagazine?.capacity ?? 0;
var ammoAmount = (int)Math.Round(capacity * 0.9, MidpointRounding.AwayFromZero);
// var ammoAmount = proj?.primaryMagazine?.capacity ?? 8;
if (proj?.primaryMagazine != null) proj.primaryMagazine.contents = capacity;
if (ammoAmount < 5) ammoAmount *= (int)Math.Round(UnityEngine.Random.Range(1.7f, 3f), MidpointRounding.AwayFromZero);
if (newAmmo != null) {
// PrintWarning("oldAmmo != newAmmo");
var allAmmo = container?.inventory?.itemList?.Where(p => p != null && p.info.category == ItemCategory.Ammunition)?.ToList() ?? null;
if (allAmmo != null && allAmmo.Count > 0) for (int i = 0; i < allAmmo.Count; i++) RemoveFromWorld(allAmmo[i]);
var ammoItem = ItemManager.Create(newAmmo, ammoAmount);
if (ammoItem == null) {
PrintWarning("new ammo item is null!!");
return;
}
if (!ammoItem.MoveToContainer(oldParent)) {
RemoveFromWorld(ammoItem);
PrintWarning("ammoItem couldn't be moved!!");
return;
}
}
}
}
}
);
}
private void Unload() {
try {
for (int i = 0; i < BasePlayer.activePlayerList.Count; i++) {
var player = BasePlayer.activePlayerList[i];
if (player == null || !(player?.IsConnected ?? false)) continue;
CuiHelper.DestroyUi(player, "BlindUI");
CuiHelper.DestroyUi(player, "BlindUIText");
CuiHelper.DestroyUi(player, "DMGUI");
CuiHelper.DestroyUi(player, "DMSGUI");
CuiHelper.DestroyUi(player, "DMAlive");
CuiHelper.DestroyUi(player, "DMAliveText");
CuiHelper.DestroyUi(player, "DMKills");
CuiHelper.DestroyUi(player, "DMKillsText");
var getDM = GetPlayerDM(player);
if (getDM != null) {
if (getDM.Teams) dmData.lastDMTeam[player.UserIDString] = getDM.GetTeam(player);
if (!getDM.LeaveDM(player)) PrintWarning("getDM was not null but player could not be forced to leave!!");
else {
dmData.lastDMTime[player.UserIDString] = DateTime.Now.ToString();
dmData.lastDMName[player.UserIDString] = getDM.ArenaName;
}
}
}
var exSB = new StringBuilder();
try {
var invList = InvokeList;
var objStr = this?.Object?.ToString() ?? string.Empty;
// var invokeEnum = (invList == null || invList.Count < 1 || string.IsNullOrEmpty(objStr)) ? null : invList?.Where(p => p.Key != null && (p.Key.action?.Target?.ToString() ?? string.Empty).Contains(objStr)) ?? null;
var newEnums = new ListDictionary<InvokeAction, float>();
foreach (var inv in invList) {
try {
if (inv.Key == null || inv.Key.action == null || inv.Key.action.Target == null) continue;
}
catch (Exception ex) {
exSB.AppendLine(ex.ToString() + " (couldn't even do null checks without an error!");
continue;
}
var strTarg = string.Empty;
try {
strTarg = inv.Key.action?.Target?.ToString() ?? string.Empty;
}
catch (Exception ex) {
exSB.AppendLine(ex.ToString());
continue;
}
if (!string.IsNullOrEmpty(strTarg) && strTarg.Contains(objStr)) newEnums.Add(inv.Key, inv.Value);
}
if (newEnums != null && newEnums.Count > 0) {
PrintWarning("Got newEnums: " + newEnums.Count);
foreach (var inv in newEnums) InvokeHandler.CancelInvoke(inv.Key.sender, inv.Key.action);
}
else PrintWarning("no newEnums!");
}
catch (Exception ex) {
PrintError(ex.ToString() + Environment.NewLine + "Error on Unload() for invokes");
}
if (exSB.Length > 0) PrintError(exSB.ToString());
/*/
try
{
var invokes = InvokeList.Where(p => (p.Key.action?.Target ?? null).ToString() == this.Object.ToString())?.ToList() ?? null;
if (invokes != null && invokes.Count > 0)
{
var invokeSB = new StringBuilder();
for (int i = 0; i < invokes.Count; i++)
{
var inv = invokes[i];
try
{
InvokeHandler.CancelInvoke(inv.Key.sender, inv.Key.action);
invokeSB.AppendLine("cancel invoke: " + inv.Key.action.Method.Name);
}
catch(Exception ex) { PrintError(ex.ToString()); }
}
PrintWarning(invokeSB.ToString().TrimEnd());
}
}
catch(Exception ex) { PrintError(ex.ToString()); }/*/
for (int i = 0; i < Arenas.Count; i++) {
var arena = Arenas[i];
if (arena == null) continue;
if (arena.GameTimer != null) {
arena.GameTimer.Destroy();
arena.GameTimer = null;
}
arena.EndSphere();
}
SaveData();
}
finally {
DMMain = null;
}
}
private object CanUseOverdrive(BasePlayer player) {
if (player == null) return null;
if (InAnyDM(player.UserIDString)) return false;
return null;
}
private object CanTeleport(BasePlayer player) {
if (player == null) return null;
if (InAnyDM(player.UserIDString)) return "You cannot teleport while in Deathmatch!";
return null;
}
private object CanPlayerTrade(BasePlayer player) {
if (player == null || !player.IsConnected) return null;
if (InAnyDM(player.UserIDString)) return "You cannot trade while in Deatchmatch!";
return null;
}
/*/
private object OnPlayerDropActiveItem(BasePlayer player, Item item)
{
if (player == null || item == null) return null;
var getDM = GetPlayerDM(player);
if (getDM != null && !getDM.AllowDroppingActiveItem)
{
if (!getDM.AllowDropping)
{
}
return true;
}
// if (InAnyDM(player.UserIDString)) return true;
return null;
}/*/
private object CanLootEntity(BasePlayer player, StorageContainer target) {
if (player == null || target == null) return null;
var getDM = GetPlayerDM(player);
if (target.ShortPrefabName.Contains("dm ") && getDM == null && !player.IsAdmin) return false;
if (getDM == null || string.IsNullOrEmpty(getDM.ZoneID)) return null;
var lootContainer = target as LootContainer;
if (lootContainer != null) return null;
var targetPly = target?.GetComponent<BasePlayer>() ?? null;
if (targetPly != null) return false;
if (!isEntityInZone(target, getDM.ZoneID)) return false;
return null;
}
private object CanLootPlayer(BasePlayer target, BasePlayer player) {
if (player == null || target == null) return null;
if (!player.IsAdmin && (InAnyDM(target.UserIDString) || InAnyDM(player.UserIDString))) return false;
return null;
}
private object OnMaxStackable(Item item) {
if (item == null) return null;
var player = item?.parent?.playerOwner ?? item?.GetOwnerPlayer() ?? null;
if (player == null) return null;
var getDM = GetPlayerDM(player);
if (getDM != null && getDM.IgnoreStacks) return int.MaxValue - 1;
return null;
}
private object CanStackItem(Item item, Item targetItem) {
if (item == null || targetItem == null) return null;
if (item?.info?.shortname != targetItem?.info?.shortname) return null;
var player = targetItem?.parent?.playerOwner ?? targetItem?.GetOwnerPlayer() ?? item?.parent?.playerOwner ?? item?.GetOwnerPlayer() ?? null;
if (player == null) return null;
var getDM = GetPlayerDM(player);
if (getDM != null && getDM.IgnoreStacks) return true;
return null;
}
// var hookVal = Interface.Oxide.CallHook("CanScaleNomadAttackerDamage", attackerPlayer, hitInfo);
private object CanScaleNomadAttackerDamage(BasePlayer attacker, HitInfo info) {
if (InAnyDM(attacker.UserIDString)) return false;
return null;
}
private object CanScaleNomadVictimDamage(BasePlayer attacker, HitInfo info) {
if (InAnyDM(attacker.UserIDString)) return false;
return null;
}
private void OnDispenserGather(ResourceDispenser dispenser, BaseEntity entity, Item item) {
var player = entity as BasePlayer;
if (player == null || dispenser == null) return;
var getDM = GetPlayerDM(player);
if (getDM != null && !getDM.AllowGather) {
// var dispEnt = dispenser?.GetComponent<BaseEntity>() ?? null;
// if (dispEnt != null && !dispEnt.IsDestroyed) dispEnt.Kill();
item.amount = 0;
}
}
private object OnRunPlayerMetabolism(PlayerMetabolism metabolism) {
if (metabolism == null) return null;
var player = metabolism?.GetComponent<BasePlayer>() ?? null;
if (player == null || (player?.IsDead() ?? true) || !player.IsConnected) return null;
var getDM = GetPlayerDM(player);
if (getDM != null) {
metabolism.calories.value = 500;
metabolism.hydration.value = 250;
if (metabolism.temperature.value < 25) metabolism.temperature.value = 25;
metabolism.radiation_level.value = 0;
metabolism.radiation_poison.value = 0;
if (getDM.BleedingScalar <= 0) metabolism.bleeding.value = 0;
metabolism.SendChangesToClient();
if (getDM.Fortnite) return true;
}
return null;
}
private void OnHealingItemUse(MedicalTool tool, BasePlayer player) {
if (tool == null || player == null) return;
var arena = GetPlayerDM(player);
if (arena == null || arena.HealingScalar == 1f) return;
var oldHP = player?.Health() ?? 0f;
NextTick(() => {
if (player == null || player.IsDestroyed || player.gameObject == null || player.IsDead()) return;
var newHP = player?.Health() ?? 0f;
var healAmount = newHP - oldHP;
var newHeal = healAmount * arena.HealingScalar;
//PrintWarning("oldHP: " + oldHP + " new hp: " + newHP + ", healAmount: " + healAmount + " newHeal: " + newHeal);
player.health = oldHP + newHeal;
player?.metabolism?.SendChangesToClient();
}
);
}
private object CanHelicopterStrafeTarget(PatrolHelicopterAI entity, BasePlayer target) {
if (entity == null || target == null) return null;
if (InAnyDM(target.UserIDString)) return false;
return null;
}
private object CanHelicopterTarget(PatrolHelicopterAI heli, BasePlayer player) {
if (heli == null || player == null || IsVanished(player)) return null;
if (InAnyDM(player.UserIDString)) return false;
return null;
}
private object OnHelicopterTarget(HelicopterTurret turret, BaseCombatEntity entity) {
if (turret == null || entity == null) return null;
var player = entity as BasePlayer;
if (player == null || !(player?.IsConnected ?? false) || IsVanished(player)) return null;
if (InAnyDM(player.UserIDString)) return false;
return null;
}
private object CanBeTargeted(BaseCombatEntity entity, MonoBehaviour monoTurret) {
if (!init || entity == null || (entity?.IsDestroyed ?? true) || monoTurret == null) return null;
try {
if (!(monoTurret is HelicopterTurret)) return null;
if (!(entity is BasePlayer)) return null;
var player = entity as BasePlayer;
if (player == null) return null;
if (IsVanished(player)) return null;
if (InAnyDM(player.UserIDString)) return false;
}
catch (Exception ex) {
PrintError(ex.ToString() + Environment.NewLine + "^Failed to complete CanBeTargeted^");
}
return null;
}
private object CanBeWounded(BasePlayer player, HitInfo hitinfo) {
if (player == null) return null;
var getDM = GetPlayerDM(player);
if (getDM != null && getDM.Fortnite) return false;
return null;
}
private object OnServerCommand(ConsoleSystem.Arg arg) {
var IP = arg?.Connection?.ipaddress ?? string.Empty;
if ((arg?.Player() ?? null) == null && !string.IsNullOrEmpty(IP)) PrintWarning("Command without player: " + IP + ", " + (arg?.cmd?.FullName ?? "Unknown"));
if (arg == null || arg.Connection == null || arg.cmd == null || arg.cmd.Name == null || !init) return null;
var player = arg?.Player() ?? null;
if (player == null) return null;
var command = arg?.cmd?.FullName ?? string.Empty;
ArenaInfo getDM;
if (command.Contains("kill") && (getDM = GetPlayerDM(player)) != null) {
var inZone = isPlayerInZone(player, getDM.ZoneID);
if (!inZone) {
PrintWarning("got all dms but not in zone: " + player.displayName);
arg.ReplyWith("You cannot use this right now!");
return false;
}
}
if ((command.Contains("addtoteam") || command.Contains("trycreateteam") || command.Contains("acceptinvite")) && InAnyDM(player.UserIDString)) {
SendReply(player, "You cannot make teams while in Deathmatch!");
return false;
}
return null;
}
private object OnPlayerViolation(BasePlayer player, AntiHackType type, float amount) {
if (player == null || amount < 0) return null;
var getDM = GetPlayerDM(player);
if (getDM == null) return null;
if (player.lifeStory != null && GetTimeAlive(player) <= 5) return true;
if (getDM.SoftAntiHack && type == AntiHackType.FlyHack) return true;
return null;
}
private readonly Dictionary<string, float> lastScoreGUI = new Dictionary<string, float>();
private readonly Dictionary<BasePlayer, Timer> kickTimer = new Dictionary<BasePlayer, Timer>();
private readonly Dictionary<ulong, float> lastBinocularTime = new Dictionary<ulong, float>();
private void OnPlayerInput(BasePlayer player, InputState input) {
if (player == null || input == null) return;
if (player.IsDead() || player.IsSleeping() || player.IsWounded()) return;
var watch = Stopwatch.StartNew();
var heldItem = player?.GetActiveItem() ?? null;
var isGrenade = (heldItem?.info?.shortname ?? string.Empty) == "grenade.f1";
var arena = GetPlayerDM(player);
if (arena != null && arena.Airstrikes && heldItem?.info?.shortname == "tool.binoculars") {
float lastBinoc;
if (lastBinocularTime.TryGetValue(player.userID, out lastBinoc) && (Time.realtimeSinceStartup - lastBinoc) < 2) {
return;
}
if (input.WasJustPressed(BUTTON.FIRE_PRIMARY) && (input.IsDown(BUTTON.FIRE_SECONDARY) || input.WasDown(BUTTON.FIRE_SECONDARY))) {
int airstrikes;
if (player.IsAdmin || (strikeAmounts.TryGetValue(player.userID, out airstrikes) && airstrikes > 0)) {
player.SendConsoleCommand("dm.strike");
}
else {
ShowPopup(player.UserIDString, "No airstrike available!", 3.5f);
}
lastBinocularTime[player.userID] = Time.realtimeSinceStartup;
}
}
if (isGrenade && arena != null && input.IsDown(BUTTON.FIRE_PRIMARY)) {
var lastCookTimeF = 0f;
var grenadeCookFuse = 0f;
if (!grenadeCook.TryGetValue(heldItem.uid, out grenadeCookFuse)) grenadeCookFuse = grenadeCook[heldItem.uid] = 5f;
var eyePos = player?.eyes?.position ?? Vector3.zero;
var centerPos = player?.CenterPoint() ?? Vector3.zero;
if (!lastCookTime.TryGetValue(player.userID, out lastCookTimeF)) {
lastCookTime[player.userID] = Time.realtimeSinceStartup;
grenadeCookFuse -= 1f;
}
else {
if ((Time.realtimeSinceStartup - lastCookTimeF) >= 1) {
grenadeCookFuse -= 1f;
lastCookTime[player.userID] = Time.realtimeSinceStartup;
}
}
if (grenadeCookFuse != grenadeCook[heldItem.uid]) {
SendLocalEffect(player, "assets/bundled/prefabs/fx/weapons/landmine/landmine_trigger.prefab", 1, 0, new Vector3(0, 0.125f));
}
if (grenadeCookFuse <= 0.05f) {
Effect.server.Run("assets/prefabs/weapons/f1 grenade/effects/f1grenade_explosion.prefab", eyePos, Vector3.zero);
var newDmgList = new List<Rust.DamageTypeEntry>();
var newDmg = new Rust.DamageTypeEntry {
amount = UnityEngine.Random.Range(50, 75), type = Rust.DamageType.Stab
}
;
newDmgList.Add(newDmg);
newDmg = new Rust.DamageTypeEntry {
amount = UnityEngine.Random.Range(20, 75), type = Rust.DamageType.Explosion
}
;
newDmgList.Add(newDmg);
DamageUtil.RadiusDamage(player, heldItem.GetHeldEntity(), player.eyes.position, 3f, 3f, newDmgList, PLAYER_LAYER, true);
if (heldItem.amount > 1) {
heldItem.amount--;
heldItem.MarkDirty();
grenadeCook[heldItem.uid] = 5f;
}
else RemoveFromWorld(heldItem);
return;
}
grenadeCook[heldItem.uid] = Mathf.Clamp(grenadeCookFuse, 0.05f, 6);
}
if (arena != null && arena.Teams) {
if (player.IsSpectating() && arena.SpectateTeamDead && arena.Teams && arena.GetTeamCount(arena.GetTeam(player)) > 1) {
if (input.WasJustPressed(BUTTON.DUCK) || input.WasJustPressed(BUTTON.JUMP)) {
var rngTeam = arena.GetTeamPlayers(arena.GetTeam(player))?.Where(p => p != player && !p.IsDead() && !p.IsSpectating() && p.UserIDString != player.spectateFilter)?.ToList()?.GetRandom() ?? null;
if (rngTeam != null) player.spectateFilter = rngTeam.UserIDString;
}
}
float lastGUI;
if (!lastScoreGUI.TryGetValue(player.UserIDString, out lastGUI) || (Time.realtimeSinceStartup - lastGUI) > 1.3f) {
if (input.IsDown(BUTTON.SPRINT) && input.IsDown(BUTTON.USE)) {
ScoreGUILarge(player, arena, 1.33f);
lastScoreGUI[player.UserIDString] = Time.realtimeSinceStartup;
}
}
}
if (arena != null && arena.Fortnite) {
if (player.IsSpectating() && (input.WasJustPressed(BUTTON.DUCK) || input.WasJustPressed(BUTTON.JUMP))) {
PrintWarning("Spectate filter prior to pressing space was: " + player.spectateFilter);
var rngSpec = arena?.ActivePlayers?.Where(p => p != null && !p.IsDead() && !p.IsSpectating() && p != player && !p.UserIDString.Equals(player.spectateFilter.Replace(" ", ""), StringComparison.OrdinalIgnoreCase))?.ToList()?.GetRandom() ?? null;
if (rngSpec != null) {
player.spectateFilter = rngSpec.UserIDString;
PrintWarning("Spectate filter after pressing space was: " + player.spectateFilter);
}
}
}
var now = Time.realtimeSinceStartup;
var lastTime = 0f;
if (!lastCheckTime.TryGetValue(player.UserIDString, out lastTime)) lastCheckTime[player.UserIDString] = now - 10;
else if ((lastTime = now - lastTime) < 2.5) return;
if (arena != null) {
var zoneID = arena?.ZoneID ?? string.Empty;
if (!isPlayerInZone(player, zoneID) && !player.IsSpectating() && GetTimeAlive(player) >= 1.5f) {
if (arena.Fortnite) player.Hurt(UnityEngine.Random.Range(3f, 8f), Rust.DamageType.ElectricShock, null, false);
else {
Timer outTimer;
if (!kickTimer.TryGetValue(player, out outTimer) || outTimer == null || outTimer.Destroyed) {
Timer newTimer = null;
newTimer = timer.Once(1f, () => {
if (player == null || player.IsDead()) return;
if (!isPlayerInZone(player, zoneID)) {
SendReply(player, "You are being kicked because you're outside of the <color=#fcb355>" + arena.ArenaName + "</color> zone!");
arena.LeaveDM(player);
GrantImmunity(player, 2.5f);
WakePlayerUp(player, true);
newTimer = null;
kickTimer[player] = null;
}
}
);
kickTimer[player] = newTimer;
}
}
}
}
if (!player.IsAdmin) {
for (int i = 0; i < Arenas.Count; i++) {
var arena2 = Arenas[i];
if (arena2 == null || arena2.Disabled || arena2.Fortnite || arena2.ZoneID == "0" || string.IsNullOrEmpty(arena2.ZoneID)) continue;
if (isPlayerInZone(player, arena2.ZoneID) && !arena2.ActivePlayers.Contains(player)) {
SendReply(player, "You are in the <color=#fcb355>" + arena2.ArenaName + "</color> deathmatch zone, but you have not joined! Please leave this area.");
if (player?.metabolism != null) {
player.metabolism.radiation_poison.MoveTowards(player.metabolism.radiation_poison.value + 36f, 5f);
player.metabolism.radiation_level.value = player.metabolism.radiation_poison.value;
}
}
}
}
var lastNote = 0f;
if (!lastNoteTime.TryGetValue(player.UserIDString, out lastNote)) lastNoteTime[player.UserIDString] = now - 10;
else lastNote = now - lastNote;
if (lastNote < 5) return;
lastCheckTime[player.UserIDString] = now;
var isDM = arena != null;
if (isDM) {
var HPT = 0;
if (highPingTimes.TryGetValue(player.userID, out HPT) && HPT > 9) {
arena.LeaveDM(player);
SendReply(player, "<color=#a6fc60>You were kicked from DM because your ping was too high (300+) for too long! Please try again later.</color>");
highPingTimes[player.userID] = 0;
PrintWarning("Kicking: " + player.displayName + " for too high ping for too long!");
return;
}
var maxPing = arena?.MaxPing ?? -1;
if (maxPing != -1 && GetPing(player) >= maxPing) {
highPingTimes[player.userID] = HPT++;
SendReply(player, "Your ping is too high! If it does not go down soon, you'll be kicked from DM!");
}
else highPingTimes[player.userID] = 0;
if (lastNote >= 8) {
var noteSB = new StringBuilder();
if (IsVanished(player)) noteSB.AppendLine("<size=16>NOTE: You're vanished while in Deathmatch!</size>");
if (IsGodmode(player)) noteSB.AppendLine("<size=16>NOTE: You're in Godmode while in Deathmatch!</size>");
if (noteSB.Length > 0) {
SendReply(player, noteSB.ToString().TrimEnd());
lastNoteTime[player.UserIDString] = now;
}
}
if (!player.IsAdmin && !player.IsSpectating()) {
var idle = player?.IdleTime ?? 0f;
if (idle >= 300) {
SendReply(player, "Kicking you from DM for being idle too long!");
arena.LeaveDM(player);
return;
}
}
}
watch.Stop();
if (watch.Elapsed.TotalMilliseconds > 1.5) PrintWarning("OnPlayerInput for Deathmatch took: " + watch.Elapsed.TotalMilliseconds + "ms");
}
private float TimeSinceFiredWeapon(BasePlayer player) {
if (player == null) return -1f;
float lastTime;
if (lastFiredWeaponTime.TryGetValue(player.userID, out lastTime)) return Time.realtimeSinceStartup - lastTime;
return -1f;
}
private float TimeSinceAttacked(BasePlayer player) {
if (player == null) return -1f;
float lastTime;
if (lastAttackTime.TryGetValue(player.userID, out lastTime)) return Time.realtimeSinceStartup - lastTime;
return -1f;
}
private void OnWeaponFired(BaseProjectile projectile, BasePlayer player, ItemModProjectile mod, ProtoBuf.ProjectileShoot projectiles) => lastFiredWeaponTime[player.userID] = Time.realtimeSinceStartup;
private void OnPlayerDisconnected(BasePlayer player) {
if (player == null) return;
var findDM = GetPlayerDM(player) ?? null;
if (findDM != null) {
GrantImmunity(player, 1.5f);
findDM.LeaveDM(player);
}
}
private void OnPlayerConnected(BasePlayer player) {
if (player == null) return;
RemoveAllDMItems(player);
if (Arenas != null && Arenas.Count > 0) {
ArenaInfo findForce = null;
for (int i = 0; i < Arenas.Count; i++) {
var arena = Arenas[i];
if (arena != null && arena.ForceJoin) {
findForce = arena;
break;
}
}
if (findForce == null) return;
PrintWarning("Force joining DM: " + findForce.ArenaName + " for player: " + player.displayName);
if (!findForce.JoinDM(player)) {
PrintWarning("!!!Could not forcefully join DM: " + player.displayName + "!!!");
if (findForce.RoundBased && findForce.GameInProgress && !findForce.JoinMidRound) {
PrintWarning("findForce is roundbased, game in progress & no join mid round, attempting queue...");
if (findForce.JoinQueue(player, false)) PrintWarning("Did join queue!");
else PrintWarning("Did not join queue!!");
}
}
}
}
private void OnPlayerSleepEnded(BasePlayer player) {
if (player == null) return;
if (!InAnyDM(player.UserIDString)) RemoveAllDMItems(player);
}
private void OnPlayerRespawned(BasePlayer player) {
// ... [Code preview truncated due to length. Full source in attached file] ...