C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
/*
* < ----- End-User License Agreement ----->
*
* 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 IIIaKa 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.*
* Developer: IIIaKa
* https://t.me/iiiaka
* Discord: @iiiaka
* https://github.com/IIIaKa
* https://umod.org/user/IIIaKa
* https://codefling.com/iiiaka
* https://www.patreon.com/iiiaka
* https://boosty.to/iiiaka
* Codefling plugin page: https://codefling.com/plugins/real-pve
* Codefling license: https://codefling.com/plugins/real-pve?tab=downloads_field_4
*
* Copyright © 2024 IIIaKa
*/
using System;
using UnityEngine;
using System.Collections.Generic;
using System.Linq;
using Facepunch;
using Newtonsoft.Json;
using Oxide.Core.Plugins;
using System.Globalization;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using Oxide.Game.Rust.Cui;
using Rust;
using Oxide.Plugins.ExtensionsRealPVE;
using UnityEngine.UI;
using Rust.Ai.Gen2;
namespace Oxide.Plugins {
[Info("RealPVE", "IIIaKa", "0.1.13")]
[Description("Plugin for Real PvE servers, featuring damage prevention, anti-griefing measures, customizable PvP zones, an automatic loot queue in radtowns and raid zones, and much more.")]
class RealPVE : RustPlugin {
private void InitMonuments() {
_harborEventMonument = string.Empty;
_monumentsList.Clear();
var pvpMonuments = new HashSet<string>();
var monuments = (Dictionary<string, string>)(MonumentsWatcher?.Call("GetMonumentsTypeDictionary") ?? new Dictionary<string, string>());
MonumentSettings monumentSettings;
foreach (var kvp in monuments) {
if (!_monumentsConfig.TrackedTypes.Contains(kvp.Value) || _monumentsConfig.IgnoredNames.Contains(kvp.Key)) continue;
var monumentID = kvp.Key;
if (monumentID.Contains("CargoShip")) {
if (!_monumentsConfig.IgnoredNames.Contains("CargoShip") && IsMonumentCargoValid(monumentID)) {
monumentSettings = _monumentsConfig.MonumentsSettings["CargoShip"];
_monumentsList[monumentID] = new MonumentData(monumentID, monumentSettings, true);
if (monumentSettings.IsPvP) pvpMonuments.Add(GetMonumentName(monumentID));
}
continue;
}
if (!_monumentsConfig.MonumentsSettings.TryGetValue(monumentID, out monumentSettings) || monumentSettings == null) _monumentsConfig.MonumentsSettings[monumentID] = monumentSettings = new MonumentSettings(monumentID, kvp.Value);
_monumentsList[monumentID] = new MonumentData(monumentID, monumentSettings);
if (monumentSettings.IsPvP) pvpMonuments.Add(GetMonumentName(monumentID));
}
SaveConfig();
LoadMonumentsImages();
if (!_monumentsList.Any()) return;
if (pvpMonuments.Any()) PrintWarning($"PvP flagged monuments: {string.Join(", ", pvpMonuments)}");
foreach (var player in BasePlayer.activePlayerList) {
if (player.userID.IsSteamId() && _monumentsList.TryGetValue(GetPlayerMonument(player.userID), out var monumentData)) monumentData.OnPlayerEnter(player);
}
Subscribe(nameof(OnNpcTarget));
Subscribe(nameof(OnEntityEnteredMonument));
Subscribe(nameof(OnEntityExitedMonument));
Subscribe(nameof(OnPlayerEnteredMonument));
Subscribe(nameof(OnPlayerExitedMonument));
Subscribe(nameof(OnCargoWatcherCreated));
Subscribe(nameof(OnCargoWatcherDeleted));
if (_monumentsConfig.CargoShip_HarborToPvP || _monumentsConfig.CargoShip_LargeHarborToPvP) {
Subscribe(nameof(OnCargoShipHarborArrived));
Subscribe(nameof(OnCargoShipHarborLeave));
}
Subscribe(nameof(OnHarborEventStart));
Subscribe(nameof(OnHarborEventEnd));
if (_monumentsList.ContainsKey("excavator_1")) {
Subscribe(nameof(OnExcavatorResourceSet));
Subscribe(nameof(OnExcavatorSuppliesRequest));
Subscribe(nameof(OnExcavatorSuppliesRequested));
}
Subscribe(nameof(CanHackCrate));
SaveMonumentsConfig();
}
object OnCrateLaptopAttack(HackableLockedCrate crate, HitInfo info) {
if (info != null && info.InitiatorPlayer is BasePlayer attacker && _monumentsList.TryGetValue(GetEntityMonument(crate), out var monumentData)) return monumentData.CanLoot(attacker);
return false;
}
object CanLootEntity(BasePlayer player, Stocking stocking) => CanLootStorage(player, stocking);
private static RealPVE Instance {
get;
set;
}
void OnEntitySpawned(LootableCorpse corpse) {
if (corpse.playerSteamID.IsSteamId()) return;
var parentEnt = corpse.parentEnt;
if (parentEnt != null && parentEnt.skinID != 0uL) {
corpse.skinID = parentEnt.skinID;
if (parentEnt.skinID == _rrPluginID && _config.RandomRaids_Enabled && _rrAllRaiders.TryGetValue(parentEnt.net.ID.Value, out var rrData)) {
_rrAllRaiders.Add(corpse.net.ID.Value, rrData);
rrData.Raiders.Add(corpse.net.ID.Value);
}
}
}
private string GetNpcMonument(BasePlayer npcPlayer) => (string)(MonumentsWatcher?.Call(MonumentGetNpcMonument, npcPlayer.net.ID) ?? string.Empty);
private const string _uiVehiclePanel = "RealPVE_VehiclePanel", _dataVehiclesPath = @"RealPVE\Data\VehiclesData";
private const string MonumentGetMonumentDisplayName = "GetMonumentDisplayName", MonumentGetMonumentType = "GetMonumentType", MonumentGetMonumentPlayers = "GetMonumentPlayers", MonumentGetMonumentEntities = "GetMonumentEntities", MonumentGetPlayerMonument = "GetPlayerMonument", MonumentGetNpcMonument = "GetNpcMonument", MonumentGetEntityMonument = "GetEntityMonument", MonumentGetMonumentPosition = "GetMonumentPosition", MonumentGetMonumentsByPos = "GetMonumentsByPos", MonumentIsPlayerInMonument = "IsPlayerInMonument";
private object CanLootByOwnerID(BasePlayer player, BaseEntity entity) {
if (entity.OwnerID.IsSteamId() && !_unrestrictedLooters.Contains(player.userID) && !IsEntityInPvP(player.userID, entity.net.ID.Value)) {
object result = player.TasirMumkin(entity.OwnerID);
if (result != null) SendMessage(player, "MsgCantInteract");
return result;
}
return null;
}
private void GiveDefaultItems(BasePlayer player) {
if (player.isMounted) return;
var inventory = player.inventory;
bool canOverride = true;
var bags = Pool.Get<List<SleepingBag>>();
Vis.Entities(inventory.baseEntity.transform.position, 0.1f, bags);
foreach (var bag in bags) {
if (bag.deployerUserID == player.userID) {
canOverride = false;
break;
}
}
Pool.FreeUnmanaged(ref bags);
if (!canOverride) return;
inventory.Strip();
foreach (var rItem in _beachConfig.Respawn_Main) {
var item = ItemManager.CreateByName(rItem.ShortName, rItem.Amount, rItem.SkinID);
if (item != null) {
if (!string.IsNullOrWhiteSpace(rItem.Text)) item.text = lang.GetMessage(rItem.Text, this, player.UserIDString);
item.MoveToContainer(inventory.containerMain, rItem.Slot);
}
}
foreach (var rItem in _beachConfig.Respawn_Belt) {
var item = ItemManager.CreateByName(rItem.ShortName, rItem.Amount, rItem.SkinID);
if (item != null) {
if (!string.IsNullOrWhiteSpace(rItem.Text)) item.text = lang.GetMessage(rItem.Text, this, player.UserIDString);
item.MoveToContainer(inventory.containerBelt, rItem.Slot);
}
}
foreach (var rItem in _beachConfig.Respawn_Wear) {
var item = ItemManager.CreateByName(rItem.ShortName, rItem.Amount, rItem.SkinID);
if (item != null) {
if (!string.IsNullOrWhiteSpace(rItem.Text)) item.text = lang.GetMessage(rItem.Text, this, player.UserIDString);
item.MoveToContainer(inventory.containerWear, rItem.Slot);
}
}
if (PlayerInventory.IsBirthday()) {
inventory.GiveItem(ItemManager.CreateByName("cakefiveyear", 1, 0uL), inventory.containerBelt);
inventory.GiveItem(ItemManager.CreateByName("partyhat", 1, 0uL), inventory.containerWear);
}
if (PlayerInventory.IsChristmas()) {
inventory.GiveItem(ItemManager.CreateByName("snowball", 1, 0uL), inventory.containerBelt);
inventory.GiveItem(ItemManager.CreateByName("snowball", 1, 0uL), inventory.containerBelt);
inventory.GiveItem(ItemManager.CreateByName("snowball", 1, 0uL), inventory.containerBelt);
}
}
private void DestroyUI(BasePlayer player, string uiName) {
CuiHelper.DestroyUi(player, uiName);
if (_playerUI.ContainsKey(player.userID)) _playerUI[player.userID].Remove(uiName);
}
private void LoadMonumentsConfig() {
List<CuiElement> uiList = null;
if (Interface.Oxide.DataFileSystem.ExistsDatafile(_monumentsPath)) {
try {
_monumentsConfig = Interface.Oxide.DataFileSystem.ReadObject<MonumentConfig>(_monumentsPath);
uiList = Interface.Oxide.DataFileSystem.ReadObject<List<CuiElement>>(_monumentsUiOfferPath);
}
catch (Exception ex) {
UnityEngine.Debug.LogException(ex);
}
}
if (_monumentsConfig == null || _monumentsConfig.Version < _monumentsVersion) {
if (_monumentsConfig != null) {
string path = string.Format(_monumentsPathOld, _monumentsConfig.Version.ToString());
PrintWarning($@"Your settings version for monuments is outdated.The config file has been updated, and your old settings have been saved in \data\{path}");
SaveMonumentsConfig(path);
}
_monumentsConfig = new MonumentConfig() {
Version = _monumentsVersion
}
;
}
if (_monumentsConfig.TrackedTypes == null) _monumentsConfig.TrackedTypes = new string[] {
"RadTown", "RadTownWater", "RadTownSmall", "TunnelStation", "Custom"
}
;
if (_monumentsConfig.IgnoredNames == null) _monumentsConfig.IgnoredNames = new string[] {
"example"
}
;
if (_monumentsConfig.MonumentsSettings == null) _monumentsConfig.MonumentsSettings = new Dictionary<string, MonumentSettings>();
else {
foreach (var monumentSettings in _monumentsConfig.MonumentsSettings.Values) monumentSettings.OfferTime = Math.Clamp(monumentSettings.OfferTime, 1f, 15f);
}
if (!_monumentsConfig.MonumentsSettings.ContainsKey("CargoShip")) _monumentsConfig.MonumentsSettings["CargoShip"] = new MonumentSettings("CargoShip", "RadTownWater");
if (uiList == null || !uiList.Any()) {
uiList = GetDefaultClaimOffer();
Interface.Oxide.DataFileSystem.WriteObject(_monumentsUiOfferPath, uiList);
}
_monumentsUiOffer = ReplacePlaceholders(CuiHelper.ToJson(uiList), MonumentOfferUI);
SaveMonumentsConfig();
}
object OnCupboardAuthorize(VehiclePrivilege privilege, BasePlayer player) {
object result = false;
if (GetVehicleData(privilege.GetParentEntity(), out var vehicleData) && vehicleData.OwnerID != 0) result = vehicleData.CanLoot(player);
if (result != null) SendMessage(player, "MsgVehicleTugboatAuthorization");
return result;
}
void OnEntitySpawned(BuildingPrivlidge privlidge) => privlidge.lastNoiseTime = DateTimeOffset.UtcNow.Day;
private HashSet<BaseEntity> GetMonumentEntities(string monumentID) => MonumentsWatcher?.Call(MonumentGetMonumentEntities, monumentID) as HashSet<BaseEntity>;
private const string RBUI = "RealPVE_RaidableBases", RBLootUI = "RealPVE_RaidableBases_Loot", RBOfferUI = "RealPVE_RaidableBasesOffer", RBTextLootRemaining = "MsgRaidableBasesBarTextLootRemaining", RBTextLootCompleted = "MsgRaidableBasesBarTextLootCompleted";
object CanDemolish(BasePlayer player, BuildingBlock block, BuildingGrade.Enum grade) => !block.OwnerID.IsSteamId() || IsEntityInPvP(player.userID, block.net.ID.Value) ? null : player.TasirMumkin(block.OwnerID);
void OnCargoWatcherCreated(string monumentID, string type) {
if (!_monumentsConfig.TrackedTypes.Contains(type) || _monumentsConfig.IgnoredNames.Contains("CargoShip")) return;
NextTick(() => {
if (IsMonumentCargoValid(monumentID)) _monumentsList[monumentID] = new MonumentData(monumentID, _monumentsConfig.MonumentsSettings["CargoShip"], true);
}
);
}
void OnPlayerDisconnected(BasePlayer player, string reason) {
_playerUI.Remove(player.userID);
if (_config.AntiSleeper > 0f && player.BinoMumkin() != null) player.Invoke(Str_ScheduledDeath, _config.AntiSleeper);
if (_monumentsList.TryGetValue(GetPlayerMonument(player.userID), out var monumentData)) monumentData.OnPlayerExit(player, "disconnect");
}
private void Command_Admin(IPlayer player, string command, string[] args) {
string replyKey = "CmdCommandFailed";
string[] replyArgs = new string[5];
bool isWarning = true;
if (args != null && args.Length > 0 && (player.IsAdmin || permission.UserHasPermission(player.Id, PERMISSION_ADMIN))) {
var bPlayer = player.Object as BasePlayer;
ulong targetID = bPlayer != null ? bPlayer.userID : 0uL;
if (args[0] == "loot") {
if (args.Length < 2) {
if (player.IsServer) replyKey = "CmdCommandForPlayers";
else if (_unrestrictedLooters.Remove(targetID)) replyKey = "CmdAdminLootDisabled";
else {
_unrestrictedLooters.Add(targetID);
replyKey = "CmdAdminLootEnabled";
isWarning = false;
}
}
else {
if (args[1] == "clear") {
replyArgs[0] = _unrestrictedLooters.Count.ToString();
_unrestrictedLooters.Clear();
SaveData(_dataLootersPath, _unrestrictedLooters);
replyKey = "CmdAdminLootClear";
isWarning = false;
}
else if (!TryGetPlayer(args[1], out var target) || !ulong.TryParse(target.Id, out targetID)) {
replyKey = "CmdAdminLootPlayerNotFound";
replyArgs[0] = args[1];
}
else {
replyArgs[0] = target.Name;
if (_unrestrictedLooters.Remove(targetID)) {
if (target.IsConnected) SendMessage(target, "CmdAdminLootDisabled");
replyKey = "CmdAdminLootPlayerDisabled";
}
else {
_unrestrictedLooters.Add(targetID);
if (target.IsConnected) SendMessage(target, "CmdAdminLootEnabled", isWarning : false);
replyKey = "CmdAdminLootPlayerEnabled";
isWarning = false;
}
}
}
}
else if (args[0] == "pickup") {
replyKey = "CmdAdminPickupFailed";
if (args.Length > 1 && args[1] == "clear") {
replyArgs[0] = _pickupPlayers.Count.ToString();
_pickupPlayers.Clear();
SaveData(_dataPickupsPath, _pickupPlayers);
replyKey = "CmdAdminPickupClear";
isWarning = false;
}
}
else if (args[0] == "monument") {
replyKey = "CmdAdminMonumentFailed";
if (args.Length < 2) {
}
else if (!_monumentsList.TryGetValue(args[^1], out var monumentData) && (!targetID.IsSteamId() || !_monumentsList.TryGetValue(GetPlayerMonument(targetID), out monumentData))) {
replyKey = "CmdAdminMonumentNotFound";
replyArgs[0] = args[^1];
}
else {
replyArgs[0] = GetMonumentName(monumentData.MonumentID, player.Id);
if (args[1] == "pvp") {
if (monumentData.OwnerID != targetID && monumentData.OwnerID.IsSteamId()) replyKey = "CmdAdminMonumentOcupied";
else {
if (monumentData.IsPvP) {
monumentData.RemovePvP();
replyKey = "CmdAdminMonumentPvPDisabled";
isWarning = false;
}
else {
monumentData.SetAsPvP();
replyKey = "CmdAdminMonumentPvPEnabled";
}
monumentData.Settings.IsPvP = monumentData.IsPvP;
SaveMonumentsConfig();
}
}
}
}
}
if (!string.IsNullOrWhiteSpace(replyKey)) SendMessage(player, replyKey, replyArgs, isWarning);
}
private void SendCounterBar(BasePlayer player, RBData rbData) {
if (!_statusIsLoaded) return;
string text = string.Format(lang.GetMessage("MsgRaidableBasesBarText", this, player.UserIDString), lang.GetMessage(rbData.TextKey, this, player.UserIDString));
Dictionary<int, object> parameters;
if (rbData.Settings.UseProgress) {
parameters = new Dictionary<int, object>(rbData.StatusProgressBar) {
{
15, text
}
, {
28, rbData.StartTime
}
, {
29, rbData.DespawnTime
}
}
;
}
else {
parameters = new Dictionary<int, object>(rbData.StatusBar) {
{
15, text
}
, {
29, rbData.DespawnTime
}
}
;
parameters[2] = BarTimeCounter;
}
AdvancedStatus?.Call(StatusCreateBar, player.userID.Get(), parameters);
}
void OnPlayerEnterPVP(BasePlayer player, string zoneID) {
if (!player.userID.IsSteamId()) return;
if (!_pvpPlayers.TryGetValue(player.userID, out var playerPvP)) _pvpPlayers[player.userID] = playerPvP = new PlayerPvP();
if (playerPvP.ActiveZones.Contains(zoneID)) return;
playerPvP.ActiveZones.Add(zoneID);
if (playerPvP.DelayEnd != 0d) {
playerPvP.DelayEnd = 0d;
Interface.CallHook(Hooks_OnPlayerPVPDelayRemoved, player);
}
if (player.IsConnected) {
if (!string.IsNullOrWhiteSpace(playerPvP.LastZone)) {
string lastBar;
if (_monumentsList.TryGetValue(playerPvP.LastZone, out var monumentData)) lastBar = (string)monumentData.StatusBar[0];
else if (_rbList.TryGetValue(playerPvP.LastZone, out var rbData)) lastBar = (string)rbData.StatusBar[0];
else lastBar = playerPvP.LastZone;
DestroyBar(player.userID, lastBar);
}
SendPvPBar(player, zoneID);
if (playerPvP.ActiveZones.Count == 1) {
player.SendEffect();
SendMessage(player, "MsgPvPEnter");
}
}
playerPvP.LastZone = zoneID;
}
private static HashSet<ulong> _unrestrictedLooters, _pickupPlayers;
public static Dictionary<ulong, RRData> _rrallPatrols = new Dictionary<ulong, RRData>();
private readonly VersionNumber _monumentsVersion = new VersionNumber(0, 1, 3);
object OnRackedWeaponSwap(Item item, WeaponRackSlot weaponAtIndex, BasePlayer player, WeaponRack rack) => CanLootWeaponRack(player, rack);
private void SaveMonumentsConfig(string path = _monumentsPath) => Interface.Oxide.DataFileSystem.WriteObject(path, _monumentsConfig);
void OnHarborEventEnd() {
if (_watcherIsLoaded && !string.IsNullOrWhiteSpace(_harborEventMonument) && !_monumentsConfig.IgnoredNames.Contains(_harborEventMonument) && _monumentsConfig.TrackedTypes.Contains(GetMonumentType(_harborEventMonument))) {
if (!_monumentsList.TryGetValue(_harborEventMonument, out var monumentData)) _monumentsList[_harborEventMonument] = new MonumentData(_harborEventMonument, _monumentsConfig.MonumentsSettings[_harborEventMonument]);
else monumentData.RemovePvP();
}
_harborEventMonument = string.Empty;
}
private object AdminOpenLoot(BasePlayer player, StorageContainer container) {
if (player.inventory.loot.StartLootingEntity(container, true)) {
container.SetFlag(BaseEntity.Flags.Open, b : true);
container.AddContainers(player.inventory.loot);
player.inventory.loot.SendImmediate();
player.ClientRPC(RpcTarget.Player("RPC_OpenLootPanel", player), container.panelName);
container.SendNetworkUpdate();
return true;
}
return null;
}
object CanLootEntity(BasePlayer player, BaseRidableAnimal animal) {
if (!IsEntityInPvP(player.userID, animal.net.ID.Value) && _vehiclesList.TryGetValue(animal.net.ID.Value, out var vehicleData)) {
object result = vehicleData.CanLoot(player);
if (result != null) SendMessage(player, "MsgVehicleCanNotInteract");
return result;
}
return null;
}
object OnEntityTakeDamage(Tugboat tugboat, HitInfo info) => CanVehicleTakeDamage(tugboat.net?.ID.Value ?? 0uL, info);
object OnEntityTakeDamage(Minicopter minicopter, HitInfo info) => CanVehicleTakeDamage(minicopter.net?.ID.Value ?? 0uL, info);
object OnZoneStatusText(BasePlayer player, string zoneID) {
switch (zoneID) {
case "SurvivalArena" : return lang.GetMessage("MsgSurvivalArena", this, player.UserIDString);
default : return null;
}
}
private readonly string[] HttpScheme = new string[2] {
"http://", "https://"
}
;
private string _monumentsUiOffer;
private static double _unixSeconds = 0d;
void OnRaidableLootDestroyed(Vector3 pos, float radius, int lootRemain) {
if (_rbList.TryGetValue(pos.ToString(), out var rbData)) rbData.OnLootUpdated(lootRemain);
}
bool CanBypassQueue(Network.Connection connection) => ServerUsers.Is(connection.userid, ServerUsers.UserGroup.Owner) ? true : CanPlayerBypassQueue(connection.userid.ToString());
private void RaidableBaseTimeUpdatedBar(BasePlayer player, RBData rbData) {
if (!_statusIsLoaded) return;
var parameters = new Dictionary<int, object> {
{
0, rbData.RaidID
}
, {
1, Name
}
, {
29, rbData.DespawnTime
}
}
;
AdvancedStatus?.Call(StatusCreateBar, player.userID.Get(), parameters);
}
object OnButtonPress(PressButton button, BasePlayer player) {
if (_unrestrictedLooters.Contains(player.userID)) return null;
object result = player.MumkinNol(button.OwnerID);
if (result != null) SendMessage(player, "MsgCantInteract");
return result;
}
object OnHotAirBalloonToggle(HotAirBalloon balloon, BasePlayer driver) {
if (!IsEntityInPvP(driver.userID, balloon.net.ID.Value) && _vehiclesList.TryGetValue(balloon.net.ID.Value, out var vehicleData)) {
object result = vehicleData.CanInteract(driver);
if (result != null) SendMessage(driver, "MsgVehicleCanNotInteract");
return result;
}
return null;
}
private void SaveVanillaEventsConfig(string path = _vanillaEventsPath) => Interface.Oxide.DataFileSystem.WriteObject(path, _vanillaEventsConfig);
object CanBeTargeted(BasePlayer player, HelicopterTurret turret) {
if (!player.userID.IsSteamId()) return null;
var patrolHeli = turret._heliAI?.helicopterBase;
if (patrolHeli != null && patrolHeli.net != null) {
if (patrolHeli.skinID == _rrPluginID) {
if (_config.RandomRaids_Enabled && _rrallPatrols.TryGetValue(patrolHeli.net.ID.Value, out var rrData) && !rrData.PlayersList.Contains(player.userID)) return false;
}
else if (_eventsList.TryGetValue(patrolHeli.net.ID.Value, out var patrolData)) {
if (patrolData.CanBeTargeted(player) != null) return false;
}
}
return null;
}
private void ShowEventOffer(BasePlayer player, EventData eventData) {
DestroyUI(player, EventOfferUI);
player.SendEffect();
CuiHelper.AddUi(player, ReplacePlaceholders(_vanillaEventsUiOffer, null, (string)ImageLibrary?.Call("GetImage", EventOfferUI), string.Format(lang.GetMessage("MsgEventOfferTitle", this, player.UserIDString), new string[] {
lang.GetMessage($"MsgEvent{eventData.Type}", this, player.UserIDString)
}
), string.Format(lang.GetMessage("MsgEventOfferDescription", this, player.UserIDString), new string[] {
string.Format(_config.PriceFormat, eventData.Settings.Price.ToString())
}
), $"{_commandUI} event pay {eventData.ID}"));
_playerUI[player.userID].Add(EventOfferUI);
}
private class Configuration {
[JsonProperty(PropertyName = "Chat admin command")]
public string AdminCommand = "adminpve";
[JsonProperty(PropertyName = "Chat command")]
public string Command = "realpve";
[JsonProperty(PropertyName = "Is it worth forcibly implementing PvE for a server?")]
public bool Force_PvE = true;
[JsonProperty(PropertyName = "Is it worth enabling GameTips for messages?")]
public bool GameTips_Enabled = true;
[JsonProperty(PropertyName = "Is it worth preventing the sending of 'Give' messages?")]
public bool PreventGiveMessage = true;
[JsonProperty(PropertyName = "Is it worth preventing resource gathering in someone else's building privilege area?")]
public bool PreventResourceGathering = false;
[JsonProperty(PropertyName = "Is it worth preventing the pickup of plants spawned by the server in someone else's building privilege zone?")]
public bool PreventPickUpCollectibleEntity = false;
[JsonProperty(PropertyName = "Is it worth assigning portals(Halloween and Christmas) to the first player?")]
public bool AssignPortals = true;
[JsonProperty(PropertyName = "Is it worth preventing players from handcuffing others?")]
public bool PreventHandcuffing = true;
[JsonProperty(PropertyName = "Is it worth preventing a backpack from dropping upon player death?")]
public bool PreventBackpackDrop = true;
[JsonProperty(PropertyName = "Is it worth preventing damage to the laptop of the Hackable Crate?")]
public bool PreventLaptopAttack = true;
[JsonProperty(PropertyName = "Is it worth removing the penalties for recyclers in safe zones?")]
public bool RecyclerNoPenalties = true;
[JsonProperty(PropertyName = "Which currency symbol and format will be utilized?")]
public string PriceFormat = "${0}";
[JsonProperty(PropertyName = "Vehicles - Time(in seconds) to display the marker when searching for a vehicle.A value of 0 disables the marker")]
public float VehiclesMarkerTime = 15f;
[JsonProperty(PropertyName = "Anti-Sleeper - Time in seconds after which a player will be killed if they disconnect while inside someone else's Building Privilege.Set to 0 to disable")]
public float AntiSleeper = 1200f;
[JsonProperty(PropertyName = "PatrolHelicopterAI - Monument Crash.If set to true, the helicopter will attempt to crash into the monument")]
public bool PatrolHelicopterAI_MonumentCrash = false;
[JsonProperty(PropertyName = "PatrolHelicopterAI - Use Danger Zones.If set to false, the helicopter will function as it did before the April update")]
public bool PatrolHelicopterAI_UseDangerZones = false;
[JsonProperty(PropertyName = "PatrolHelicopterAI - Flee Damage Percentage.A value of 1 or above will make the helicopter behave as it did before the April update")]
public float PatrolHelicopterAI_FleeDamagePercentage = 1f;
[JsonProperty(PropertyName = "Is Npc Random Raids enabled?")]
public bool RandomRaids_Enabled = true;
[JsonProperty(PropertyName = "PvP - Is friendly fire enabled by default when creating a team?")]
public bool PvPTeamFF = false;
[JsonProperty(PropertyName = "PvP - Is it worth adding map markers for PvP zones?")]
public bool PvPMapMarkers = true;
[JsonProperty(PropertyName = "PvP - Name of the map maker")]
public string PvPMapMarkersName = "PvP Zone!";
[JsonProperty(PropertyName = "PvP - Settings for the status bar")]
public BarSettings BarPvP = null;
[JsonProperty(PropertyName = "PvP - Settings for the progress status bar")]
public ProgressBarSettings ProgressBarPvP = null;
[JsonProperty(PropertyName = "Wipe ID")]
public string WipeID = "";
public Oxide.Core.VersionNumber Version;
}
void OnFriendAdded(string userID, string friendID) => OnFriendUpdated(userID, friendID);
private int _defaultBeds = 15, _defaultShelters = 1, _defaultTurrets = 12;
private bool GetLookEntity(BasePlayer player, out BaseEntity entity, float maxDistance = 10f) {
entity = null;
if (Physics.Raycast(player.eyes.HeadRay(), out RaycastHit hit, maxDistance, Physics.DefaultRaycastLayers, QueryTriggerInteraction.Ignore)) entity = hit.GetEntity();
return entity != null;
}
object CanAdministerVending(BasePlayer player, VendingMachine machine) => _unrestrictedLooters.Contains(player.userID) ? true : (!machine.OwnerID.IsSteamId() || IsEntityInPvP(player.userID, machine.net.ID.Value) ? null : player.TasirMumkin(machine.OwnerID));
object CanLootEntity(BasePlayer player, BoxStorage storage) => CanLootStorage(player, storage);
private void UpdatePvPBars() {
if (_pvpBar == null) return;
_pvpBar.Remove(10);
_pvpBar.Remove(9);
_pvpBar.Remove(8);
if (!string.IsNullOrWhiteSpace(_config.BarPvP.Image_Sprite)) _pvpBar.Add(10, _config.BarPvP.Image_Sprite);
else if (!string.IsNullOrWhiteSpace(_config.BarPvP.Image_Local)) _pvpBar.Add(9, _config.BarPvP.Image_Local);
else _pvpBar.Add(8, _imgLibIsLoaded && _config.BarPvP.Image_Url.StartsWithAny(HttpScheme) ? Bar_PvP : _config.BarPvP.Image_Url);
if (_pvpDelayBar != null) _pvpDelayBar.Clear();
var progressBar = _config.ProgressBarPvP;
_pvpDelayBar = new Dictionary<int, object>(_pvpBar) {
{
32, progressBar.Progress_Reverse
}
, {
33, progressBar.Progress_Color
}
, {
-33, progressBar.Progress_Transparency
}
, {
34, progressBar.Progress_OffsetMin
}
, {
35, progressBar.Progress_OffsetMax
}
}
;
_pvpDelayBar[2] = "TimeProgressCounter";
_pvpDelayBar[6] = progressBar.Main_Color;
if (progressBar.Main_Color.StartsWith("#")) _pvpDelayBar[-6] = progressBar.Main_Transparency;
else _pvpDelayBar.Remove(-6);
}
private const ulong _bradleySkinId = 3074297551uL;
private void LoadMonumentsImages() {
if (_statusIsLoaded) {
var imgList = new HashSet<string>();
foreach (var monumentSettings in _monumentsConfig.MonumentsSettings.Values) {
if (!string.IsNullOrWhiteSpace(monumentSettings.Bar.Image_Local)) imgList.Add(monumentSettings.Bar.Image_Local);
}
if (imgList.Any()) AdvancedStatus?.Call("LoadImages", imgList);
}
if (_imgLibIsLoaded) {
var imgList = new Dictionary<string, string>();
BarSettings barSettings;
foreach (var kvp in _monumentsConfig.MonumentsSettings) {
barSettings = kvp.Value.Bar;
if (string.IsNullOrWhiteSpace(barSettings.Image_Sprite) && string.IsNullOrWhiteSpace(barSettings.Image_Local) && barSettings.Image_Url.StartsWithAny(HttpScheme)) imgList.Add($"{StatusBarID}{kvp.Key}", barSettings.Image_Url);
}
if (imgList.Any()) ImageLibrary?.Call("ImportImageList", Name, imgList, 0uL, true);
}
}
object CanLootEntity(BasePlayer player, ModularCarGarage garage) {
if (garage.carOccupant == null) {
SendMessage(player, "MsgVehicleCarGarageEmpty");
return false;
}
return null;
}
object OnEntityTakeDamage(VehicleModuleCamper module, HitInfo info) => CanModuleTakeDamage(module, info);
void OnPluginUnloaded(Plugin plugin) {
if (plugin.Name == "ImageLibrary") {
_imgLibIsLoaded = false;
foreach (var monumentData in _monumentsList.Values) monumentData.UpdateBars();
UpdatePvPBars();
foreach (var rbData in _rbList.Values) rbData.UpdateBars();
}
else if (plugin.Name == "Economics") _economicsIsLoaded = false;
else if (plugin.Name == "AdvancedStatus") _statusIsLoaded = false;
else if (plugin.Name == "MonumentsWatcher") {
_watcherIsLoaded = false;
Unsubscribe(nameof(OnEntityEnteredMonument));
Unsubscribe(nameof(OnEntityExitedMonument));
Unsubscribe(nameof(OnPlayerEnteredMonument));
Unsubscribe(nameof(OnPlayerExitedMonument));
Unsubscribe(nameof(OnCargoWatcherCreated));
Unsubscribe(nameof(OnCargoWatcherDeleted));
Unsubscribe(nameof(OnCargoShipHarborArrived));
Unsubscribe(nameof(OnCargoShipHarborLeave));
Unsubscribe(nameof(OnHarborEventStart));
Unsubscribe(nameof(OnHarborEventEnd));
Unsubscribe(nameof(OnExcavatorResourceSet));
Unsubscribe(nameof(OnExcavatorSuppliesRequest));
Unsubscribe(nameof(OnExcavatorSuppliesRequested));
Unsubscribe(nameof(CanHackCrate));
foreach (var monumentData in _monumentsList.Values) monumentData.Destroy();
_monumentsList.Clear();
if (_statusIsLoaded) DestroyAllBars();
_harborEventMonument = string.Empty;
}
else if (plugin.Name == "HarborEvent") {
NextTick(() => {
if (!string.IsNullOrWhiteSpace(_harborEventMonument)) OnHarborEventEnd();
}
);
}
else if (plugin.Name == "RaidableBases") {
Unsubscribe(nameof(OnPlayerEnteredRaidableBase));
Unsubscribe(nameof(OnPlayerExitedRaidableBase));
Unsubscribe(nameof(OnRaidableLootDestroyed));
Unsubscribe(nameof(OnRaidableDespawnUpdate));
Unsubscribe(nameof(OnRaidableBasePurchased));
Unsubscribe(nameof(OnRaidableBaseStarted));
Unsubscribe(nameof(OnRaidableBaseEnded));
foreach (var rbData in _rbList.Values.ToList()) rbData.Destroy();
}
else if (plugin.Name == "RandomRaids") {
Unsubscribe(nameof(OnRandomRaidStart));
Unsubscribe(nameof(RandomRaidEventEnd));
Unsubscribe(nameof(OnRandomRaidRaiderSpawned));
Unsubscribe(nameof(OnRandomRaidHeliSpawned));
Unsubscribe(nameof(OnRandomRaidWin));
Unsubscribe(nameof(OnBuildingSplit));
}
else if (plugin.Name == "DynamicPVP") {
Unsubscribe(nameof(OnEntityEnterZone));
Unsubscribe(nameof(OnEntityExitZone));
Unsubscribe(nameof(OnCreateDynamicPVP));
Unsubscribe(nameof(OnCreatedDynamicPVP));
Unsubscribe(nameof(OnDeletedDynamicPVP));
}
}
private float GetEventPriceMultiplier(string userID) {
float result = float.MaxValue;
foreach (var perm in _permissionsConfig.PermissionsList) {
if (perm.Event_Multiplier < result && permission.UserHasPermission(userID, perm.Name)) result = perm.Event_Multiplier;
}
return result == float.MaxValue ? _permissionsConfig.PermissionsList[0].Event_Multiplier : result;
}
private const string _monumentsPath = @"RealPVE\MonumentsConfig";
void OnPlayerRespawned(BasePlayer player) {
if (_respawnMessage.TryGetValue(player.userID, out var msg)) {
if (_config.GameTips_Enabled) player.SendConsoleCommand("gametip.showtoast", (int)GameTip.Styles.Blue_Long, msg, string.Empty);
else player.ChatMessage(msg);
_respawnMessage.Remove(player.userID);
}
}
void OnEntityKill(ScientistNPC scientist) {
if (scientist.skinID == _bradleySkinId) _eventScientistsList.Remove(scientist.net.ID);
}
object OnStructureRotate(BaseCombatEntity entity, BasePlayer player) => !entity.OwnerID.IsSteamId() || IsEntityInPvP(player.userID, entity.net.ID.Value) ? null : player.TasirMumkin(entity.OwnerID);
private Dictionary<string, HashSet<string>> _pvpChangedMonuments = new Dictionary<string, HashSet<string>>();
private readonly VersionNumber _permissionsVersion = new VersionNumber(0, 1, 1);
private const string _vanillaEventsPath = @"RealPVE\VanillaEventsConfig";
private CuiElementContainer GetVehicleCarPanel(string userID, VehicleData vehicleData) {
string description, descriptionValue;
bool notOwner = vehicleData.OwnerID != 0uL && !vehicleData.IsOwner(userID);
var container = new CuiElementContainer();
container.Add(new CuiPanel {
RectTransform = {
AnchorMin = "0.5 0", AnchorMax = "0.5 0", OffsetMin = "385 110", OffsetMax = "573 200"
}
, Image = {
Color = "0.35 0.35 0.35 1", Material = "assets/content/ui/ui.background.tiletex.psd"
}
}
, "Overlay", _uiVehiclePanel);
if (notOwner) {
container.Add(new CuiElement {
Parent = _uiVehiclePanel, Components = {
new CuiImageComponent {
Color = "0 0 0 0"
}
, new CuiRectTransformComponent {
AnchorMin = "1 1", AnchorMax = "1 1", OffsetMin = "-382 230", OffsetMax = "2 381"
}
}
}
);
}
container.Add(new CuiElement {
Parent = _uiVehiclePanel, Components = {
new CuiImageComponent {
Color = "0 0 0 0"
}
, new CuiRectTransformComponent {
AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = "-50 0", OffsetMax = "0 0"
}
}
}
);
string[] values = new string[5];
values[0] = vehicleData.ID.ToString();
values[1] = lang.GetMessage($"MsgVehicle{vehicleData.Type}", this, userID).FirstToUpper();
values[2] = lang.GetMessage($"MsgVehicle{vehicleData.Category}", this, userID);
values[3] = !string.IsNullOrWhiteSpace(vehicleData.RegistrationDate) ? $"{vehicleData.RegistrationDate}(UTC)" : lang.GetMessage("MsgNoDate", this, userID);
if (notOwner) {
var owner = BasePlayer.FindByID(vehicleData.OwnerID);
values[4] = owner != null ? owner.displayName : vehicleData.OwnerID.ToString();
description = lang.GetMessage("MsgVehicleCarDialogDescriptionNotOwner", this, userID);
descriptionValue = string.Format(lang.GetMessage("MsgVehicleCarDialogDescriptionNotOwnerValue", this, userID), values);
}
else if (vehicleData.OwnerID == 0uL) {
if (_economicsIsLoaded) {
var perm = GetVehiclePricePermission(userID, vehicleData.Type);
values[4] = $"{string.Format(_config.PriceFormat, $" {
perm?.Allowed_Vehicles[vehicleData.Type].Price ?? 0
}
")}({string.Format(_config.PriceFormat, $" {
Economics?.Call("Balance", userID) ?? 0
}
")})";
}
else values[4] = lang.GetMessage("MsgFree", this, userID);
description = lang.GetMessage("MsgVehicleCarDialogDescription", this, userID);
descriptionValue = string.Format(lang.GetMessage("MsgVehicleCarDialogDescriptionValue", this, userID), values);
}
else {
description = lang.GetMessage("MsgVehicleCarDialogDescriptionRegistered", this, userID);
descriptionValue = string.Format(lang.GetMessage("MsgVehicleCarDialogDescriptionRegisteredValue", this, userID), values);
}
container.Add(new CuiLabel {
Text = {
Text = lang.GetMessage("MsgVehicleDialogTitle", this, userID), FontSize = 12, Color = WhiteColor, Align = TextAnchor.MiddleCenter
}
, RectTransform = {
AnchorMin = "0 0", AnchorMax = "1 0", OffsetMin = "5 75", OffsetMax = "-5 92"
}
}
, _uiVehiclePanel);
container.Add(new CuiElement {
Name = "Description", Parent = _uiVehiclePanel, Components = {
new CuiImageComponent {
Color = "0 0 0 0"
}
, new CuiRectTransformComponent {
AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = $"5 {(notOwner ? "5" : "25")}", OffsetMax = "-5 -20"
}
, new CuiScrollViewComponent {
ContentTransform = new CuiRectTransform {
AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = $"0 -{(11 * description.Split('\n').Length * 1.2) - (notOwner ? 67 : 47)}", OffsetMax = "0 0"
}
, Vertical = true, MovementType = ScrollRect.MovementType.Elastic, ScrollSensitivity = 20f, HorizontalScrollbar = null, VerticalScrollbar = null
}
}
}
);
container.Add(new CuiLabel {
Text = {
Text = description, Font = "RobotoCondensed-Regular.ttf", FontSize = 11, Color = WhiteColor, Align = TextAnchor.MiddleLeft
}
, RectTransform = {
AnchorMin = "0 0", AnchorMax = "1 1", OffsetMin = "5 0", OffsetMax = "0 0"
}
}
, "Description");
container.Add(new CuiLabel {
Text = {
Text = descriptionValue, Font = "RobotoCondensed-Regular.ttf", FontSize = 11, Color = WhiteColor, Align = TextAnch
// ... [Code preview truncated due to length. Full source in attached file] ...