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

FREE LoyaltyRewards : 0.4.7 0.4.7

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

namespace Oxide.Plugins
{
    [Info("Loyalty Rewards", "Corpse", "0.4.7")]
    [Description("Rewards players with permission groups based on their activity on the server.")]
    public class LoyaltyRewards : CovalencePlugin
    {
        #region Fields

        private Configuration config;
        private PersistentData persistentData;
        private Dictionary<string, PlayerData> playerData;

        #endregion

        #region Nested Classes

        private class Configuration
        {
            public bool UseWipeCycle { get; set; }
            public int Period { get; set; }
            public int RequiredDays { get; set; }
            public double DemotionThreshold { get; set; }
            public int MinimumPeriod { get; set; }
            public bool PromoteImmediately { get; set; }
            public bool PermissionRequired { get; set; }
            public string RequiredPermissionGroup { get; set; }
            public List<string> PromotionGroups { get; set; }
        }

        private class PlayerData
        {
            public HashSet<DateTime> ActiveDays { get; set; } = new HashSet<DateTime>();
            public string CurrentGroup { get; set; }
            public bool PromotedThisPeriod { get; set; }
            public bool PendingPromotionNotification { get; set; }
        }

        private class PersistentData
        {
            public DateTime PeriodStartTime { get; set; }
            public DateTime LastWipeDate { get; set; }
            public Dictionary<string, PlayerData> PlayerData { get; set; }
        }

        #endregion

        #region Configuration Methods

        protected override void LoadDefaultConfig()
        {
            config = new Configuration
            {
                UseWipeCycle = true,
                Period = 30,
                RequiredDays = 7,
                DemotionThreshold = 0.5,
                MinimumPeriod = 2,
                PromoteImmediately = true,                 PermissionRequired = false,
                RequiredPermissionGroup = "linked",
                PromotionGroups = new List<string> { "endurer", "veteran", "legend" }
            };
            SaveConfig();
        }

        protected override void LoadConfig()
        {
            base.LoadConfig();
            config = Config.ReadObject<Configuration>();
            bool saveNeeded = false;

            if (config.PromotionGroups == null || config.PromotionGroups.Count == 0)
            {
                config.PromotionGroups = new List<string> { "endurer", "veteran", "legend" };
                saveNeeded = true;
            }

            if (saveNeeded)
            {
                SaveConfig();
            }
        }

        protected override void SaveConfig() => Config.WriteObject(config);

        #endregion

        #region Initialization

        private void Init()
        {
            LoadPersistentData();
            RegisterPermissions();
            ReconcilePlayerData();

            if (config.PromoteImmediately)
            {
                ScheduleDailyPromotionCheck();
            }
        }

        private void LoadPersistentData()
        {
            persistentData = Interface.Oxide.DataFileSystem.ReadObject<PersistentData>("LoyaltyRewardsData");
            playerData = persistentData.PlayerData ?? new Dictionary<string, PlayerData>();
        }

        private void RegisterPermissions()
        {
            permission.RegisterPermission("loyaltyrewards.admin", this);
        }

        private void ReconcilePlayerData()
        {
            foreach (var group in config.PromotionGroups)
            {
                if (permission.GroupExists(group))
                {
                    var usersInGroup = permission.GetUsersInGroup(group);
                    foreach (var userId in usersInGroup)
                    {
                        string key = GetPlayerKey(userId);
                        var player = players.FindPlayerById(userId);
                        if (player != null)
                        {
                            key = $"{player.Id} ({player.Name})";
                        }

                        if (playerData.TryGetValue(key, out var data))
                        {
                            string oldGroup = data.CurrentGroup;
                            data.CurrentGroup = ValidateCurrentGroup(data.CurrentGroup);
                            if (data.CurrentGroup != group)
                            {
                                string previousGroup = data.CurrentGroup;
                                data.CurrentGroup = group;

                                                                Puts($"[Reconcile] Player '{player?.Name ?? "Unknown"}' (ID: {player?.Id ?? userId}) CurrentGroup changed from '{previousGroup}' to '{group}' during reconciliation.");
                            }
                        }
                        else
                        {
                            playerData[key] = new PlayerData
                            {
                                CurrentGroup = group,
                                ActiveDays = new HashSet<DateTime>(),
                                PromotedThisPeriod = false
                            };

                                                        Puts($"[Reconcile] Player '{player?.Name ?? "Unknown"}' (ID: {player?.Id ?? userId}) assigned to group '{group}' during reconciliation.");
                        }
                    }
                }
            }

            foreach (var playerDataEntry in playerData.Values)
            {
                string validatedGroup = ValidateCurrentGroup(playerDataEntry.CurrentGroup);
                if (playerDataEntry.CurrentGroup != validatedGroup)
                {
                    string oldGroup = playerDataEntry.CurrentGroup;
                    playerDataEntry.CurrentGroup = validatedGroup;

                                        Puts($"[Reconcile] Player group '{oldGroup}' validated to '{validatedGroup}'.");
                }
            }

            SavePersistentData();
        }

