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

FREE Tides : 1.0.0 1.0.0

Нет прав для скачивания
C#:
using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Oxide.Core;
using Oxide.Core.Libraries.Covalence;
using UnityEngine;

namespace Oxide.Plugins
{
    [Info("Tides" , "Krungh Crow" , "1.0.0")]
    [Description("Automated Tidal System.")]
    public class Tides : RustPlugin
    {
        #region variables

        private const string PermAdmin = "tides.admin";
        private const float MinOceanLevel = 0f;
        private const bool StartRising = true;
        private const float ChangeThreshold = 0.0001f;

        private PluginConfig _config;
        private Timer _updateTimer;

        private bool _initialized;
        private bool _paused;
        private bool _manualOverrideActive;
        private bool _rising;

        private float _manualOceanLevel;
        private float _currentOceanLevel;
        private float _lastAppliedOceanLevel = float.MinValue;
        private float _holdUntilRealtime;

        private TideState _tideState = TideState.Rising;

        private enum TideState
        {
            Rising = 0,
            HighTide = 1,
            Falling = 2,
            LowTide = 3
        }

        #endregion

        #region Config

        private class PluginConfig
        {
            [JsonProperty("Tides Enabled")]
            public bool TidesEnabled = true;
            [JsonProperty("Update Interval Seconds")]
            public float UpdateIntervalSeconds = 1f;
            [JsonProperty("Increment Amount Per Tick")]
            public float IncrementAmountPerTick = 0.005f;
            [JsonProperty("Maximum Tide Level")]
            public float MaximumTideLevel = 1.15f;
            [JsonProperty("Time Between Tides Seconds")]
            public float TimeBetweenTidesSeconds = 600f;
            [JsonProperty("Send Tide Milestone Messages")]
            public bool SendTideMilestones = false;
            [JsonProperty("Debug")]
            public bool Debug = false;
            [JsonProperty("Plugin Version (Do not edit)")]
            public string Version = "1.0.0";
        }

        protected override void LoadDefaultConfig()
        {
            _config = new PluginConfig
            {
                Version = Version.ToString()
            };
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();

            try
            {
                _config = Config.ReadObject<PluginConfig>();
                if (_config == null)
                    throw new Exception("Config file is null.");
            }
            catch
            {
                PrintWarning("Config file was invalid, creating a new one with defaults.");
                LoadDefaultConfig();
            }

            ValidateConfig();
            _config.Version = Version.ToString();
            SaveConfig();
        }

        protected override void SaveConfig()
        {
            Config.WriteObject(_config , true);
        }

        private void ValidateConfig()
        {
            _config.UpdateIntervalSeconds = Mathf.Max(0.05f , _config.UpdateIntervalSeconds);
            _config.IncrementAmountPerTick = Mathf.Max(0.0001f , _config.IncrementAmountPerTick);
            _config.MaximumTideLevel = Mathf.Max(MinOceanLevel , _config.MaximumTideLevel);
            _config.TimeBetweenTidesSeconds = Mathf.Max(0f , _config.TimeBetweenTidesSeconds);
        }

        #endregion

        #region Lang

        protected override void LoadDefaultMessages()
        {
            lang.RegisterMessages(new Dictionary<string , string>
            {
                ["Prefix"] = "[Tides]" ,
                ["NoPermission"] = "You don't have permission to use this command." ,
                ["Usage"] = "Usage: tide pause | resume | set <value> | clear | max <value> | step <value> | interval <seconds> | hold <seconds> | rising | falling" ,
                ["TidesPaused"] = "Tides paused." ,
                ["TidesResumed"] = "Tides resumed." ,
                ["ManualSet"] = "Manual ocean level override enabled: {0:0.###}." ,
                ["ManualCleared"] = "Manual override cleared. Incremental tides resumed." ,
                ["MaxSet"] = "Maximum tide level set to {0:0.###}." ,
                ["StepSet"] = "Increment amount per tick set to {0:0.###}." ,
                ["IntervalSet"] = "Update interval set to {0:0.###} seconds." ,
                ["HoldSet"] = "Time between tides set to {0:0.###} seconds." ,
                ["DirectionRising"] = "Tide direction set to rising." ,
                ["DirectionFalling"] = "Tide direction set to falling." ,
                ["InvalidValue"] = "Invalid value." ,
                ["ReachedHigh"] = "High tide reached. Ocean level: {0:0.0}" ,
                ["ReachedLow"] = "Low tide reached. Ocean level: {0:0.0}"
            } , this);
        }

