Иконка ресурса

FREE VirtualCarGarage : 1.0.0 1.0.0

Нет прав для скачивания
C#:
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Game.Rust.Cui;
using Rust;
using Rust.Modular;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using UnityEngine;
using UnityEngine.UI;

namespace Oxide.Plugins
{
    [Info("Virtual Car Garage", "DaBoiJason", "1.0.0")]
    [Description("Stores modular cars virtually and lets players load them from a polished car-lift garage UI.")]
    public class VirtualCarGarage : RustPlugin
    {
        #region References / constants

        private const string PermissionUse = "virtualcargarage.use";
        private const string DataFileName = "VirtualCarGarage";

        private const string LiftUi = "VirtualCarGarage.Lift";
        private const string GarageUi = "VirtualCarGarage.Garage";
        private const string ModalUi = "VirtualCarGarage.Modal";

        private const string ChassisPrefab2 =
            "assets/content/vehicles/modularcar/car_chassis_2module.entity.prefab";

        private const string ChassisPrefab3 =
            "assets/content/vehicles/modularcar/car_chassis_3module.entity.prefab";

        private const string ChassisPrefab4 =
            "assets/content/vehicles/modularcar/car_chassis_4module.entity.prefab";

        private readonly Dictionary<ulong, ModularCarGarage> _activeLifts =
            new Dictionary<ulong, ModularCarGarage>();

        private readonly HashSet<ulong> _busyPlayers =
            new HashSet<ulong>();

        private StoredData _data;
        private Configuration _config;

        #endregion

        #region Oxide hooks

        private void Init()
        {
            permission.RegisterPermission(PermissionUse, this);

            string lockBypassPermission =
                GetLockBypassPermission();

            if (!string.IsNullOrWhiteSpace(
                    lockBypassPermission))
            {
                permission.RegisterPermission(
                    lockBypassPermission,
                    this
                );
            }

            if (_config.PermissionVehicleLimits != null)
            {
                foreach (KeyValuePair<string, int> entry in _config.PermissionVehicleLimits)
                {
                    if (!string.IsNullOrWhiteSpace(entry.Key))
                        permission.RegisterPermission(entry.Key, this);
                }
            }

            LoadData();
        }

        private void OnServerInitialized()
        {
            foreach (BasePlayer player in BasePlayer.activePlayerList)
            {
                DestroyAllUi(player);
            }
        }

        private void Unload()
        {
            foreach (BasePlayer player in BasePlayer.activePlayerList)
            {
                DestroyAllUi(player);
            }

            SaveData();
        }

        private void OnServerSave()
        {
            SaveData();
        }

        private void OnLootEntity(
            BasePlayer player,
            ModularCarGarage lift)
        {
            if (player == null || lift == null)
                return;

            if (!HasPermission(player))
                return;

            _activeLifts[player.userID] = lift;

            NextTick(delegate
            {
                if (player == null || !player.IsConnected)
                    return;

                ModularCarGarage currentLift;

                if (!_activeLifts.TryGetValue(
                        player.userID,
                        out currentLift) ||
                    currentLift != lift)
                {
                    return;
                }

                ShowLiftUi(player, lift);
            });
        }

        private void OnPlayerLootEnd(
            PlayerLoot loot)
        {
            if (loot == null)
                return;

            BasePlayer player =
                loot.baseEntity as BasePlayer;

            if (player == null)
                return;

            _activeLifts.Remove(player.userID);
            DestroyAllUi(player);
        }

        private void OnPlayerDisconnected(
            BasePlayer player,
            string reason)
        {
            if (player == null)
                return;

            _activeLifts.Remove(player.userID);
            _busyPlayers.Remove(player.userID);
        }

        #endregion

        #region Commands - lift / garage