        private void SavePersistentData()
        {
            persistentData.PlayerData = playerData;
            Interface.Oxide.DataFileSystem.WriteObject("LoyaltyRewardsData", persistentData);
        }

        #endregion

        #region Event Handlers

        private void OnServerSave()
        {
            SavePersistentData();
        }

        private void OnUserConnected(IPlayer player)
        {
            string key = GetPlayerKey(player.Id, player.Name);

            if (!playerData.TryGetValue(key, out var data))
            {
                string currentGroup = config.PromotionGroups.FirstOrDefault(g => permission.UserHasGroup(player.Id, g)) ?? "";
                data = new PlayerData
                {
                    CurrentGroup = currentGroup,
                    ActiveDays = new HashSet<DateTime>(),
                    PromotedThisPeriod = false
                };
                playerData[key] = data;
                SavePersistentData();

                                Puts($"[OnUserConnected] Player '{player.Name}' (ID: {player.Id}) connected and assigned to group '{currentGroup}'.");
            }

                        string validatedGroup = ValidateCurrentGroup(data.CurrentGroup);
            if (data.CurrentGroup != validatedGroup)
            {
                string oldGroup = data.CurrentGroup;
                data.CurrentGroup = validatedGroup;

                                Puts($"[OnUserConnected] Player '{player.Name}' (ID: {player.Id}) CurrentGroup changed from '{oldGroup}' to '{validatedGroup}' during connection validation.");
            }

            var today = DateTime.Now.Date;
            if (data.ActiveDays.Add(today))
            {
                SavePersistentData();

                                Puts($"[OnUserConnected] Player '{player.Name}' (ID: {player.Id}) active on {today.ToShortDateString()}.");
            }

            if (config.PromoteImmediately && !data.PromotedThisPeriod)
            {
                CheckPlayerPromotion(player, suppressOutput: true, allowDemotions: false);             }
        }

        private void OnPlayerSpawned(BasePlayer player)
        {
            IPlayer iPlayer = covalence.Players.FindPlayerById(player.UserIDString);
            if (iPlayer != null && playerData.TryGetValue(GetPlayerKey(iPlayer), out var data))
            {
                if (data.PendingPromotionNotification)
                {
                    iPlayer.Message($"Congratulations! Loyalty Rewards has promoted you to {data.CurrentGroup}.");
                    data.PendingPromotionNotification = false;

                    SavePersistentData();

                                        Puts($"[OnPlayerSpawned] Sent promotion notification to '{iPlayer.Name}' (ID: {iPlayer.Id}) for group '{data.CurrentGroup}'.");
                }
            }
        }

        private void OnNewSave(string filename)
        {
            if (config.UseWipeCycle)
            {
                Puts("Detected new save file. Processing promotions and demotions.");
                ProcessPromotionsAndDemotions();
                ResetPeriod(withPromotions: false);                 Puts("Period reset. All players' active days and promotion flags have been cleared.");
            }
        }

        #endregion

        #region Promotion and Demotion Logic

        private void ScheduleDailyPromotionCheck()
        {
            var now = DateTime.Now;
            var midnight = new DateTime(now.Year, now.Month, now.Day).AddDays(1);
            var timeUntilMidnight = midnight - now;

            timer.Once((float)timeUntilMidnight.TotalSeconds, () =>
            {
                RunMidnightCheck();
                ScheduleDailyPromotionCheck();
            });
        }

        private void RunMidnightCheck()
        {
            foreach (var player in players.Connected)
            {
                OnUserConnected(player);
            }
        }

        private void CheckPlayerPromotion(IPlayer player, bool suppressOutput, bool allowDemotions)
        {
            string key = GetPlayerKey(player);
            if (!playerData.TryGetValue(key, out var data)) return;

            if (data.PromotedThisPeriod) return;

            if (config.PermissionRequired && !permission.UserHasGroup(player.Id, config.RequiredPermissionGroup))
            {
                return;
            }

            int activeDays = data.ActiveDays.Count;
            int promotionIndex = config.PromotionGroups.IndexOf(data.CurrentGroup) + 1;

            if (activeDays >= config.RequiredDays && promotionIndex < config.PromotionGroups.Count)
            {
                PromotePlayer(player, data, promotionIndex);
            }
            else if (allowDemotions)
            {
                HandleDemotionOrRetention(player, data, suppressOutput);
            }
        }