        private string Msg(string key , string userId = null , params object[] args)
        {
            string message = lang.GetMessage(key , this , userId);
            return args == null || args.Length == 0 ? message : string.Format(message , args);
        }

        private string GetPrefix(string userId = null)
        {
            return Msg("Prefix" , userId);
        }

        #endregion

        #region Hooks

        private void Init()
        {
            permission.RegisterPermission(PermAdmin , this);
            LoadConfig();
        }

        private void OnServerInitialized()
        {
            _initialized = true;
            _rising = StartRising;
            _currentOceanLevel = ClampOcean(GetCurrentOceanLevel());
            _holdUntilRealtime = 0f;

            if (_currentOceanLevel <= MinOceanLevel)
                SetTideState(_rising ? TideState.Rising : TideState.LowTide , true);
            else if (_currentOceanLevel >= _config.MaximumTideLevel)
                SetTideState(_rising ? TideState.HighTide : TideState.Falling , true);
            else
                SetTideState(_rising ? TideState.Rising : TideState.Falling , true);

            if (_config.Debug)
                Puts($"Initialized. Version={_config.Version}, CurrentOcean={_currentOceanLevel:0.###}, Max={_config.MaximumTideLevel:0.###}, Hold={_config.TimeBetweenTidesSeconds:0.###}, State={_tideState}");

            StartUpdater();
        }

        private void Unload()
        {
            DestroyUpdater();
            SetOceanLevel(0f);
        }

        #endregion

        #region Commands