        // Saves the car then removes the real one from the lift.
        [ConsoleCommand("virtualcar.save")]
        private void CmdSave(
            ConsoleSystem.Arg arg)
        {
            BasePlayer player = arg.Player();

            if (!ValidatePlayer(player))
                return;

            ModularCarGarage lift;

            if (!TryGetActiveLift(
                    player,
                    out lift))
            {
                return;
            }

            if (_busyPlayers.Contains(
                    player.userID))
            {
                return;
            }

            ModularCar car =
                lift.carOccupant;

            if (car == null)
            {
                Reply(
                    player,
                    "There is no modular car on this lift."
                );

                return;
            }

            // Do not let somebody garage a locked car they cannot use.
            if (!CanPlayerStoreLockedVehicle(
                    player,
                    car))
            {
                return;
            }

            PlayerGarage garage =
                GetGarage(player.userID);

            int vehicleLimit =
                GetVehicleLimit(player);

            if (garage.Vehicles.Count >=
                vehicleLimit)
            {
                Reply(
                    player,
                    string.Format(
                        "Your virtual garage is full ({0}/{1}).",
                        garage.Vehicles.Count,
                        vehicleLimit
                    )
                );

                return;
            }

            if (!ValidateVehicleContentsForSave(
                    player,
                    car))
            {
                return;
            }

            _busyPlayers.Add(
                player.userID
            );

            try
            {
                VirtualCar snapshot =
                    CaptureVehicle(
                        player,
                        car,
                        garage
                    );

                // Save it before removing the real car.
                garage.Vehicles.Add(
                    snapshot
                );

                SaveData();

                // Clear it first so stuff cannot dupe.
                StripPhysicalCar(car);

                if (lift.carOccupant == car)
                {
                    lift.ReleaseOccupant();
                }

                car.Kill();

                Reply(
                    player,
                    string.Format(
                        "Stored <color=#F3A84B>{0}</color> in your virtual garage.",
                        snapshot.Name
                    )
                );

                RefreshLiftUi(player);
            }
            catch (Exception ex)
            {
                PrintError(
                    string.Format(
                        "Failed to save virtual car for {0} ({1}): {2}",
                        player.displayName,
                        player.userID,
                        ex
                    )
                );

                Reply(
                    player,
                    "The car could not be stored. Check the server console."
                );
            }
            finally
            {
                _busyPlayers.Remove(
                    player.userID
                );
            }
        }

        [ConsoleCommand("virtualcar.garage")]
        private void CmdGarage(
            ConsoleSystem.Arg arg)
        {
            BasePlayer player = arg.Player();

            if (!ValidatePlayer(player))
                return;

            ModularCarGarage lift;

            if (!TryGetActiveLift(
                    player,
                    out lift))
            {
                return;
            }

            OpenGarageUi(player);
        }

        [ConsoleCommand("virtualcar.garage.close")]
        private void CmdGarageClose(
            ConsoleSystem.Arg arg)
        {
            BasePlayer player = arg.Player();

            if (player == null)
                return;

            CuiHelper.DestroyUi(
                player,
                GarageUi
            );

            CuiHelper.DestroyUi(
                player,
                ModalUi
            );
        }

        // Loads the selected car back onto the lift.
        [ConsoleCommand("virtualcar.load")]
        private void CmdLoad(
            ConsoleSystem.Arg arg)
        {
            BasePlayer player = arg.Player();

            if (!ValidatePlayer(player))
                return;

            if (arg.Args == null ||
                arg.Args.Length < 1)
            {
                return;
            }

            if (_busyPlayers.Contains(
                    player.userID))
            {
                return;
            }

            ModularCarGarage lift;

            if (!TryGetActiveLift(
                    player,
                    out lift))
            {
                return;
            }

            if (lift.carOccupant != null)
            {
                Reply(
                    player,
                    "The Modular Car Lift must be empty before loading a stored vehicle."
                );

                return;
            }

            string vehicleId =
                arg.Args[0].ToString();

            PlayerGarage garage =
                GetGarage(player.userID);

            VirtualCar stored =
                garage.Vehicles.FirstOrDefault(
                    x => string.Equals(
                        x.Id,
                        vehicleId,
                        StringComparison.OrdinalIgnoreCase
                    )
                );

            if (stored == null)
            {
                Reply(
                    player,
                    "That stored vehicle no longer exists."
                );

                OpenGarageUi(player);
                return;
            }

            _busyPlayers.Add(
                player.userID
            );

            // Remove the saved one first so we do not end up with 2 cars.
            garage.Vehicles.Remove(stored);

            SaveData();

            ModularCar spawnedCar = null;

            try
            {
                spawnedCar =
                    SpawnStoredVehicleSkeleton(
                        player,
                        lift,
                        stored
                    );

                if (spawnedCar == null)
                {
                    throw new Exception(
                        "CreateEntity returned null."
                    );
                }

                CuiHelper.DestroyUi(
                    player,
                    GarageUi
                );

                CuiHelper.DestroyUi(
                    player,
                    ModalUi
                );

                // Storage boxes are sometimes not ready straight away.
                TryFinalizeLoadedVehicle(
                    player.userID,
                    spawnedCar,
                    stored,
                    0
                );
            }
            catch (Exception ex)
            {
                RollbackFailedLoad(
                    player.userID,
                    spawnedCar,
                    stored,
                    ex
                );
            }
        }