        private void PromotePlayer(IPlayer player, PlayerData data, int promotionIndex)
        {
            string newGroup = config.PromotionGroups[promotionIndex];
            string oldGroup = data.CurrentGroup;

            AddPlayerToGroup(player, newGroup);
            RemoveOnlyManagedGroups(player, newGroup);

            data.CurrentGroup = newGroup;
            data.PromotedThisPeriod = true;

                        Puts($"[PromotePlayer] Player '{player.Name}' (ID: {player.Id}) promoted from '{oldGroup}' to '{newGroup}'.");

            if (!player.IsConnected)
            {
                data.PendingPromotionNotification = true;
            }
            else
            {
                player.Message($"Congratulations! Loyalty Rewards has promoted you to {newGroup}.");
            }

            SavePersistentData();
        }

        private void HandleDemotionOrRetention(IPlayer player, PlayerData data, bool suppressOutput)
        {
            int activeDays = data.ActiveDays.Count;
            int promotionIndex = config.PromotionGroups.IndexOf(data.CurrentGroup);

            if ((DateTime.Now - persistentData.PeriodStartTime).TotalDays < config.MinimumPeriod)
            {
                return;
            }

            if (activeDays < config.RequiredDays * config.DemotionThreshold && promotionIndex > 0)
            {
                DemotePlayer(player, data, promotionIndex);
            }
        }

        private void DemotePlayer(IPlayer player, PlayerData data, int promotionIndex)
        {
            string oldGroup = data.CurrentGroup;

            if (!string.IsNullOrEmpty(data.CurrentGroup) && permission.UserHasGroup(player.Id, data.CurrentGroup))
            {
                permission.RemoveUserGroup(player.Id, data.CurrentGroup);

                                Puts($"[DemotePlayer] Removed group '{data.CurrentGroup}' from player '{player.Name}' (ID: {player.Id}).");
            }

            if (promotionIndex == 0)
            {
                DemoteToBaseGroup(player, data);
            }
            else
            {
                string previousGroup = config.PromotionGroups[promotionIndex - 1];
                AddPlayerToGroup(player, previousGroup);
                data.CurrentGroup = previousGroup;

                                Puts($"[DemotePlayer] Player '{player.Name}' (ID: {player.Id}) demoted to '{previousGroup}' from '{oldGroup}'.");
            }

            SavePersistentData();
        }

        private void DemoteToBaseGroup(IPlayer player, PlayerData data)
        {
            var userGroups = permission.GetUserGroups(player.Id);
            var promotionGroupsInPlayer = config.PromotionGroups.Where(group => userGroups.Contains(group)).ToList();
            string oldGroup = data.CurrentGroup;

            if (!promotionGroupsInPlayer.Any())
            {
                data.CurrentGroup = ""; 
                                Puts($"[DemoteToBaseGroup] Player '{player.Name}' (ID: {player.Id}) demoted to base group from '{oldGroup}'.");
            }
            else
            {
                foreach (var group in promotionGroupsInPlayer)
                {
                    permission.RemoveUserGroup(player.Id, group);

                                        Puts($"[DemoteToBaseGroup] Removed group '{group}' from player '{player.Name}' (ID: {player.Id}).");
                }
                data.CurrentGroup = "";

                                Puts($"[DemoteToBaseGroup] Player '{player.Name}' (ID: {player.Id}) demoted to base group.");
            }
        }

        private void AddPlayerToGroup(IPlayer player, string group)
        {
            if (!permission.UserHasGroup(player.Id, group))
            {
                permission.AddUserGroup(player.Id, group);

                                Puts($"[AddPlayerToGroup] Added group '{group}' to player '{player.Name}' (ID: {player.Id}).");
            }
        }

        private void RemoveOnlyManagedGroups(IPlayer player, string currentGroup)
        {
            var userGroups = permission.GetUserGroups(player.Id);

            foreach (var group in userGroups)
            {
                if (config.PromotionGroups.Contains(group) && group != currentGroup)
                {
                    permission.RemoveUserGroup(player.Id, group);

                                        Puts($"[RemoveOnlyManagedGroups] Removed group '{group}' from player '{player.Name}' (ID: {player.Id}) to maintain single group assignment.");
                }
            }
        }

        private void ProcessPromotionsAndDemotions()
        {
            foreach (var player in players.All)
            {
                CheckPlayerPromotion(player, suppressOutput: true, allowDemotions: true);             }
        }

        #endregion

        #region Period Management