        [Command("tide")]
        private void TideCommand(IPlayer player , string command , string[] args)
        {
            if (player == null)
                return;

            if (!player.IsServer && !player.HasPermission(PermAdmin))
            {
                player.Reply($"{GetPrefix(player.Id)} {Msg("NoPermission" , player.Id)}");
                return;
            }

            if (args.Length == 0)
            {
                player.Reply($"{GetPrefix(player.Id)} {Msg("Usage" , player.Id)}");
                return;
            }

            switch (args[0].ToLower())
            {
                case "pause":
                    _paused = true;
                    player.Reply($"{GetPrefix(player.Id)} {Msg("TidesPaused" , player.Id)}");
                    return;

                case "resume":
                    _paused = false;
                    _manualOverrideActive = false;
                    player.Reply($"{GetPrefix(player.Id)} {Msg("TidesResumed" , player.Id)}");
                    ApplyCurrentMode(true);
                    return;

                case "set":
                    {
                        float value;
                        if (args.Length < 2 || !float.TryParse(args[1] , out value))
                        {
                            player.Reply($"{GetPrefix(player.Id)} {Msg("InvalidValue" , player.Id)}");
                            return;
                        }

                        value = ClampOcean(value);
                        _manualOverrideActive = true;
                        _manualOceanLevel = value;
                        _currentOceanLevel = value;
                        _holdUntilRealtime = 0f;

                        if (_currentOceanLevel <= MinOceanLevel)
                            SetTideState(TideState.LowTide);
                        else if (_currentOceanLevel >= _config.MaximumTideLevel)
                            SetTideState(TideState.HighTide);
                        else
                            SetTideState(_rising ? TideState.Rising : TideState.Falling);

                        player.Reply($"{GetPrefix(player.Id)} {Msg("ManualSet" , player.Id , value)}");
                        ApplyCurrentMode(true);
                        return;
                    }

                case "clear":
                    _manualOverrideActive = false;
                    _paused = false;
                    _holdUntilRealtime = 0f;
                    SetTideState(_rising ? TideState.Rising : TideState.Falling);
                    player.Reply($"{GetPrefix(player.Id)} {Msg("ManualCleared" , player.Id)}");
                    ApplyCurrentMode(true);
                    return;

                case "max":
                    {
                        float value;
                        if (args.Length < 2 || !float.TryParse(args[1] , out value))
                        {
                            player.Reply($"{GetPrefix(player.Id)} {Msg("InvalidValue" , player.Id)}");
                            return;
                        }

                        _config.MaximumTideLevel = Mathf.Max(MinOceanLevel , value);
                        _manualOceanLevel = ClampOcean(_manualOceanLevel);
                        _currentOceanLevel = ClampOcean(_currentOceanLevel);

                        SaveConfig();
                        player.Reply($"{GetPrefix(player.Id)} {Msg("MaxSet" , player.Id , _config.MaximumTideLevel)}");
                        ApplyCurrentMode(true);
                        return;
                    }

                case "step":
                    {
                        float value;
                        if (args.Length < 2 || !float.TryParse(args[1] , out value))
                        {
                            player.Reply($"{GetPrefix(player.Id)} {Msg("InvalidValue" , player.Id)}");
                            return;
                        }

                        _config.IncrementAmountPerTick = Mathf.Max(0.0001f , value);
                        SaveConfig();
                        player.Reply($"{GetPrefix(player.Id)} {Msg("StepSet" , player.Id , _config.IncrementAmountPerTick)}");
                        return;
                    }

                case "interval":
                    {
                        float value;
                        if (args.Length < 2 || !float.TryParse(args[1] , out value))
                        {
                            player.Reply($"{GetPrefix(player.Id)} {Msg("InvalidValue" , player.Id)}");
                            return;
                        }

                        _config.UpdateIntervalSeconds = Mathf.Max(0.05f , value);
                        SaveConfig();
                        RestartUpdater();

                        player.Reply($"{GetPrefix(player.Id)} {Msg("IntervalSet" , player.Id , _config.UpdateIntervalSeconds)}");
                        return;
                    }

                case "hold":
                    {
                        float value;
                        if (args.Length < 2 || !float.TryParse(args[1] , out value))
                        {
                            player.Reply($"{GetPrefix(player.Id)} {Msg("InvalidValue" , player.Id)}");
                            return;
                        }

                        _config.TimeBetweenTidesSeconds = Mathf.Max(0f , value);
                        SaveConfig();
                        player.Reply($"{GetPrefix(player.Id)} {Msg("HoldSet" , player.Id , _config.TimeBetweenTidesSeconds)}");
                        return;
                    }

                case "rising":
                    _rising = true;
                    _holdUntilRealtime = 0f;
                    SetTideState(TideState.Rising);
                    player.Reply($"{GetPrefix(player.Id)} {Msg("DirectionRising" , player.Id)}");
                    ApplyCurrentMode(true);
                    return;

                case "falling":
                    _rising = false;
                    _holdUntilRealtime = 0f;
                    SetTideState(TideState.Falling);
                    player.Reply($"{GetPrefix(player.Id)} {Msg("DirectionFalling" , player.Id)}");
                    ApplyCurrentMode(true);
                    return;

                default:
                    player.Reply($"{GetPrefix(player.Id)} {Msg("Usage" , player.Id)}");
                    return;
            }
        }

        #endregion

        #region Core

        private void StartUpdater()
        {
            DestroyUpdater();

            _updateTimer = timer.Every(_config.UpdateIntervalSeconds , () =>
            {
                if (!_initialized || !_config.TidesEnabled)
                    return;

                ApplyCurrentMode();
            });

            ApplyCurrentMode(true);
        }

        private void RestartUpdater()
        {
            if (!_initialized)
                return;

            StartUpdater();
        }

        private void DestroyUpdater()
        {
            if (_updateTimer == null)
                return;

            _updateTimer.Destroy();
            _updateTimer = null;
        }

        private void ApplyCurrentMode(bool force = false)
        {
            if (_manualOverrideActive)
            {
                ApplyOceanLevel(_manualOceanLevel , force);
                return;
            }

            if (_paused)
                return;

            TickIncrementalTide(force);
        }