        // Waits a bit for the engine and storage boxes to be ready.
        private void TryFinalizeLoadedVehicle(
            ulong userId,
            ModularCar car,
            VirtualCar stored,
            int attempt)
        {
            if (car == null ||
                car.IsDestroyed)
            {
                RollbackFailedLoad(
                    userId,
                    car,
                    stored,
                    new Exception(
                        "Vehicle was destroyed before restoration completed."
                    )
                );

                return;
            }

            if (!AreStoredVehicleContainersReady(
                    car,
                    stored))
            {
                if (attempt <
                    _config.LoadRestoreMaximumRetries)
                {
                    timer.Once(
                        _config
                            .LoadRestoreRetryDelaySeconds,
                        () =>
                        {
                            TryFinalizeLoadedVehicle(
                                userId,
                                car,
                                stored,
                                attempt + 1
                            );
                        }
                    );

                    return;
                }

                RollbackFailedLoad(
                    userId,
                    car,
                    stored,
                    new Exception(
                        "Timed out waiting for modular-car engine/storage containers to initialize."
                    )
                );

                return;
            }

            try
            {
                RestoreVehicleState(
                    car,
                    stored
                );

                // Put the built-in car lock back after all modules are ready.
                RestoreVehicleLock(
                    car,
                    stored
                );

                car.SendNetworkUpdateImmediate();

                BasePlayer player =
                    BasePlayer.FindByID(
                        userId
                    );

                if (player != null &&
                    player.IsConnected)
                {
                    Reply(
                        player,
                        string.Format(
                            "Loaded <color=#7CD37C>{0}</color> onto the lift.",
                            stored.Name
                        )
                    );

                    RefreshLiftUi(player);
                }

                _busyPlayers.Remove(
                    userId
                );
            }
            catch (Exception ex)
            {
                RollbackFailedLoad(
                    userId,
                    car,
                    stored,
                    ex
                );
            }
        }

        // Checks if all the boxes we need are ready yet.
        private bool AreStoredVehicleContainersReady(
            ModularCar car,
            VirtualCar stored)
        {
            if (car == null ||
                stored == null ||
                stored.Modules == null)
            {
                return false;
            }

            foreach (
                VirtualModule savedModule
                in stored.Modules)
            {
                BaseVehicleModule module;

                if (!car.TryGetModuleAt(
                        savedModule.Socket,
                        out module) ||
                    module == null ||
                    module.FirstSocketIndex !=
                    savedModule.Socket)
                {
                    return false;
                }

                VehicleModuleEngine engineModule =
                    module as VehicleModuleEngine;

                if (_config
                        .SaveAndRestoreEngineParts &&
                    engineModule != null &&
                    savedModule.EngineParts != null &&
                    savedModule.EngineParts.Count > 0)
                {
                    EngineStorage engineStorage =
                        engineModule
                            .GetContainer()
                            as EngineStorage;

                    if (engineStorage == null ||
                        engineStorage.inventory == null)
                    {
                        return false;
                    }
                }

                if (_config
                        .SaveModuleStorageContents &&
                    savedModule
                        .StorageContainers != null &&
                    savedModule
                        .StorageContainers.Count > 0)
                {
                    List<StorageContainer>
                        liveContainers =
                            GetModuleStorageContainers(
                                module,
                                engineModule
                            );

                    if (liveContainers.Count <
                        savedModule
                            .StorageContainers.Count)
                    {
                        return false;
                    }
                }
            }

            return true;
        }

