C#:
using System.Collections.Generic;
using Oxide.Core.Plugins;
using Oxide.Game.Rust.Cui;
using UnityEngine;
namespace Oxide.Plugins
{
[Info("RBRaidBlockTrigger", "NukeSter", "2.5.0")]
[Description("Stable RaidBlock system for RaidableBases + NoEscape v2.1.37")]
public class RBRaidBlockTrigger : RustPlugin
{
[PluginReference] private Plugin NoEscape;
private const string PermBypass = "rbraidblocktrigger.bypass";
private float raidBlockTime = 300f;
private HashSet<ulong> inRaid = new HashSet<ulong>();
private Dictionary<ulong, float> raidEndTime = new Dictionary<ulong, float>();
private Dictionary<ulong, Timer> hudTimers = new Dictionary<ulong, Timer>();
void Init()
{
permission.RegisterPermission(PermBypass, this);
}
#region RAIDABLE BASES
void OnPlayerEnteredRaidableBase(BasePlayer player)
{
if (player == null) return;
inRaid.Add(player.userID);
}
void OnPlayerExitedRaidableBase(BasePlayer player)
{
if (player == null) return;
inRaid.Remove(player.userID);
raidEndTime.Remove(player.userID);
StopHud(player);
}
#endregion
#region DAMAGE DETECTION
object OnEntityTakeDamage(BaseCombatEntity entity, HitInfo info)
{
if (entity == null || info == null) return null;
BasePlayer attacker = info.InitiatorPlayer;
if (attacker == null) return null;
if (!inRaid.Contains(attacker.userID))
return null;
if (!IsRaidExplosion(info))
return null;
TriggerRaidBlock(attacker, entity);
return null;
}
// ✔ FIXED: safe & compatible with ALL Rust versions
private bool IsRaidExplosion(HitInfo info)
{
if (info == null) return false;
return info.damageTypes.Has(Rust.DamageType.Explosion);
}
#endregion
#region RAIDBLOCK CORE
private void TriggerRaidBlock(BasePlayer player, BaseCombatEntity entity)
{
if (NoEscape == null) return;
Vector3 pos = entity != null ? entity.transform.position : player.transform.position;
float newEnd = Time.realtimeSinceStartup + raidBlockTime;
// 🔥 refresh timer on every explosive hit
raidEndTime[player.userID] = newEnd;
// ✔ correct NoEscape v2.1.37 API
NoEscape.Call("StartRaidBlocking", player, pos, true);
if (!hudTimers.ContainsKey(player.userID))
{
StartHud(player);
}
}
#endregion
#region HUD
private void StartHud(BasePlayer player)
{
StopHud(player);
hudTimers[player.userID] = timer.Every(1f, () =>
{
if (player == null || !player.IsConnected)
{
StopHud(player);
return;
}
if (!raidEndTime.ContainsKey(player.userID))
{
StopHud(player);
return;
}
float timeLeft = raidEndTime[player.userID] - Time.realtimeSinceStartup;
if (timeLeft <= 0)
{
StopHud(player);
return;
}
DrawHud(player, timeLeft);
});
}
private void DrawHud(BasePlayer player, float timeLeft)
{
CuiHelper.DestroyUi(player, "RBHUD");
CuiHelper.AddUi(player, $@"
{{
""type"": ""Overlay"",
""name"": ""RBHUD"",
""components"": [
{{
""type"": ""Text"",
""text"": ""<color=#ff4444>🔴 RAID BLOCK ACTIVE</color>\n{Format(timeLeft)}"",
""fontSize"": 18,
""align"": ""MiddleCenter""
}}
]
}}");
}
private void StopHud(BasePlayer player)
{
if (player == null) return;
ulong id = player.userID;
if (hudTimers.ContainsKey(id))
{
hudTimers[id]?.Destroy();
hudTimers.Remove(id);
}
CuiHelper.DestroyUi(player, "RBHUD");
}
private string Format(float t)
{
int m = Mathf.FloorToInt(t / 60);
int s = Mathf.FloorToInt(t % 60);
return $"{m:00}:{s:00}";
}
#endregion
}
}