        [Command("lr.resetperiod", "loyaltyrewards.admin")]
        private void ResetPeriodCommand(IPlayer player, string command, string[] args)
        {
            if (!player.HasPermission("loyaltyrewards.admin"))
            {
                player.Reply("You do not have permission to use this command.");
                return;
            }

            if (args.Length == 0 || (args[0].ToLower() != "withpromotions" && args[0].ToLower() != "withoutpromotions"))
            {
                player.Reply("Usage: /lr.resetperiod <withpromotions|withoutpromotions>");
                return;
            }

            bool withPromotions = args[0].ToLower() == "withpromotions";

            ResetPeriod(withPromotions);
            if (withPromotions)
            {
                player.Reply("Loyalty Rewards period has been manually reset with promotions and demotions.");
                Puts($"[ResetPeriodCommand] Admin '{player.Name}' (ID: {player.Id}) manually reset the period with promotions and demotions.");
            }
            else
            {
                player.Reply("Loyalty Rewards period has been manually reset without promotions and demotions.");
                Puts($"[ResetPeriodCommand] Admin '{player.Name}' (ID: {player.Id}) manually reset the period without promotions and demotions.");
            }
        }

        private void ResetPeriod(bool withPromotions)
        {
            if (withPromotions)
            {
                ProcessPromotionsAndDemotions();
            }

            persistentData.PeriodStartTime = DateTime.Now;
            foreach (var data in playerData.Values)
            {
                data.ActiveDays.Clear();
                data.PromotedThisPeriod = false;
            }

            SavePersistentData();

                        Puts($"[ResetPeriod] Period reset at {DateTime.Now}. Promotions applied: {withPromotions}.");
        }

        #endregion

        #region Helper Methods

        private string ValidateCurrentGroup(string currentGroup)
        {
            if (string.IsNullOrEmpty(currentGroup) || config.PromotionGroups.Contains(currentGroup))
            {
                return currentGroup;             }
            else
            {
                                Puts($"[ValidateCurrentGroup] Invalid group '{currentGroup}' detected. Resetting to base group.");
                return "";             }
        }

                private string GetPlayerKey(IPlayer player)
        {
            return $"{player.Id} ({player.Name})";
        }

        private string GetPlayerKey(string userId, string userName = "")
        {
            if (string.IsNullOrEmpty(userName))
            {
                var player = players.FindPlayerById(userId);
                if (player != null)
                {
                    return $"{player.Id} ({player.Name})";
                }
            }
            return $"{userId} ({userName})";
        }

        #endregion

        #region Command Handlers

        [Command("lr.promote", "loyaltyrewards.admin")]
        private void PromoteCommand(IPlayer player, string command, string[] args)
        {
            if (!player.HasPermission("loyaltyrewards.admin"))
            {
                player.Reply("You do not have permission to use this command.");
                return;
            }

            if (args.Length < 1)
            {
                player.Reply("Usage: /lr.promote <player> [levels] [keeppromotioneligibility]");
                return;
            }

            var target = players.FindPlayer(args[0]);
            if (target == null)
            {
                player.Reply($"Player '{args[0]}' not found.");
                return;
            }

            string key = GetPlayerKey(target);
            if (!playerData.TryGetValue(key, out var data))
            {
                player.Reply($"No data found for player '{target.Name}'.");
                return;
            }

                        int levels = 1;
            bool keepPromotionEligibility = false;

                        if (args.Length > 1)
            {
                if (int.TryParse(args[1], out int parsedLevels))
                {
                                        levels = parsedLevels;
                }
                else if (args[1].ToLower() == "keeppromotioneligibility")
                {
                                        keepPromotionEligibility = true;
                }
            }

                        if (args.Length > 2 && args[2].ToLower() == "keeppromotioneligibility")
            {
                keepPromotionEligibility = true;
            }

                        int promotionIndex = config.PromotionGroups.IndexOf(data.CurrentGroup) + 1;
            int targetIndex = promotionIndex + levels - 1;

                        if (targetIndex >= config.PromotionGroups.Count)
            {
                targetIndex = config.PromotionGroups.Count - 1;
                Puts($"[PromoteCommand] Player {target.Name} specified promotion levels exceed available groups. Promoting to highest group: {config.PromotionGroups[targetIndex]}.");
            }

                        PromotePlayer(target, data, targetIndex);

                        if (!keepPromotionEligibility)
            {
                data.PromotedThisPeriod = true;
            }

            player.Reply($"{target.Name} has been promoted to {data.CurrentGroup}.");

                        Puts($"[PromoteCommand] Admin '{player.Name}' (ID: {player.Id}) promoted player '{target.Name}' (ID: {target.Id}) to '{data.CurrentGroup}'. Levels: {levels}, Keep Eligibility: {keepPromotionEligibility}.");
        }

