using System; using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Networking; using Newtonsoft.Json; using System.Linq; public class MANAGER_Mail : MonoBehaviour { public static MANAGER_Mail Instance { get; private set; } private const string MAIL_URL = "http://mc1.live-on.pro:64093/api/mail/mail.json"; private const string REWARDS_URL = "http://mc1.live-on.pro:64093/api/other/rewards_table_id.json"; // Данные сервера public List ActiveMails { get; private set; } = new List(); public Dictionary> RewardsTable { get; private set; } = new Dictionary>(); // Состояние инициализации public bool IsDataLoaded { get; private set; } = false; private void Awake() { if (Instance == null) { Instance = this; DontDestroyOnLoad(gameObject); } else { Destroy(gameObject); } } private void Start() { StartCoroutine(LoadMailSystemData()); } private IEnumerator LoadMailSystemData() { IsDataLoaded = false; // 1. Загрузка конфигурации писем UnityWebRequest mailReq = UnityWebRequest.Get(MAIL_URL); yield return mailReq.SendWebRequest(); if (mailReq.result != UnityWebRequest.Result.Success) { yield break; // В реальном проекте здесь нужна логика ретрая } // 2. Загрузка таблицы наград UnityWebRequest rewardsReq = UnityWebRequest.Get(REWARDS_URL); yield return rewardsReq.SendWebRequest(); if (rewardsReq.result != UnityWebRequest.Result.Success) { yield break; } // 3. Десериализация try { // 1. Десериализуем во временную обертку var wrapper = JsonConvert.DeserializeObject(mailReq.downloadHandler.text); // 2. Присваиваем список из обертки в ActiveMails ActiveMails = wrapper != null ? wrapper.mails : new List(); // Для наград (если там такая же структура с корневым объектом, проверьте rewards_table_id.json) RewardsTable = JsonConvert.DeserializeObject>>(rewardsReq.downloadHandler.text); IsDataLoaded = true; MANAGER_GameEvents.TriggerUIUpdate(); } catch (System.Exception e) { } } public DateTime GetCurrentTime() { try { // Пытаемся получить локальное время устройства return DateTime.Now; } catch { // Если по какой-то причине на Linux или другой ОС произошел сбой, // берем UTC и прибавляем 7 часов (Красноярск) return DateTime.UtcNow.AddHours(7); } } public bool IsMailDeleted(string mailId) { return PlayerPrefs.GetInt($"Mail_Deleted_{mailId}", 0) == 1; } public void DeleteMail(string mailId) { PlayerPrefs.SetInt($"Mail_Deleted_{mailId}", 1); PlayerPrefs.Save(); MANAGER_GameEvents.TriggerUIUpdate(); // Обновляем список, чтобы письмо исчезло } // --- ЛОГИКА СОСТОЯНИЙ (ПРОЧИТАНО / ЗАБРАНО) --- public bool IsMailRead(string mailId) { return PlayerPrefs.GetInt($"Mail_Read_{mailId}", 0) == 1; } public void MarkAsRead(string mailId) { if (!IsMailRead(mailId)) { PlayerPrefs.SetInt($"Mail_Read_{mailId}", 1); PlayerPrefs.Save(); // Отправляем сигнал для визуального снятия метки "Новое" MANAGER_GameEvents.TriggerUIUpdate(); } } // Добавьте это в MANAGER_Mail.cs public string GetFormattedBody(MailEntry mail) { if (mail == null || mail.content == null) return ""; string body = mail.content.body; // Проверяем наличие плейсхолдера if (body.Contains("{today_reward}")) { string rewardText = ""; // Проверяем, есть ли ID таблицы наград и загружена ли она if (!string.IsNullOrEmpty(mail.rewards_table_id) && RewardsTable.TryGetValue(mail.rewards_table_id, out var rewards)) { // Собираем строку наград (например: "Золото x15, Меч x1") // Здесь r.name — это то самое поле, которое мы договорились добавить в RewardItem rewardText = string.Join(", ", rewards.Select(r => $"[g]x{r.amount} {r.name}[/c]")); } else { // Если награда не найдена, выводим заглушку или пустую строку rewardText = "награды отсутствуют"; } body = body.Replace("{today_reward}", rewardText); } return body; } private const int TEST_COOLDOWN_SECONDS = 86400; public void ClaimReward(string mailId) { if (IsRewardClaimed(mailId)) return; MailEntry mail = ActiveMails.FirstOrDefault(m => m.id == mailId); if (mail != null) { // Сохраняем текущее время в формате Total Seconds double totalSecondsNow = GetCurrentTime().Subtract(new DateTime(1970, 1, 1)).TotalSeconds; PlayerPrefs.SetString($"Mail_LastClaimedTime_{mailId}", totalSecondsNow.ToString()); PlayerPrefs.Save(); MarkAsRead(mailId); MANAGER_GameEvents.TriggerUIUpdate(); } } public bool IsRewardClaimed(string mailId) { string lastClaimedStr = PlayerPrefs.GetString($"Mail_LastClaimedTime_{mailId}", "0"); double lastClaimedSeconds = double.Parse(lastClaimedStr); double currentSeconds = GetCurrentTime().Subtract(new DateTime(1970, 1, 1)).TotalSeconds; // Письмо "забрано", если с момента последнего клика прошло МЕНЬШЕ 60 секунд return (currentSeconds - lastClaimedSeconds) < TEST_COOLDOWN_SECONDS; } public List GetAvailableMails() { return ActiveMails .Where(mail => { // Базовая фильтрация: удаленные и не подходящие по дате if (IsMailDeleted(mail.id)) return false; DateTime now = GetCurrentTime(); if (mail.logic.StartDate.HasValue && now < mail.logic.StartDate.Value) return false; if (mail.logic.EndDate.HasValue && now > mail.logic.EndDate.Value) return false; return true; }) /* СОРТИРОВКА: 1. Сначала считаем приоритет: Если награда ЗАБРАНА (IsRewardClaimed == true), ставим -99. Если награда ДОСТУПНА, ставим 0 (или можно брать mail.priority, если он есть в классе). */ .OrderByDescending(mail => IsRewardClaimed(mail.id) ? -99 : 0) // 2. Внутри групп (сначала новые/доступные) сортируем по дате начала .ThenByDescending(mail => mail.logic.StartDate) .ToList(); } }