        // Load failed, remove the bad car and put the save back.
        private void RollbackFailedLoad(
            ulong userId,
            ModularCar spawnedCar,
            VirtualCar stored,
            Exception ex)
        {
            PrintError(
                string.Format(
                    "Failed to load virtual car {0} for {1}: {2}",
                    stored != null
                        ? stored.Id
                        : "unknown",
                    userId,
                    ex
                )
            );

            if (spawnedCar != null &&
                !spawnedCar.IsDestroyed)
            {
                try
                {
                    StripPhysicalCar(
                        spawnedCar
                    );

                    spawnedCar.Kill();
                }
                catch
                {
                    // Just clean up what we can.
                }
            }

            if (stored != null)
            {
                PlayerGarage garage =
                    GetGarage(userId);

                bool alreadyRestored =
                    garage.Vehicles.Any(
                        x => string.Equals(
                            x.Id,
                            stored.Id,
                            StringComparison
                                .OrdinalIgnoreCase
                        )
                    );

                if (!alreadyRestored)
                {
                    garage.Vehicles.Add(
                        stored
                    );

                    SortGarage(garage);
                    SaveData();
                }
            }

            _busyPlayers.Remove(userId);

            BasePlayer player =
                BasePlayer.FindByID(userId);

            if (player != null &&
                player.IsConnected)
            {
                Reply(
                    player,
                    "The vehicle could not be fully restored. Its virtual copy was returned to your garage."
                );

                OpenGarageUi(player);
                RefreshLiftUi(player);
            }
        }

        #endregion

        #region Commands - rename / delete

        [ConsoleCommand("virtualcar.rename.ask")]
        private void CmdRenameAsk(
            ConsoleSystem.Arg arg)
        {
            BasePlayer player = arg.Player();

            if (!ValidatePlayer(player))
                return;

            if (arg.Args == null ||
                arg.Args.Length < 1)
            {
                return;
            }

            VirtualCar car =
                FindVehicle(
                    player.userID,
                    arg.Args[0].ToString()
                );

            if (car == null)
                return;

            ShowRenameModal(
                player,
                car
            );
        }

        [ConsoleCommand("virtualcar.rename.submit")]
        private void CmdRenameSubmit(
            ConsoleSystem.Arg arg)
        {
            BasePlayer player = arg.Player();

            if (!ValidatePlayer(player))
                return;

            if (arg.Args == null ||
                arg.Args.Length < 2)
            {
                Reply(
                    player,
                    "Enter a vehicle name."
                );

                return;
            }

            string vehicleId =
                arg.Args[0].ToString();

            string newName =
                string.Join(
                    " ",
                    arg.Args
                        .Skip(1)
                        .Select(
                            x => x.ToString()
                        )
                        .ToArray()
                );

            newName =
                SanitizeVehicleName(
                    newName
                );

            if (string.IsNullOrEmpty(
                    newName))
            {
                Reply(
                    player,
                    "Vehicle name cannot be empty."
                );

                return;
            }

            VirtualCar car =
                FindVehicle(
                    player.userID,
                    vehicleId
                );

            if (car == null)
                return;

            car.Name = newName;

            SaveData();

            CuiHelper.DestroyUi(
                player,
                ModalUi
            );

            OpenGarageUi(player);
        }

        [ConsoleCommand("virtualcar.delete.ask")]
        private void CmdDeleteAsk(
            ConsoleSystem.Arg arg)
        {
            BasePlayer player = arg.Player();

            if (!ValidatePlayer(player))
                return;

            if (arg.Args == null ||
                arg.Args.Length < 1)
            {
                return;
            }

            VirtualCar car =
                FindVehicle(
                    player.userID,
                    arg.Args[0].ToString()
                );

            if (car == null)
                return;

            ShowDeleteModal(
                player,
                car
            );
        }

        [ConsoleCommand("virtualcar.delete.confirm")]
        private void CmdDeleteConfirm(
            ConsoleSystem.Arg arg)
        {
            BasePlayer player = arg.Player();

            if (!ValidatePlayer(player))
                return;

            if (arg.Args == null ||
                arg.Args.Length < 1)
            {
                return;
            }

            PlayerGarage garage =
                GetGarage(
                    player.userID
                );

            string vehicleId =
                arg.Args[0].ToString();

            VirtualCar car =
                garage.Vehicles
                    .FirstOrDefault(
                        x => string.Equals(
                            x.Id,
                            vehicleId,
                            StringComparison
                                .OrdinalIgnoreCase
                        )
                    );

            if (car == null)
                return;

            garage.Vehicles.Remove(car);

            SaveData();

            CuiHelper.DestroyUi(
                player,
                ModalUi
            );

            Reply(
                player,
                string.Format(
                    "Deleted <color=#E77878>{0}</color> from the virtual garage.",
                    car.Name
                )
            );

            OpenGarageUi(player);
            RefreshLiftUi(player);
        }