        private void TickIncrementalTide(bool force = false)
        {
            float now = UnityEngine.Time.realtimeSinceStartup;

            if (!force && _holdUntilRealtime > now)
            {
                if (_currentOceanLevel >= _config.MaximumTideLevel)
                    SetTideState(TideState.HighTide);
                else if (_currentOceanLevel <= MinOceanLevel)
                    SetTideState(TideState.LowTide);

                if (_config.Debug)
                    Puts($"Holding tide. Remaining={_holdUntilRealtime - now:0.###}s State={_tideState}");

                return;
            }

            float previousLevel = _currentOceanLevel;

            if (!force)
            {
                if (_rising)
                {
                    SetTideState(TideState.Rising);
                    _currentOceanLevel += _config.IncrementAmountPerTick;
                }
                else
                {
                    SetTideState(TideState.Falling);
                    _currentOceanLevel -= _config.IncrementAmountPerTick;
                }
            }

            if (_currentOceanLevel >= _config.MaximumTideLevel)
            {
                _currentOceanLevel = _config.MaximumTideLevel;

                if (_rising)
                {
                    SetTideState(TideState.HighTide);

                    if (_config.SendTideMilestones)
                        SendChatAnnouncement("ReachedHigh" , _currentOceanLevel);

                    _rising = false;
                    _holdUntilRealtime = now + _config.TimeBetweenTidesSeconds;
                }
            }
            else if (_currentOceanLevel <= MinOceanLevel)
            {
                _currentOceanLevel = MinOceanLevel;

                if (!_rising)
                {
                    SetTideState(TideState.LowTide);

                    if (_config.SendTideMilestones)
                        SendChatAnnouncement("ReachedLow" , _currentOceanLevel);

                    _rising = true;
                    _holdUntilRealtime = now + _config.TimeBetweenTidesSeconds;
                }
            }

            _currentOceanLevel = ClampOcean(_currentOceanLevel);

            if (_config.Debug && !force)
                Puts($"Tick tide: previous={previousLevel:0.###}, current={_currentOceanLevel:0.###}, state={_tideState}, holdUntil={_holdUntilRealtime:0.###}");

            ApplyOceanLevel(_currentOceanLevel , force);
        }

        private void ApplyOceanLevel(float level , bool force = false)
        {
            level = ClampOcean(level);

            if (!force && Mathf.Abs(level - _lastAppliedOceanLevel) < ChangeThreshold)
                return;

            if (!SetOceanLevel(level))
                return;

            _lastAppliedOceanLevel = level;
        }

        private bool SetOceanLevel(float level)
        {
            try
            {
                level = ClampOcean(level);

                ConsoleSystem.Run(ConsoleSystem.Option.Server.Quiet() , "oceanlevel" , level);

                if (WaterSystem.Instance != null)
                    WaterSystem.OceanLevel = level;

                if (_config.Debug)
                    Puts($"Applied ocean level: {level:0.###}");

                return true;
            }
            catch (Exception ex)
            {
                PrintError($"Failed to apply ocean level {level:0.###}: {ex}");
                return false;
            }
        }

        private float GetCurrentOceanLevel()
        {
            return Mathf.Max(MinOceanLevel , ConVar.Env.oceanlevel);
        }

        private float ClampOcean(float level)
        {
            return Mathf.Clamp(level , MinOceanLevel , _config.MaximumTideLevel);
        }

        private bool IsHolding()
        {
            return _holdUntilRealtime > UnityEngine.Time.realtimeSinceStartup;
        }

        private void SetTideState(TideState newState , bool force = false)
        {
            if (!force && _tideState == newState)
                return;

            TideState oldState = _tideState;
            _tideState = newState;

            Interface.CallHook("OnFloodTideStateChanged" , oldState.ToString() , newState.ToString() , _currentOceanLevel);

            if (_config.Debug)
                Puts($"Tide state changed: {oldState} -> {newState} at {_currentOceanLevel:0.###}");
        }

        private int GetTicksBetween(float fromLevel , float toLevel)
        {
            float distance = Mathf.Abs(toLevel - fromLevel);
            if (distance <= 0f)
                return 0;

            if (_config.IncrementAmountPerTick <= 0f)
                return 0;

            return Mathf.CeilToInt(distance / _config.IncrementAmountPerTick);
        }

        private float GetTravelSeconds(float fromLevel , float toLevel)
        {
            return GetTicksBetween(fromLevel , toLevel) * _config.UpdateIntervalSeconds;
        }

        private float GetHoldRemainingSeconds()
        {
            float remaining = _holdUntilRealtime - UnityEngine.Time.realtimeSinceStartup;
            return Mathf.Max(0f , remaining);
        }

        private float GetTimeUntilNextStateChangeInternal()
        {
            switch (_tideState)
            {
                case TideState.Rising:
                    return GetTravelSeconds(_currentOceanLevel , _config.MaximumTideLevel);

                case TideState.HighTide:
                    return GetHoldRemainingSeconds();

                case TideState.Falling:
                    return GetTravelSeconds(_currentOceanLevel , MinOceanLevel);

                case TideState.LowTide:
                    return GetHoldRemainingSeconds();

                default:
                    return 0f;
            }
        }