        [Command("lr.demote", "loyaltyrewards.admin")]
        private void DemoteCommand(IPlayer player, string command, string[] args)
        {
            if (!player.HasPermission("loyaltyrewards.admin"))
            {
                player.Reply("You do not have permission to use this command.");
                return;
            }

            if (args.Length < 1)
            {
                player.Reply("Usage: /lr.demote <player>");
                return;
            }

            var target = players.FindPlayer(args[0]);
            if (target == null)
            {
                player.Reply($"Player '{args[0]}' not found.");
                return;
            }

            string key = GetPlayerKey(target);
            if (!playerData.TryGetValue(key, out var data))
            {
                player.Reply($"No data found for player '{target.Name}'.");
                return;
            }

            int promotionIndex = config.PromotionGroups.IndexOf(data.CurrentGroup);

            if (promotionIndex < 0)
            {
                player.Reply($"{target.Name} is already at the base group.");
                return;
            }

            DemotePlayer(target, data, promotionIndex);

            if (promotionIndex > 0)
            {
                player.Reply($"{target.Name} has been demoted to {data.CurrentGroup}.");
            }

                        Puts($"[DemoteCommand] Admin '{player.Name}' (ID: {player.Id}) demoted player '{target.Name}' (ID: {target.Id}) to '{data.CurrentGroup}'.");
        }

        [Command("lr.playtime")]
        private void PlaytimeCommand(IPlayer player, string command, string[] args)
        {
            string key = GetPlayerKey(player);

            if (!playerData.TryGetValue(key, out var data))
            {
                player.Reply("Your playtime data is not available.");
                return;
            }

            if (config.PermissionRequired && !permission.UserHasGroup(player.Id, config.RequiredPermissionGroup))
            {
                player.Reply($"You are not eligible for promotions because you are not a member of the required group '{config.RequiredPermissionGroup}'.");
                return;
            }

            int activeDays = data.ActiveDays.Count;
            double demotionThreshold = config.RequiredDays * config.DemotionThreshold;
            bool isAboveDemotionThreshold = activeDays >= Math.Ceiling(demotionThreshold);
            string periodLabel = config.UseWipeCycle ? "wipe" : "period";

            if (data.PromotedThisPeriod)
            {
                player.Reply($"You have already been promoted this {periodLabel} and are not eligible for further promotions, but you are safe from demotion.");
                return;
            }

            if (activeDays >= config.RequiredDays)
            {
                player.Reply($"You have played for {activeDays} days, are eligible for promotion, and are safe from demotion.");
            }
            else
            {
                int daysNeededForPromotion = config.RequiredDays - activeDays;
                if (isAboveDemotionThreshold)
                {
                    player.Reply($"You have played for {activeDays} days, need {daysNeededForPromotion} more days for promotion, and are safe from demotion.");
                }
                else
                {
                    int daysBelowThreshold = (int)Math.Ceiling(demotionThreshold - activeDays);
                    player.Reply($"You have played for {activeDays} days, need {daysNeededForPromotion} more days for promotion, and are {daysBelowThreshold} days below the threshold, putting you at risk of demotion.");
                }
            }

                        Puts($"[PlaytimeCommand] Player '{player.Name}' (ID: {player.Id}) queried playtime: ActiveDays={activeDays}, PromotedThisPeriod={data.PromotedThisPeriod}.");
        }

        [Command("lr.cleanup", "loyaltyrewards.admin")]
        private void CleanupCommand(IPlayer player, string command, string[] args)
        {
            if (!player.HasPermission("loyaltyrewards.admin"))
            {
                player.Reply("You do not have permission to use this command.");
                return;
            }

            if (args.Length != 1 || args[0].ToLower() != "ihaveabackup")
            {
                player.Reply("Usage: /lr.cleanup ihaveabackup");
                return;
            }

            int removedPlayers = 0;
            foreach (var playerDataEntry in playerData.ToList())
            {
                var data = playerDataEntry.Value;
                if (!config.PromotionGroups.Contains(data.CurrentGroup) && data.ActiveDays.Count == 0)
                {
                    playerData.Remove(playerDataEntry.Key);
                    removedPlayers++;
                }
            }

            SavePersistentData();

            player.Reply($"Loyalty Rewards data cleaned up. {removedPlayers} players removed.");

                        Puts($"[CleanupCommand] Admin '{player.Name}' (ID: {player.Id}) performed cleanup. {removedPlayers} players removed from data.");
        }

        #endregion
    }
}

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

Другие ресурсы пользователя 15FPS

Сверху