        [ConsoleCommand("virtualcar.modal.close")]
        private void CmdModalClose(
            ConsoleSystem.Arg arg)
        {
            BasePlayer player = arg.Player();

            if (player == null)
                return;

            CuiHelper.DestroyUi(
                player,
                ModalUi
            );
        }

        #endregion

        #region Capture / restore

        // Checks storage and engine rules before the car can be saved.
        private bool ValidateVehicleContentsForSave(
            BasePlayer player,
            ModularCar car)
        {
            if (car == null)
                return false;

            HashSet<string> blacklist =
                new HashSet<string>(
                    (
                        _config.StorageItemBlacklist ??
                        new List<string>()
                    )
                    .Where(
                        x =>
                            !string.IsNullOrWhiteSpace(
                                x
                            )
                    )
                    .Select(
                        x => x.Trim()
                    ),
                    StringComparer.OrdinalIgnoreCase
                );

            for (
                int socketIndex = 0;
                socketIndex < car.TotalSockets;
                socketIndex++)
            {
                BaseVehicleModule module;

                if (!car.TryGetModuleAt(
                        socketIndex,
                        out module) ||
                    module == null ||
                    module.FirstSocketIndex !=
                    socketIndex)
                {
                    continue;
                }

                VehicleModuleEngine engineModule =
                    module as VehicleModuleEngine;

                // Check engine parts.
                if (!_config
                        .SaveAndRestoreEngineParts &&
                    _config
                        .RequireEngineEmptyWhenEnginePartsAreNotSaved &&
                    engineModule != null)
                {
                    EngineStorage engineStorage =
                        engineModule
                            .GetContainer()
                            as EngineStorage;

                    if (engineStorage != null &&
                        ContainerHasItems(
                            engineStorage.inventory
                        ))
                    {
                        Reply(
                            player,
                            "Remove all engine parts before storing this vehicle."
                        );

                        return false;
                    }
                }

                // Check storage and blocked items.
                List<StorageContainer>
                    storageContainers =
                        GetModuleStorageContainers(
                            module,
                            engineModule
                        );

                foreach (
                    StorageContainer container
                    in storageContainers)
                {
                    if (container == null ||
                        container.inventory == null)
                    {
                        continue;
                    }

                    if (_config
                            .RequireModuleStorageEmptyBeforeSave &&
                        ContainerHasItems(
                            container.inventory
                        ))
                    {
                        Reply(
                            player,
                            "Empty all vehicle module storage before storing this vehicle."
                        );

                        return false;
                    }

                    if (blacklist.Count > 0)
                    {
                        string blockedShortname;

                        if (TryFindBlacklistedItem(
                                container.inventory,
                                blacklist,
                                out blockedShortname))
                        {
                            Reply(
                                player,
                                string.Format(
                                    "This vehicle cannot be stored while its storage contains blacklisted item: <color=#E77878>{0}</color>.",
                                    blockedShortname
                                )
                            );

                            return false;
                        }
                    }
                }
            }

            return true;
        }

        private bool ContainerHasItems(
            ItemContainer container)
        {
            return
                container != null &&
                container.itemList != null &&
                container.itemList.Count > 0;
        }

        private bool TryFindBlacklistedItem(
            ItemContainer container,
            HashSet<string> blacklist,
            out string shortname)
        {
            shortname = null;

            if (container == null ||
                container.itemList == null)
            {
                return false;
            }

            foreach (
                Item item
                in container.itemList)
            {
                if (item == null ||
                    item.info == null)
                {
                    continue;
                }

                if (blacklist.Contains(
                        item.info.shortname))
                {
                    shortname =
                        item.info.shortname;

                    return true;
                }

                if (item.contents != null &&
                    TryFindBlacklistedItem(
                        item.contents,
                        blacklist,
                        out shortname))
                {
                    return true;
                }
            }

            return false;
        }

