C#:
// Все права принадлежат дискорд сообществу https://discord.gg/VgNHPpNrz6
// #define DEBUG
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Facepunch;
using Network;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;
using Oxide.Core;
using Oxide.Core.Plugins;
using Oxide.Game.Rust;
using Rust;
using Rust.Modular;
using UnityEngine;
using Debug = UnityEngine.Debug;
using Random = UnityEngine.Random;
namespace Oxide.Plugins {
[Info("Vehicle Licence", "Sorrow/TheDoc/Arainrr", "1.7.48")]
[Description("Allows players to buy vehicles and then spawn or store it")]
public class VehicleLicence : RustPlugin {
#region Fields
[PluginReference]
private readonly Plugin Economics, ServerRewards, Friends, Clans, NoEscape, LandOnCargoShip, RustTranslationAPI, ZoneManager;
private const string PERMISSION_USE = "vehiclelicence.use";
private const string PERMISSION_ALL = "vehiclelicence.all";
private const string PERMISSION_ADMIN = "vehiclelicence.admin";
private const string PERMISSION_BYPASS_COST = "vehiclelicence.bypasscost";
private const int ITEMID_FUEL = -946369541;
private const string PREFAB_ITEM_DROP = "assets/prefabs/misc/item drop/item_drop.prefab";
private const string PREFAB_TUGBOAT = "assets/content/vehicles/boats/tugboat/tugboat.prefab";
private const string PREFAB_ROWBOAT = "assets/content/vehicles/boats/rowboat/rowboat.prefab";
private const string PREFAB_RHIB = "assets/content/vehicles/boats/rhib/rhib.prefab";
private const string PREFAB_SEDAN = "assets/content/vehicles/sedan_a/sedantest.entity.prefab";
private const string PREFAB_HOTAIRBALLOON = "assets/prefabs/deployable/hot air balloon/hotairballoon.prefab";
private const string PREFAB_MINICOPTER = "assets/content/vehicles/minicopter/minicopter.entity.prefab";
private const string PREFAB_TRANSPORTCOPTER = "assets/content/vehicles/scrap heli carrier/scraptransporthelicopter.prefab";
private const string PREFAB_CHINOOK = "assets/prefabs/npc/ch47/ch47.entity.prefab";
private const string PREFAB_RIDABLEHORSE = "assets/rust.ai/nextai/testridablehorse.prefab";
private const string PREFAB_WORKCART = "assets/content/vehicles/trains/workcart/workcart.entity.prefab";
private const string PREFAB_SEDANRAIL = "assets/content/vehicles/sedan_a/sedanrail.entity.prefab";
private const string PREFAB_MAGNET_CRANE = "assets/content/vehicles/crane_magnet/magnetcrane.entity.prefab";
private const string PREFAB_SUBMARINE_DUO = "assets/content/vehicles/submarine/submarineduo.entity.prefab";
private const string PREFAB_SUBMARINE_SOLO = "assets/content/vehicles/submarine/submarinesolo.entity.prefab";
private const string PREFAB_CHASSIS_SMALL = "assets/content/vehicles/modularcar/car_chassis_2module.entity.prefab";
private const string PREFAB_CHASSIS_MEDIUM = "assets/content/vehicles/modularcar/car_chassis_3module.entity.prefab";
private const string PREFAB_CHASSIS_LARGE = "assets/content/vehicles/modularcar/car_chassis_4module.entity.prefab";
private const string PREFAB_SNOWMOBILE = "assets/content/vehicles/snowmobiles/snowmobile.prefab";
private const string PREFAB_SNOWMOBILE_TOMAHA = "assets/content/vehicles/snowmobiles/tomahasnowmobile.prefab";
// Train Engine
private const string PREFAB_TRAINENGINE = "assets/content/vehicles/trains/workcart/workcart_aboveground.entity.prefab";
private const string PREFAB_TRAINENGINE_COVERED = "assets/content/vehicles/trains/workcart/workcart_aboveground2.entity.prefab";
private const string PREFAB_TRAINENGINE_LOCOMOTIVE = "assets/content/vehicles/trains/locomotive/locomotive.entity.prefab";
// Train Car
private const string PREFAB_TRAINWAGON_A = "assets/content/vehicles/trains/wagons/trainwagona.entity.prefab";
private const string PREFAB_TRAINWAGON_B = "assets/content/vehicles/trains/wagons/trainwagonb.entity.prefab";
private const string PREFAB_TRAINWAGON_C = "assets/content/vehicles/trains/wagons/trainwagonc.entity.prefab";
private const string PREFAB_TRAINWAGON_UNLOADABLE = "assets/content/vehicles/trains/wagons/trainwagonunloadable.entity.prefab";
private const string PREFAB_TRAINWAGON_UNLOADABLE_FUEL = "assets/content/vehicles/trains/wagons/trainwagonunloadablefuel.entity.prefab";
private const string PREFAB_TRAINWAGON_UNLOADABLE_LOOT = "assets/content/vehicles/trains/wagons/trainwagonunloadableloot.entity.prefab";
private const string PREFAB_CABOOSE = "assets/content/vehicles/trains/caboose/traincaboose.entity.prefab";
// Defaults for Vehicle Modifications
private readonly float TUGBOAT_ENGINETHRUST = 200000f;
private readonly float HELICOPTER_LIFT = 0.25f;
private readonly Vector3 SCRAP_HELICOPTER_TORQUE = new Vector3(8000.0f, 8000.0f, 4000.0f);
private readonly Vector3 MINICOPTER_TORQUE = new Vector3(400.0f, 400.0f, 200.0f);
private const int LAYER_GROUND = Layers.Solid | Layers.Mask.Water;
private readonly object _false = false;
private bool finishedLoading = false;
public static VehicleLicence Instance {
get;
private set;
}
public readonly Dictionary<BaseEntity, Vehicle> vehiclesCache = new Dictionary<BaseEntity, Vehicle>();
public readonly Dictionary<string, BaseVehicleSettings> allVehicleSettings = new Dictionary<string, BaseVehicleSettings>();
public readonly Dictionary<string, string> commandToVehicleType = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
public enum NormalVehicleType {
Tugboat, Rowboat, RHIB, Sedan, HotAirBalloon, MiniCopter, TransportHelicopter, Chinook, RidableHorse, WorkCart, SedanRail, MagnetCrane, SubmarineSolo, SubmarineDuo, Snowmobile, TomahaSnowmobile
}
[JsonConverter(typeof(StringEnumConverter))]
public enum ChassisType {
Small, Medium, Large
}
[JsonConverter(typeof(StringEnumConverter))]
public enum TrainComponentType {
Engine, CoveredEngine, Locomotive, WagonA, WagonB, WagonC, Unloadable, UnloadableLoot, UnloadableFuel, Caboose,
}
#endregion Fields
#region Oxide Hooks
private void Init() {
LoadData();
Instance = this;
permission.RegisterPermission(PERMISSION_USE, this);
permission.RegisterPermission(PERMISSION_ALL, this);
permission.RegisterPermission(PERMISSION_ADMIN, this);
permission.RegisterPermission(PERMISSION_BYPASS_COST, this);
foreach (NormalVehicleType value in Enum.GetValues(typeof(NormalVehicleType))) {
allVehicleSettings.Add(value.ToString(), GetBaseVehicleSettings(value));
}
foreach (var entry in configData.modularVehicles) {
allVehicleSettings.Add(entry.Key, entry.Value);
}
foreach (var entry in configData.trainVehicles) {
allVehicleSettings.Add(entry.Key, entry.Value);
}
foreach (var entry in allVehicleSettings) {
var settings = entry.Value;
if (settings.UsePermission && !string.IsNullOrEmpty(settings.Permission)) {
if (!permission.PermissionExists(settings.Permission, this)) {
permission.RegisterPermission(settings.Permission, this);
}
}
foreach (var perm in settings.CooldownPermissions.Keys) {
if (!permission.PermissionExists(perm, this)) {
permission.RegisterPermission(perm, this);
}
}
foreach (var command in settings.Commands) {
if (string.IsNullOrEmpty(command)) {
continue;
}
if (!commandToVehicleType.ContainsKey(command)) {
commandToVehicleType.Add(command, entry.Key);
}
else {
PrintError($"You have the same two commands({command}).");
}
if (configData.chat.useUniversalCommand) {
cmd.AddChatCommand(command, this, nameof(CmdUniversal));
}
if (!string.IsNullOrEmpty(configData.chat.customKillCommandPrefix)) {
cmd.AddChatCommand(configData.chat.customKillCommandPrefix + command, this, nameof(CmdCustomKill));
}
}
}
cmd.AddChatCommand(configData.chat.helpCommand, this, nameof(CmdLicenseHelp));
cmd.AddChatCommand(configData.chat.buyCommand, this, nameof(CmdBuyVehicle));
cmd.AddChatCommand(configData.chat.spawnCommand, this, nameof(CmdSpawnVehicle));
cmd.AddChatCommand(configData.chat.recallCommand, this, nameof(CmdRecallVehicle));
cmd.AddChatCommand(configData.chat.killCommand, this, nameof(CmdKillVehicle));
Unsubscribe(nameof(CanMountEntity));
Unsubscribe(nameof(OnEntityTakeDamage));
Unsubscribe(nameof(OnEntityDismounted));
Unsubscribe(nameof(OnEntityEnter));
Unsubscribe(nameof(CanLootEntity));
Unsubscribe(nameof(OnEntitySpawned));
Unsubscribe(nameof(OnRidableAnimalClaimed));
Unsubscribe(nameof(OnEngineStarted));
}
private void OnServerInitialized() {
ServerMgr.Instance.StartCoroutine(UpdatePlayerData(TimeEx.currentTimestamp));
if (configData.global.preventMounting) {
Subscribe(nameof(CanMountEntity));
}
if (configData.global.noDecay) {
Subscribe(nameof(OnEntityTakeDamage));
}
if (configData.global.preventDamagePlayer) {
Subscribe(nameof(OnEntityEnter));
}
if (configData.global.preventLooting) {
Subscribe(nameof(CanLootEntity));
}
if (configData.global.autoClaimFromVendor) {
Subscribe(nameof(OnEntitySpawned));
Subscribe(nameof(OnRidableAnimalClaimed));
}
if (configData.global.checkVehiclesInterval > 0 && allVehicleSettings.Any(x => x.Value.WipeTime > 0)) {
Subscribe(nameof(OnEntityDismounted));
timer.Every(configData.global.checkVehiclesInterval, CheckVehicles);
}
if(configData.global.InstantMiniTakeoff) {
Subscribe(nameof(OnEngineStarted));
}
}
private void Unload() {
if (!configData.global.storeVehicle) {
foreach (var entry in vehiclesCache.ToArray()) {
if (entry.Key != null && !entry.Key.IsDestroyed) {
RefundVehicleItems(entry.Value, isUnload : true);
entry.Key.Kill(BaseNetworkable.DestroyMode.Gib);
}
entry.Value.EntityId = 0;
}
}
SaveData();
Instance = null;
}
private void OnServerSave() {
timer.Once(Random.Range(0f, 60f), SaveData);
}
private void OnEntityDismounted(BaseMountable entity, BasePlayer player) {
if (entity == null) {
return;
}
if (player != null && configData.normalVehicles.miniCopter.flyHackPause > 0 && entity.GetParentEntity() is MiniCopter) {
player.PauseFlyHackDetection(configData.normalVehicles.miniCopter.flyHackPause);
}
else if (player != null && configData.normalVehicles.transportHelicopter.flyHackPause > 0 && entity.GetParentEntity() is ScrapTransportHelicopter) {
player.PauseFlyHackDetection(configData.normalVehicles.transportHelicopter.flyHackPause);
}
var vehicleParent = entity.VehicleParent();
if (vehicleParent == null || vehicleParent.IsDestroyed) {
return;
}
Vehicle vehicle;
if (!vehiclesCache.TryGetValue(vehicleParent, out vehicle)) {
return;
}
vehicle.OnDismount();
}
private void OnEngineStarted(BaseMountable entity, BasePlayer player) {
if (!permission.UserHasPermission(player.UserIDString, PERMISSION_USE)) return;
if (player.GetMountedVehicle() as MiniCopter != null && player.GetMountedVehicle() as ScrapTransportHelicopter == null) {
(player.GetMountedVehicle() as MiniCopter).engineController.FinishStartingEngine();
}
}
#region Mount
private object CanMountEntity(BasePlayer friend, BaseMountable entity) {
if (friend == null || entity == null) {
return null;
}
var vehicleParent = entity.VehicleParent();
if (vehicleParent == null || vehicleParent.IsDestroyed) {
return null;
}
Vehicle vehicle;
if (!vehiclesCache.TryGetValue(vehicleParent, out vehicle)) {
return null;
}
if (AreFriends(vehicle.PlayerId, friend.userID)) {
return null;
}
if (configData.global.preventDriverSeat && vehicleParent.HasMountPoints()) {
foreach (var mountPointInfo in vehicleParent.allMountPoints) {
if (mountPointInfo != null && mountPointInfo.mountable == entity) {
if (!mountPointInfo.isDriver) {
return null;
}
break;
}
}
}
if (HasAdminPermission(friend)) {
return null;
}
SendCantUseMessage(friend, vehicle);
return _false;
}
#endregion Mount
#region Loot
private object CanLootEntity(BasePlayer friend, RidableHorse horse) {
if (friend == null || horse == null) {
return null;
}
return CanLootEntityInternal(friend, horse);
}
private object CanLootEntity(BasePlayer friend, StorageContainer container) {
if (friend == null || container == null) {
return null;
}
var parentEntity = container.GetParentEntity();
if (parentEntity == null) {
return null;
}
return CanLootEntityInternal(friend, parentEntity);
}
private object CanLootEntityInternal(BasePlayer friend, BaseEntity parentEntity) {
Vehicle vehicle;
if (!TryGetVehicle(parentEntity, out vehicle)) {
return null;
}
if (AreFriends(vehicle.PlayerId, friend.userID)) {
return null;
}
if (HasAdminPermission(friend)) {
return null;
}
SendCantUseMessage(friend, vehicle);
return _false;
}
#endregion Loot
#region Decay
private void OnEntityTakeDamage(BaseCombatEntity entity, HitInfo hitInfo) {
if (entity == null || hitInfo?.damageTypes == null) {
return;
}
if (hitInfo.damageTypes.Has(DamageType.Decay)) {
Vehicle vehicle;
if (!TryGetVehicle(entity, out vehicle)) {
return;
}
hitInfo.damageTypes.Scale(DamageType.Decay, 0);
}
}
#endregion Decay
#region Claim
private void OnEntitySpawned(Tugboat tugboat) {
TryClaimVehicle(tugboat);
}
private void OnEntitySpawned(BaseSubmarine baseSubmarine) {
TryClaimVehicle(baseSubmarine);
}
private void OnEntitySpawned(MotorRowboat motorRowboat) {
TryClaimVehicle(motorRowboat);
}
private void OnEntitySpawned(MiniCopter miniCopter) {
TryClaimVehicle(miniCopter);
}
private void OnRidableAnimalClaimed(BaseRidableAnimal ridableAnimal, BasePlayer player) {
TryClaimVehicle(ridableAnimal, player);
}
#endregion Claim
#region Damage
// ScrapTransportHelicopter / ModularCar / TrainEngine / MagnetCrane
private object OnEntityEnter(TriggerHurtNotChild triggerHurtNotChild, BasePlayer player) {
if (triggerHurtNotChild == null || player == null || triggerHurtNotChild.SourceEntity == null) {
return null;
}
var sourceEntity = triggerHurtNotChild.SourceEntity;
if (vehiclesCache.ContainsKey(sourceEntity)) {
var baseVehicle = sourceEntity as BaseVehicle;
if (baseVehicle != null && player.userID.IsSteamId()) {
if (baseVehicle is TrainEngine) {
var transform = triggerHurtNotChild.transform;
MoveToPosition(player, transform.position + (Random.value >= 0.5f ? -transform.right : transform.right) * 2.5f);
return _false;
}
Vector3 pos;
if (GetDismountPosition(baseVehicle, player, out pos)) {
MoveToPosition(player, pos);
}
}
//triggerHurtNotChild.enabled = false;
return _false;
}
return null;
}
// HotAirBalloon
private object OnEntityEnter(TriggerHurt triggerHurt, BasePlayer player) {
if (triggerHurt == null || player == null) {
return null;
}
var sourceEntity = triggerHurt.gameObject.ToBaseEntity();
if (sourceEntity == null) {
return null;
}
if (vehiclesCache.ContainsKey(sourceEntity)) {
if (player.userID.IsSteamId()) {
MoveToPosition(player, sourceEntity.CenterPoint() + Vector3.down);
}
//triggerHurt.enabled = false;
return _false;
}
return null;
}
#endregion Damage
#region Destroy
private void OnEntityDeath(BaseCombatEntity entity, HitInfo info) {
OnEntityDeathOrKill(entity, true);
}
private void OnEntityKill(BaseCombatEntity entity) {
OnEntityDeathOrKill(entity);
}
#endregion Destroy
#region Reskin
private object OnEntityReskin(BaseEntity entity, ItemSkinDirectory.Skin skin, BasePlayer player) {
if (entity == null || player == null) {
return null;
}
Vehicle vehicle;
if (TryGetVehicle(entity, out vehicle)) {
return _false;
}
return null;
}
#endregion Reskin
#endregion Oxide Hooks
#region Methods
#region Message
private void SendCantUseMessage(BasePlayer friend, Vehicle vehicle) {
var settings = GetBaseVehicleSettings(vehicle.VehicleType);
if (settings != null) {
var player = RustCore.FindPlayerById(vehicle.PlayerId);
var playerName = player?.displayName ?? ServerMgr.Instance.persistance.GetPlayerName(vehicle.PlayerId) ?? "Unknown";
Print(friend, Lang("CantUse", friend.UserIDString, settings.DisplayName, $"<color=#{(player != null && player.IsConnected ? "69D214" : "FF6347")}>{playerName}</color>"));
}
}
#endregion Message
#region CheckEntity
private void OnEntityDeathOrKill(BaseCombatEntity entity, bool isCrash = false) {
if (entity == null) {
return;
}
Vehicle vehicle;
if (!vehiclesCache.TryGetValue(entity, out vehicle)) {
return;
}
RefundVehicleItems(vehicle, isCrash);
var settings = GetBaseVehicleSettings(vehicle.VehicleType);
if (isCrash && settings.RemoveLicenseOnceCrash) {
RemoveVehicleLicense(vehicle.PlayerId, vehicle.VehicleType);
}
vehicle.OnDeath();
vehiclesCache.Remove(entity);
}
#endregion CheckEntity
#region CheckVehicles
private void CheckVehicles() {
var currentTimestamp = TimeEx.currentTimestamp;
foreach (var entry in vehiclesCache.ToArray()) {
if (entry.Key == null || entry.Key.IsDestroyed) {
continue;
}
if (VehicleIsActive(entry.Key, entry.Value, currentTimestamp)) {
continue;
}
if (VehicleAnyMounted(entry.Key)) {
continue;
}
entry.Key.Kill(BaseNetworkable.DestroyMode.Gib);
}
}
private bool VehicleIsActive(BaseEntity entity, Vehicle vehicle, double currentTimestamp) {
var settings = GetBaseVehicleSettings(vehicle.VehicleType);
if (settings.WipeTime <= 0) {
return true;
}
if (settings.ExcludeCupboard && entity.GetBuildingPrivilege() != null) {
return true;
}
return currentTimestamp - vehicle.LastDismount < settings.WipeTime;
}
#endregion CheckVehicles
#region Refund
private void RefundVehicleItems(Vehicle vehicle, bool isCrash = false, bool isUnload = false) {
var entity = vehicle.Entity;
if (entity == null || entity.IsDestroyed) {
return;
}
var settings = GetBaseVehicleSettings(vehicle.VehicleType);
settings.RefundVehicleItems(vehicle, isCrash, isUnload);
}
private static void DropItemContainer(BaseEntity entity, ulong playerId, List<Item> collect) {
var droppedItemContainer = GameManager.server.CreateEntity(PREFAB_ITEM_DROP, entity.GetDropPosition(), entity.transform.rotation) as DroppedItemContainer;
if (droppedItemContainer != null) {
droppedItemContainer.inventory = new ItemContainer();
droppedItemContainer.inventory.ServerInitialize(null, Mathf.Min(collect.Count, droppedItemContainer.maxItemCount));
droppedItemContainer.inventory.GiveUID();
droppedItemContainer.inventory.entityOwner = droppedItemContainer;
droppedItemContainer.inventory.SetFlag(ItemContainer.Flag.NoItemInput, true);
for (var i = collect.Count - 1; i >= 0; i--) {
var item = collect[i];
if (!item.MoveToContainer(droppedItemContainer.inventory)) {
item.DropAndTossUpwards(droppedItemContainer.transform.position);
}
}
droppedItemContainer.OwnerID = playerId;
droppedItemContainer.Spawn();
}
}
#endregion Refund
#region TryPay
private bool TryPay(BasePlayer player, Dictionary<string, PriceInfo> prices, out string resources) {
if (permission.UserHasPermission(player.UserIDString, PERMISSION_BYPASS_COST)) {
resources = null;
return true;
}
if (!CanPay(player, prices, out resources)) {
return false;
}
var collect = Pool.GetList<Item>();
foreach (var entry in prices) {
if (entry.Value.amount <= 0) {
continue;
}
var itemDefinition = ItemManager.FindItemDefinition(entry.Key);
if (itemDefinition != null) {
player.inventory.Take(collect, itemDefinition.itemid, entry.Value.amount);
player.Command("note.inv", itemDefinition.itemid, -entry.Value.amount);
continue;
}
switch (entry.Key.ToLower()) {
case "economics" : Economics?.Call("Withdraw", player.userID, (double)entry.Value.amount);
continue;
case "serverrewards" : ServerRewards?.Call("TakePoints", player.userID, entry.Value.amount);
continue;
}
}
foreach (var item in collect) {
item.Remove();
}
Pool.FreeList(ref collect);
resources = null;
return true;
}
private bool CanPay(BasePlayer player, Dictionary<string, PriceInfo> prices, out string resources) {
var entries = new Hash<string, int>();
var language = RustTranslationAPI != null ? lang.GetLanguage(player.UserIDString) : null;
foreach (var entry in prices) {
if (entry.Value.amount <= 0) {
continue;
}
int missingAmount;
var itemDefinition = ItemManager.FindItemDefinition(entry.Key);
if (itemDefinition != null) {
missingAmount = entry.Value.amount - player.inventory.GetAmount(itemDefinition.itemid);
}
else {
missingAmount = CheckBalance(entry.Key, entry.Value.amount, player.userID);
}
if (missingAmount <= 0) {
continue;
}
var displayName = GetItemDisplayName(language, entry.Key, entry.Value.displayName);
entries[displayName] += missingAmount;
}
if (entries.Count > 0) {
var stringBuilder = new StringBuilder();
foreach (var entry in entries) {
stringBuilder.AppendLine($"* {Lang("PriceFormat", player.UserIDString, entry.Key, entry.Value)}");
}
resources = stringBuilder.ToString();
return false;
}
resources = null;
return true;
}
private int CheckBalance(string key, int price, ulong playerId) {
switch (key.ToLower()) {
case "economics" : var balance = Economics?.Call("Balance", playerId);
if (balance is double) {
var n = price - (double)balance;
return n <= 0 ? 0 : (int)Math.Ceiling(n);
}
return price;
case "serverrewards" : var points = ServerRewards?.Call("CheckPoints", playerId);
if (points is int) {
var n = price - (int)points;
return n <= 0 ? 0 : n;
}
return price;
default : PrintError($"Unknown Currency Type '{key}'");
return price;
}
}
#endregion TryPay
#region AreFriends
private bool AreFriends(ulong playerId, ulong friendId) {
if (playerId == friendId) {
return true;
}
if (configData.global.useTeams && SameTeam(playerId, friendId)) {
return true;
}
if (configData.global.useFriends && HasFriend(playerId, friendId)) {
return true;
}
if (configData.global.useClans && SameClan(playerId, friendId)) {
return true;
}
return false;
}
private static bool SameTeam(ulong playerId, ulong friendId) {
if (!RelationshipManager.TeamsEnabled()) {
return false;
}
var playerTeam = RelationshipManager.ServerInstance.FindPlayersTeam(playerId);
if (playerTeam == null) {
return false;
}
var friendTeam = RelationshipManager.ServerInstance.FindPlayersTeam(friendId);
if (friendTeam == null) {
return false;
}
return playerTeam == friendTeam;
}
private bool HasFriend(ulong playerId, ulong friendId) {
if (Friends == null) {
return false;
}
return (bool)Friends.Call("HasFriend", playerId, friendId);
}
private bool SameClan(ulong playerId, ulong friendId) {
if (Clans == null) {
return false;
}
//Clans
var isMember = Clans.Call("IsClanMember", playerId.ToString(), friendId.ToString());
if (isMember != null) {
return (bool)isMember;
}
//Rust:IO Clans
var playerClan = Clans.Call("GetClanOf", playerId);
if (playerClan == null) {
return false;
}
var friendClan = Clans.Call("GetClanOf", friendId);
if (friendClan == null) {
return false;
}
return playerClan == friendClan;
}
#endregion AreFriends
#region IsPlayerBlocked
private bool IsPlayerBlocked(BasePlayer player) {
if (NoEscape == null) {
return false;
}
if (configData.global.useRaidBlocker && IsRaidBlocked(player.UserIDString)) {
Print(player, Lang("RaidBlocked", player.UserIDString));
return true;
}
if (configData.global.useCombatBlocker && IsCombatBlocked(player.UserIDString)) {
Print(player, Lang("CombatBlocked", player.UserIDString));
return true;
}
return false;
}
private bool IsRaidBlocked(string playerId) {
return (bool)NoEscape.Call("IsRaidBlocked", playerId);
}
private bool IsCombatBlocked(string playerId) {
return (bool)NoEscape.Call("IsCombatBlocked", playerId);
}
private bool InZone(BasePlayer player) {
if (ZoneManager == null || !ZoneManager.IsLoaded) return false;
return configData.AntiSpawnZones.Any(x => (bool)ZoneManager?.Call("PlayerHasFlag", player, x.ToLower()));
}
#endregion IsPlayerBlocked
#region GetSettings
private BaseVehicleSettings GetBaseVehicleSettings(string vehicleType) {
BaseVehicleSettings settings;
return allVehicleSettings.TryGetValue(vehicleType, out settings) ? settings : null;
}
private BaseVehicleSettings GetBaseVehicleSettings(NormalVehicleType normalVehicleType) {
switch (normalVehicleType) {
case NormalVehicleType.Tugboat : return configData.normalVehicles.tugboat;
case NormalVehicleType.Rowboat : return configData.normalVehicles.rowboat;
case NormalVehicleType.RHIB : return configData.normalVehicles.rhib;
case NormalVehicleType.Sedan : return configData.normalVehicles.sedan;
case NormalVehicleType.HotAirBalloon : return configData.normalVehicles.hotAirBalloon;
case NormalVehicleType.MiniCopter : return configData.normalVehicles.miniCopter;
case NormalVehicleType.TransportHelicopter : return configData.normalVehicles.transportHelicopter;
case NormalVehicleType.Chinook : return configData.normalVehicles.chinook;
case NormalVehicleType.RidableHorse : return configData.normalVehicles.ridableHorse;
case NormalVehicleType.WorkCart : return configData.normalVehicles.workCart;
case NormalVehicleType.SedanRail : return configData.normalVehicles.sedanRail;
case NormalVehicleType.MagnetCrane : return configData.normalVehicles.magnetCrane;
case NormalVehicleType.SubmarineSolo : return configData.normalVehicles.submarineSolo;
case NormalVehicleType.SubmarineDuo : return configData.normalVehicles.submarineDuo;
case NormalVehicleType.Snowmobile : return configData.normalVehicles.snowmobile;
case NormalVehicleType.TomahaSnowmobile : return configData.normalVehicles.tomahaSnowmobile;
default : return null;
}
}
#endregion GetSettings
#region Permission
private bool HasAdminPermission(BasePlayer player) {
return permission.UserHasPermission(player.UserIDString, PERMISSION_ADMIN);
}
private bool CanViewVehicleInfo(BasePlayer player, string vehicleType, BaseVehicleSettings settings) {
if (settings.Purchasable && settings.Commands.Count > 0) {
return HasVehiclePermission(player, vehicleType);
}
return false;
}
private bool HasVehiclePermission(BasePlayer player, string vehicleType) {
var settings = GetBaseVehicleSettings(vehicleType);
if (!settings.UsePermission || string.IsNullOrEmpty(settings.Permission)) {
return true;
}
return permission.UserHasPermission(player.UserIDString, PERMISSION_ALL) || permission.UserHasPermission(player.UserIDString, settings.Permission);
}
#endregion Permission
#region Claim
private void TryClaimVehicle(BaseVehicle baseVehicle) {
NextTick(() => {
if (baseVehicle == null) {
return;
}
var player = baseVehicle.creatorEntity as BasePlayer;
if (player == null || !player.userID.IsSteamId() || !baseVehicle.OnlyOwnerAccessible()) {
return;
}
var vehicleType = GetClaimableVehicleType(baseVehicle);
if (vehicleType.HasValue) {
TryClaimVehicle(player, baseVehicle, vehicleType.Value.ToString());
}
}
);
}
private void TryClaimVehicle(BaseVehicle baseVehicle, BasePlayer player) {
if (player == null || !player.userID.IsSteamId()) {
return;
}
var vehicleType = GetClaimableVehicleType(baseVehicle);
if (vehicleType.HasValue) {
TryClaimVehicle(player, baseVehicle, vehicleType.Value.ToString());
}
}
private bool TryClaimVehicle(BasePlayer player, BaseEntity entity, string vehicleType) {
Vehicle vehicle;
if (!storedData.IsVehiclePurchased(player.userID, vehicleType, out vehicle)) {
if (!configData.global.autoUnlockFromVendor) {
return false;
}
storedData.AddVehicleLicense(player.userID, vehicleType);
vehicle = storedData.GetVehicleLicense(player.userID, vehicleType);
}
if (vehicle.Entity == null || vehicle.Entity.IsDestroyed) {
var settings = GetBaseVehicleSettings(vehicle.VehicleType);
if (settings != null) {
settings.PreSetupVehicle(entity, vehicle, player);
settings.SetupVehicle(entity, vehicle, player, false);
}
CacheVehicleEntity(entity, vehicle, player);
return true;
}
return false;
}
#endregion Claim
private bool TryGetVehicle(BaseEntity entity, out Vehicle vehicle) {
if (!vehiclesCache.TryGetValue(entity, out vehicle)) {
var vehicleModule = entity as BaseVehicleModule;
if (vehicleModule == null) {
return false;
}
var parent = vehicleModule.Vehicle;
if (parent == null || !vehiclesCache.TryGetValue(parent, out vehicle)) {
return false;
}
}
return true;
}
private IEnumerator UpdatePlayerData(double currentTimestamp) {
foreach (var playerData in storedData.playerData) {
foreach (var entry in playerData.Value) {
entry.Value.PlayerId = playerData.Key;
entry.Value.VehicleType = entry.Key;
if (configData.global.storeVehicle) {
entry.Value.LastRecall = entry.Value.LastDismount = currentTimestamp;
if (entry.Value.EntityId == 0) {
continue;
}
NetworkableId id = new NetworkableId(entry.Value.EntityId);
entry.Value.Entity = BaseNetworkable.serverEntities.Find(id) as BaseEntity;
if (entry.Value.Entity == null || entry.Value.Entity.IsDestroyed) {
entry.Value.EntityId = 0;
}
else {
vehiclesCache.Add(entry.Value.Entity, entry.Value);
if (entry.Value.Entity is Tugboat) {
Tugboat vehicle = entry.Value.Entity as Tugboat;
vehicle.engineThrust = TUGBOAT_ENGINETHRUST * configData.normalVehicles.tugboat.speedMultiplier;
}
else if (entry.Value.Entity is ScrapTransportHelicopter) {
ScrapTransportHelicopter vehicle = entry.Value.Entity as ScrapTransportHelicopter;
vehicle.liftFraction = configData.normalVehicles.transportHelicopter.liftFraction;
vehicle.torqueScale = SCRAP_HELICOPTER_TORQUE * configData.normalVehicles.transportHelicopter.rotationScale;
}
else if (entry.Value.Entity is MiniCopter) {
MiniCopter vehicle = entry.Value.Entity as MiniCopter;
vehicle.liftFraction = configData.normalVehicles.miniCopter.liftFraction;
vehicle.torqueScale = MINICOPTER_TORQUE * configData.normalVehicles.miniCopter.rotationScale;
}
}
}
// Adjust the delay duration here if needed
yield return new WaitForSeconds(0.1f);
}
}
finishedLoading = true;
}
#region Helpers
private static NormalVehicleType? GetClaimableVehicleType(BaseVehicle baseVehicle) {
if (baseVehicle is Tugboat) {
return NormalVehicleType.Tugboat;
}
if (baseVehicle is BaseRidableAnimal) {
return NormalVehicleType.RidableHorse;
}
if (baseVehicle is ScrapTransportHelicopter) {
return NormalVehicleType.TransportHelicopter;
}
if (baseVehicle is MiniCopter) {
return NormalVehicleType.MiniCopter;
}
if (baseVehicle is RHIB) {
return NormalVehicleType.RHIB;
}
if (baseVehicle is MotorRowboat) {
return NormalVehicleType.Rowboat;
}
if (baseVehicle is SubmarineDuo) {
return NormalVehicleType.SubmarineDuo;
}
if (baseVehicle is BaseSubmarine) {
return NormalVehicleType.SubmarineSolo;
}
return null;
}
private static bool GetDismountPosition(BaseVehicle baseVehicle, BasePlayer player, out Vector3 result) {
var parentVehicle = baseVehicle.VehicleParent();
if (parentVehicle != null) {
return GetDismountPosition(parentVehicle, player, out result);
}
var list = Pool.GetList<Vector3>();
foreach (var transform in baseVehicle.dismountPositions) {
if (baseVehicle.ValidDismountPosition(player, transform.position)) {
list.Add(transform.position);
if (baseVehicle.dismountStyle == BaseVehicle.DismountStyle.Ordered) {
break;
}
}
}
if (list.Count == 0) {
result = Vector3.zero;
Pool.FreeList(ref list);
return false;
}
var pos = player.transform.position;
list.Sort((a, b) => Vector3.Distance(a, pos).CompareTo(Vector3.Distance(b, pos)));
result = list[0];
Pool.FreeList(ref list);
return true;
}
private static bool VehicleAnyMounted(BaseEntity entity) {
var baseVehicle = entity as BaseVehicle;
if (baseVehicle != null && baseVehicle.AnyMounted()) {
return true;
}
return entity.GetComponentsInChildren<BasePlayer>()?.Length > 0;
}
private static void DismountAllPlayers(BaseEntity entity) {
var baseVehicle = entity as BaseVehicle;
if (baseVehicle != null) {
//(vehicle as BaseVehicle).DismountAllPlayers();
foreach (var mountPointInfo in baseVehicle.allMountPoints) {
if (mountPointInfo != null && mountPointInfo.mountable != null) {
var mounted = mountPointInfo.mountable.GetMounted();
if (mounted != null) {
mountPointInfo.mountable.DismountPlayer(mounted);
}
}
}
}
var players = entity.GetComponentsInChildren<BasePlayer>();
foreach (var player in players) {
player.SetParent(null, true, true);
}
}
private static Vector3 GetGroundPositionLookingAt(BasePlayer player, float distance, bool needUp = true) {
RaycastHit hitInfo;
var headRay = player.eyes.HeadRay();
if (Physics.Raycast(headRay, out hitInfo, distance, LAYER_GROUND)) {
return hitInfo.point;
}
return GetGroundPosition(headRay.origin + headRay.direction * distance, needUp);
}
private static Vector3 GetGroundPosition(Vector3 position, bool needUp = true) {
RaycastHit hitInfo;
position.y = Physics.Raycast(needUp ? position + Vector3.up * 250 : position, Vector3.down, out hitInfo, needUp ? 400f : 50f, LAYER_GROUND) ? hitInfo.point.y : TerrainMeta.HeightMap.GetHeight(position);
return position;
}
private static bool IsInWater(Vector3 position) {
var colliders = Pool.GetList<Collider>();
Vis.Colliders(position, 0.5f, colliders);
var flag = colliders.Any(x => x.gameObject.layer == (int)Layer.Water);
Pool.FreeList(ref colliders);
return flag || WaterLevel.Test(position, false, false);
}
private static void MoveToPosition(BasePlayer player, Vector3 position) {
player.Teleport(position);
player.ForceUpdateTriggers();
//if (player.HasParent()) player.SetParent(null, true, true);
player.SendNetworkUpdateImmediate();
}
// Authorizes player and their team.private static void AuthTeamOnTugboat(Tugboat tug, BasePlayer player)
{
RelationshipManager.PlayerTeam team = RelationshipManager.ServerInstance.FindPlayersTeam(player.userID);
VehiclePrivilege vehiclePrivilege = null;
if (team == null || team.members.Count == 1) {
foreach (BaseEntity child in tug.children) {
vehiclePrivilege = child as VehiclePrivilege;
if (vehiclePrivilege != null) break;
}
if (vehiclePrivilege == null) return;
// I find this a bit broken to do, as it breaks gameplay and makes it OP to recall tugboat.// if (clear) vehiclePrivilege.authorizedPlayers.Clear();
vehiclePrivilege.AddPlayer(player);
return;
}
BasePlayer teammate;
foreach (BaseEntity child in tug.children) {
vehiclePrivilege = child as VehiclePrivilege;
if (vehiclePrivilege == null) continue;
// I find this a bit broken to do, as it breaks gameplay, as it breaks gameplay and makes it OP to recall tugboat.// if(clear) vehiclePrivilege.authorizedPlayers.Clear();
vehiclePrivilege.AddPlayer(player);
foreach (ulong id in team.members) {
teammate = BasePlayer.FindByID(id);
if (teammate == null) continue;
vehiclePrivilege.AddPlayer(teammate);
}
}
}
#region Train Car
#endregion
#endregion Helpers
#endregion Methods
#region API
[HookMethod(nameof(IsLicensedVehicle))]
public bool IsLicensedVehicle(BaseEntity entity) {
return vehiclesCache.ContainsKey(entity);
}
[HookMethod(nameof(GetLicensedVehicle))]
public BaseEntity GetLicensedVehicle(ulong playerId, string license) {
return storedData.GetVehicleLicense(playerId, license)?.Entity;
}
[HookMethod(nameof(HasVehicleLicense))]
public bool HasVehicleLicense(ulong playerId, string license) {
return storedData.HasVehicleLicense(playerId, license);
}
[HookMethod(nameof(RemoveVehicleLicense))]
public bool RemoveVehicleLicense(ulong playerId, string license) {
return storedData.RemoveVehicleLicense(playerId, license);
}
[HookMethod(nameof(AddVehicleLicense))]
public bool AddVehicleLicense(ulong playerId, string license) {
return storedData.AddVehicleLicense(playerId, license);
}
[HookMethod(nameof(GetVehicleLicenses))]
public List<string> GetVehicleLicenses(ulong playerId) {
return storedData.GetVehicleLicenseNames(playerId);
}
[HookMethod(nameof(PurchaseAllVehicles))]
public void PurchaseAllVehicles(ulong playerId) {
storedData.PurchaseAllVehicles(playerId);
}
#endregion API
#region Commands
#region Universal Command
private void CmdUniversal(BasePlayer player, string command, string[] args) {
if (!permission.UserHasPermission(player.UserIDString, PERMISSION_USE)) {
Print(player, Lang("NotAllowed", player.UserIDString));
return;
}
string vehicleType;
if (IsValidOption(player, command, out vehicleType)) {
var bypassCooldown = args.Length > 0 && IsValidBypassCooldownOption(args[0]);
H
// ... [Code preview truncated due to length. Full source in attached file] ...