        private float GetTimeUntilRisingInternal()
        {
            switch (_tideState)
            {
                case TideState.Rising:
                    return 0f;

                case TideState.HighTide:
                    return GetHoldRemainingSeconds() + GetTravelSeconds(_config.MaximumTideLevel , MinOceanLevel) + _config.TimeBetweenTidesSeconds;

                case TideState.Falling:
                    return GetTravelSeconds(_currentOceanLevel , MinOceanLevel) + _config.TimeBetweenTidesSeconds;

                case TideState.LowTide:
                    return GetHoldRemainingSeconds();

                default:
                    return 0f;
            }
        }

        private float GetTimeUntilFallingInternal()
        {
            switch (_tideState)
            {
                case TideState.Rising:
                    return GetTravelSeconds(_currentOceanLevel , _config.MaximumTideLevel) + _config.TimeBetweenTidesSeconds;

                case TideState.HighTide:
                    return GetHoldRemainingSeconds();

                case TideState.Falling:
                    return 0f;

                case TideState.LowTide:
                    return GetHoldRemainingSeconds() + GetTravelSeconds(MinOceanLevel , _config.MaximumTideLevel) + _config.TimeBetweenTidesSeconds;

                default:
                    return 0f;
            }
        }

        private float GetTimeUntilHighTideInternal()
        {
            switch (_tideState)
            {
                case TideState.Rising:
                    return GetTravelSeconds(_currentOceanLevel , _config.MaximumTideLevel);

                case TideState.HighTide:
                    return 0f;

                case TideState.Falling:
                    return GetTravelSeconds(_currentOceanLevel , MinOceanLevel) + _config.TimeBetweenTidesSeconds + GetTravelSeconds(MinOceanLevel , _config.MaximumTideLevel);

                case TideState.LowTide:
                    return GetHoldRemainingSeconds() + GetTravelSeconds(MinOceanLevel , _config.MaximumTideLevel);

                default:
                    return 0f;
            }
        }

        private float GetTimeUntilLowTideInternal()
        {
            switch (_tideState)
            {
                case TideState.Rising:
                    return GetTravelSeconds(_currentOceanLevel , _config.MaximumTideLevel) + _config.TimeBetweenTidesSeconds + GetTravelSeconds(_config.MaximumTideLevel , MinOceanLevel);

                case TideState.HighTide:
                    return GetHoldRemainingSeconds() + GetTravelSeconds(_config.MaximumTideLevel , MinOceanLevel);

                case TideState.Falling:
                    return GetTravelSeconds(_currentOceanLevel , MinOceanLevel);

                case TideState.LowTide:
                    return 0f;

                default:
                    return 0f;
            }
        }

        #endregion

        #region API

        private object GetTideState() => _tideState.ToString();

        private object GetTideStateIndex() => (int)_tideState;

        private object GetCurrentTideLevel() => GetCurrentOceanLevel();

        private object TideIsRising() => _tideState == TideState.Rising;

        private object TideIsFalling() => _tideState == TideState.Falling;

        private object TideIsHigh() => _tideState == TideState.HighTide;

        private object TideIsLow() => _tideState == TideState.LowTide;

        private object GetTimeUntilNextStateChange() => GetTimeUntilNextStateChangeInternal();

        private object GetTimeUntilRising() => GetTimeUntilRisingInternal();

        private object GetTimeUntilFalling() => GetTimeUntilFallingInternal();

        private object GetTimeUntilHighTide() => GetTimeUntilHighTideInternal();

        private object GetTimeUntilLowTide() => GetTimeUntilLowTideInternal();

        private object GetHoldRemaining() => GetHoldRemainingSeconds();

        #endregion

        #region Messaging

        private void SendChatAnnouncement(string key , params object[] args)
        {
            var players = BasePlayer.activePlayerList;
            if (players == null || players.Count == 0)
                return;

            foreach (BasePlayer basePlayer in players)
            {
                if (basePlayer == null || !basePlayer.IsConnected)
                    continue;

                basePlayer.ChatMessage($"{GetPrefix(basePlayer.UserIDString)} {Msg(key , basePlayer.UserIDString , args)}");
            }
        }

        #endregion
    }
}

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