        // Checks the built-in car lock before SAVE.
        private bool CanPlayerStoreLockedVehicle(
            BasePlayer player,
            ModularCar car)
        {
            if (player == null ||
                car == null ||
                car.CarLock == null ||
                !car.CarLock.HasALock)
            {
                return true;
            }

            if (_config.AllowSavingLockedCarsWithoutAuthorization)
                return true;

            string bypassPermission =
                GetLockBypassPermission();

            if (!string.IsNullOrWhiteSpace(
                    bypassPermission) &&
                permission.UserHasPermission(
                    player.UserIDString,
                    bypassPermission))
            {
                return true;
            }

            bool? directAccess =
                TryCheckCarLockAccess(
                    car.CarLock,
                    player
                );

            if (directAccess == true)
                return true;

            ulong lockOwnerId =
                GetCarLockOwnerId(
                    car.CarLock
                );

            if (lockOwnerId != 0 &&
                lockOwnerId == player.userID)
            {
                return true;
            }

            List<ulong> authorizedPlayers =
                GetCarLockAuthorizedPlayers(
                    car.CarLock
                );

            if (authorizedPlayers.Contains(
                    player.userID))
            {
                return true;
            }

            Reply(
                player,
                "You are not authorized to this vehicle lock."
            );

            return false;
        }

        private string GetLockBypassPermission()
        {
            if (_config == null ||
                string.IsNullOrWhiteSpace(
                    _config.LockAuthorizationBypassPermission))
            {
                return
                    "virtualcargarage.bypasslockauth";
            }

            return
                _config
                    .LockAuthorizationBypassPermission
                    .Trim();
        }

        // Saves the built-in modular car code lock.
        private VirtualCarLock CaptureVehicleLock(
            ModularCar car)
        {
            if (!_config.SaveAndRestoreVehicleLock ||
                car == null ||
                car.CarLock == null ||
                !car.CarLock.HasALock)
            {
                return null;
            }

            VirtualCarLock saved =
                new VirtualCarLock();

            saved.HasLock = true;
            saved.Code =
                GetCarLockCode(
                    car.CarLock
                );
            saved.OwnerId =
                GetCarLockOwnerId(
                    car.CarLock
                );
            saved.AuthorizedPlayers =
                GetCarLockAuthorizedPlayers(
                    car.CarLock
                );

            if (saved.OwnerId != 0 &&
                !saved.AuthorizedPlayers.Contains(
                    saved.OwnerId))
            {
                saved.AuthorizedPlayers.Add(
                    saved.OwnerId
                );
            }

            if (string.IsNullOrEmpty(
                    saved.Code))
            {
                throw new Exception(
                    "Could not read the modular car lock code. The car was not stored so the lock is not lost."
                );
            }

            return saved;
        }

        // Adds the saved built-in lock back onto the loaded car.
        private void RestoreVehicleLock(
            ModularCar car,
            VirtualCar stored)
        {
            if (!_config.SaveAndRestoreVehicleLock ||
                car == null ||
                stored == null ||
                stored.Lock == null ||
                !stored.Lock.HasLock)
            {
                return;
            }

            if (string.IsNullOrEmpty(
                    stored.Lock.Code))
            {
                throw new Exception(
                    "Saved vehicle has a lock but no saved lock code."
                );
            }

            if (car.CarLock == null)
            {
                throw new Exception(
                    "Loaded vehicle does not have a CarLock component."
                );
            }

            if (car.CarLock.HasALock)
            {
                car.CarLock.RemoveLock();
            }

            ulong lockOwnerId =
                stored.Lock.OwnerId;

            if (lockOwnerId == 0)
            {
                lockOwnerId =
                    stored.OriginalOwnerId;
            }

            if (lockOwnerId == 0 &&
                stored.Lock.AuthorizedPlayers != null &&
                stored.Lock.AuthorizedPlayers.Count > 0)
            {
                lockOwnerId =
                    stored.Lock.AuthorizedPlayers[0];
            }

            if (!car.CarLock.TryAddALock(
                    stored.Lock.Code,
                    lockOwnerId))
            {
                throw new Exception(
                    "Could not put the saved vehicle lock back onto the car."
                );
            }

            List<ulong> players =
                stored.Lock.AuthorizedPlayers ??
                new List<ulong>();

            bool authRestored =
                RestoreCarLockAuthorizedPlayers(
                    car.CarLock,
                    players
                );

            int extraAuthCount =
                players.Count(
                    x => x != 0 &&
                         x != lockOwnerId
                );

            if (!authRestored &&
                extraAuthCount > 0)
            {
                throw new Exception(
                    "Vehicle lock was added but its authorized player list could not be restored."
                );
            }

            car.SendNetworkUpdateImmediate();
        }

        private bool? TryCheckCarLockAccess(
            object carLock,
            BasePlayer player)
        {
            if (carLock == null ||
                player == null)
            {
                return null;
            }

            string[] methodNames =
            {
                "HasAccess",
                "HasPlayerAuth",
                "IsPlayerAuthorized",
                "IsAuthorized",
                "CanAccess",
                "HasLockPermission",
                "GetPlayerLockPermission"
            };

            Type type =
                carLock.GetType();

            foreach (string methodName in methodNames)
            {
                MethodInfo[] methods =
                    type.GetMethods(
                        BindingFlags.Instance |
                        BindingFlags.Public |
                        BindingFlags.NonPublic
                    );

                foreach (MethodInfo method in methods)
                {
                    if (!string.Equals(
                            method.Name,
                            methodName,
                            StringComparison.OrdinalIgnoreCase) ||
                        method.ReturnType != typeof(bool))
                    {
                        continue;
                    }

                    ParameterInfo[] parameters =
                        method.GetParameters();

                    if (parameters.Length != 1)
                        continue;

                    try
                    {
                        object argument;

                        if (parameters[0]
                                .ParameterType
                                .IsAssignableFrom(
                                    typeof(BasePlayer)))
                        {
                            argument = player;
                        }
                        else if (parameters[0].ParameterType ==
                                 typeof(ulong))
                        {
                            argument = player.userID;
                        }
                        else
                        {
                            continue;
                        }

                        return (bool)method.Invoke(
                            carLock,
                            new[] { argument }
                        );
                    }
                    catch
                    {
                        // Try the saved auth list below instead.
                    }
                }
            }

            return null;
        }

        private string GetCarLockCode(
            object carLock)
        {
            object value =
                GetCarLockMemberValue(
                    carLock,
                    typeof(string),
                    new[]
                    {
                        "code",
                        "Code",
                        "lockCode",
                        "LockCode"
                    },
                    new[]
                    {
                        "code"
                    }
                );

            return value as string;
        }

        private ulong GetCarLockOwnerId(
            object carLock)
        {
            object value =
                GetCarLockMemberValue(
                    carLock,
                    typeof(ulong),
                    new[]
                    {
                        "ownerID",
                        "OwnerID",
                        "ownerId",
                        "OwnerId",
                        "lockOwnerID",
                        "LockOwnerID",
                        "lockOwnerId",
                        "LockOwnerId"
                    },
                    new[]
                    {
                        "owner"
                    }
                );

            return value is ulong
                ? (ulong)value
                : 0UL;
        }

        private List<ulong> GetCarLockAuthorizedPlayers(
            object carLock)
        {
            List<ulong> result =
                new List<ulong>();

            if (carLock == null)
                return result;

            Type type =
                carLock.GetType();

            BindingFlags flags =
                BindingFlags.Instance |
                BindingFlags.Public |
                BindingFlags.NonPublic;

            foreach (FieldInfo field in
                type.GetFields(flags))
            {
                if (!IsLikelyAuthMemberName(
                        field.Name))
                {
                    continue;
                }

                AddUlongValues(
                    result,
                    field.GetValue(carLock)
                );
            }

            foreach (PropertyInfo property in
                type.GetProperties(flags))
            {
                if (!property.CanRead ||
                    property.GetIndexParameters().Length > 0 ||
                    !IsLikelyAuthMemberName(
                        property.Name))
                {
                    continue;
                }

                try
                {
                    AddUlongValues(
                        result,
                        property.GetValue(
                            carLock,
                            null
                        )
                    );
                }
                catch
                {
                    // Ignore members that cannot be read safely.
                }
            }

            return result
                .Where(x => x != 0)
                .Distinct()
                .ToList();
        }

        private bool RestoreCarLockAuthorizedPlayers(
            object carLock,
            List<ulong> players)
        {
            if (carLock == null ||
                players == null ||
                players.Count == 0)
            {
                return true;
            }

            Type type =
                carLock.GetType();

            BindingFlags flags =
                BindingFlags.Instance |
                BindingFlags.Public |
                BindingFlags.NonPublic;

            bool foundCollection = false;

            foreach (FieldInfo field in
                type.GetFields(flags))
            {
                if (!IsLikelyAuthMemberName(
                        field.Name))
                {
                    continue;
                }

                object value =
                    field.GetValue(carLock);

                if (AddPlayersToCollection(
                        value,
                        players))
                {
                    foundCollection = true;
                }
            }

            foreach (PropertyInfo property in
                type.GetProperties(flags))
            {
                if (!property.CanRead ||
                    property.GetIndexParameters().Length > 0 ||
                    !IsLikelyAuthMemberName(
                        property.Name))
                {
                    continue;
                }

                try
                {
                    object value =
                        property.GetValue(
                            carLock,
                            null
                        );

                    if (AddPlayersToCollection(
                            value,
                            players))
                    {
                        foundCollection = true;
                    }
                }
                catch
                {
                    // Skip anything that cannot be changed.
                }
            }

            return foundCollection;
        }

        private bool AddPlayersToCollection(
            object collection,
            List<ulong> players)
        {
            ICollection<ulong> genericCollection =
                collection as ICollection<ulong>;

            if (genericCollection != null)
            {
                foreach (ulong userId in players)
                {
                    if (userId != 0 &&
                        !genericCollection.Contains(
                            userId))
                    {
                        genericCollection.Add(
                            userId
                        );
                    }
                }

                return true;
            }

            if (collection == null)
                return false;

            MethodInfo addMethod =
                collection
                    .GetType()
                    .GetMethod(
                        "Add",
                        new[] { typeof(ulong) }
                    );

            if (addMethod == null)
                return false;

            foreach (ulong userId in players)
            {
                if (userId == 0)
                    continue;

                try
                {
                    addMethod.Invoke(
                        collection,
                        new object[] { userId }
                    );
                }
                catch
                {
                    return false;
                }
            }

            return true;
        }

        private void AddUlongValues(
            List<ulong> target,
            object value)
        {
            if (target == null ||
                value == null ||
                value is string)
            {
                return;
            }

            IEnumerable enumerable =
                value as IEnumerable;

            if (enumerable == null)
                return;

            foreach (object item in enumerable)
            {
                if (item is ulong)
                {
                    target.Add((ulong)item);
                }
            }
        }

        private bool IsLikelyAuthMemberName(
            string name)
        {
            if (string.IsNullOrEmpty(name))
                return false;

            string lower =
                name.ToLowerInvariant();

            if (lower.Contains("denied") ||
                lower.Contains("blocked") ||
                lower.Contains("failed") ||
                lower.Contains("attempt"))
            {
                return false;
            }

            return
                lower.Contains("auth") ||
                lower.Contains("whitelist") ||
                lower.Contains("player") ||
                lower.Contains("user");
        }

        private object GetCarLockMemberValue(
            object instance,
            Type wantedType,
            string[] exactNames,
            string[] nameParts)
        {
            if (instance == null)
                return null;

            Type type =
                instance.GetType();

            BindingFlags flags =
                BindingFlags.Instance |
                BindingFlags.Public |
                BindingFlags.NonPublic;

            foreach (string name in exactNames)
            {
                FieldInfo field =
                    type.GetField(
                        name,
                        flags
                    );

                if (field != null &&
                    wantedType.IsAssignableFrom(
                        field.FieldType))
                {
                    return field.GetValue(
                        instance
                    );
                }

                PropertyInfo property =
                    type.GetProperty(
                        name,
                        flags
                    );

                if (property != null &&
                    property.CanRead &&
                    property.GetIndexParameters().Length == 0 &&
                    wantedType.IsAssignableFrom(
                        property.PropertyType))
                {
                    try
                    {
                        return 
// ... [Code preview truncated due to length. Full source in attached file] ...

Автор
15FPS
Скачиваний
0
Просмотры
1
Первый выпуск
Обновление
Оценка
0.00 звёзд 0 оценок
Сверху