757 lines
29 KiB
C#
757 lines
29 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
[Serializable]
|
|
public struct EnemyConfiguration
|
|
{
|
|
public int enemyID;
|
|
[Range(0, 100)]
|
|
public int hpPercentage;
|
|
}
|
|
|
|
[Serializable]
|
|
public class ChartFileEntry
|
|
{
|
|
[Header("Inspector")]
|
|
public int difficulty;
|
|
public float difficultyLEVEL;
|
|
|
|
[Header("Inspector")]
|
|
public float enemyTotalHP_Multiplier;
|
|
|
|
[Header("Enemy Configuration")]
|
|
[Tooltip("List of enemy configurations for this difficulty (0-5 enemies)")]
|
|
public List<EnemyConfiguration> enemyConfigList = new List<EnemyConfiguration>();
|
|
|
|
// [Tooltip("List of enemy IDs for this difficulty (0-5 enemies)")]
|
|
// public List<int> enemyList = new List<int>(); // Deprecated
|
|
|
|
[Header("Inspector")]
|
|
public string difficultyName;
|
|
|
|
[Header("Inspector")]
|
|
public TextAsset chartFile;
|
|
|
|
[Header("Inspector")]
|
|
[TextArea(3, 10)]
|
|
public string difficultyDescription;
|
|
|
|
[Header("Inspector")]
|
|
public int lastScoreForThisDifficulty;
|
|
|
|
[Header("Inspector")]
|
|
public int chartPersonalRecordForThisDifficulty;
|
|
public int idolPersonalRecordForThisDifficulty;
|
|
public int totalPersonalRecordForThisDifficulty;
|
|
|
|
[Header("Inspector")]
|
|
public float levelProgressForThisDifficulty;
|
|
|
|
[Header("Inspector")]
|
|
public DateTime lastPlayTimeForThisDifficulty;
|
|
|
|
[Header("Inspector")]
|
|
public int experienceProvidedForThisDifficulty;
|
|
}
|
|
|
|
[CreateAssetMenu(fileName = "NewSongData", menuName = "EaseOut/SongData")]
|
|
public class SongData : ScriptableObject
|
|
{
|
|
public string usernameID = "user_TestUser@FloatGaming";
|
|
public string songName;
|
|
public int songID;
|
|
public int songLength_second;
|
|
public string artistName;
|
|
public string painter;
|
|
public string level_creator;
|
|
public string belongsTo_whichDLC;
|
|
|
|
public int bpm;
|
|
public float songDuration;
|
|
|
|
public int game_enterTimes;
|
|
public float time_totalPlayingTime;
|
|
public DateTime uploadData;
|
|
|
|
[Header("Inspector")]
|
|
public Sprite illustration;
|
|
public Sprite backgroudPIC;
|
|
public Sprite fullscreen_songPicture;
|
|
public Sprite card_profileImage;
|
|
|
|
[Header("Inspector")]
|
|
public Sprite right_pic_bottom_image;
|
|
public Sprite right_pic_top_image;
|
|
|
|
[Header("Inspector")]
|
|
public AudioClip audioFile;
|
|
public AudioClip audio_previewAudio;
|
|
|
|
[Header("Inspector")]
|
|
public int difficultyID;
|
|
public Dictionary<int, int> difficultyNumberMap = new Dictionary<int, int>();
|
|
public Dictionary<int, int> personalRecordMap = new Dictionary<int, int>();
|
|
public Dictionary<int, int> idolRecordMap = new Dictionary<int, int>();
|
|
public Dictionary<int, int> chartScoreMap = new Dictionary<int, int>();
|
|
public Dictionary<int, TextAsset> chartFileMap = new Dictionary<int, TextAsset>();
|
|
|
|
public List<ChartFileEntry> chartFiles = new List<ChartFileEntry>();
|
|
|
|
[NonSerialized] private Dictionary<int, List<long>> enemyConfigSignatureCache;
|
|
|
|
public int personalRecord;
|
|
public float current_levelProgress;
|
|
public bool _if_level_is_EASE;
|
|
public int max_comboRecord;
|
|
|
|
[Header("Inspector")]
|
|
public int thisLevel_selectedDifficultyID;
|
|
|
|
[Header("Inspector")]
|
|
public string thisLevel_addDateString;
|
|
|
|
[Header("Inspector")]
|
|
[TextArea(3, 10)]
|
|
public string thisLevel_overallDescription;
|
|
|
|
// [Header("Enemy Configuration")]
|
|
// [Tooltip("DEPRECATED: Use enemyList in ChartFileEntry instead. List of enemy IDs for this song (0-5 enemies)")]
|
|
// public List<int> enemyList = new List<int>();
|
|
|
|
private void OnValidate()
|
|
{
|
|
if (enemyConfigSignatureCache == null) enemyConfigSignatureCache = new Dictionary<int, List<long>>();
|
|
|
|
if (chartFiles != null)
|
|
{
|
|
foreach (var chart in chartFiles)
|
|
{
|
|
if (chart != null)
|
|
{
|
|
if (chart.enemyConfigList != null && chart.enemyConfigList.Count > 5)
|
|
{
|
|
chart.enemyConfigList.RemoveRange(5, chart.enemyConfigList.Count - 5);
|
|
Debug.LogWarning($"[SongData] {songName} (Difficulty {chart.difficulty}): enemyConfigList length restricted to a maximum of 5.");
|
|
}
|
|
|
|
if (chart.enemyConfigList != null && chart.enemyConfigList.Count > 0)
|
|
{
|
|
var activeIndices = new List<int>();
|
|
var currentSignature = new List<long>();
|
|
for (int i = 0; i < chart.enemyConfigList.Count; i++)
|
|
{
|
|
var c = chart.enemyConfigList[i];
|
|
if (c.enemyID == 0)
|
|
{
|
|
if (c.hpPercentage != 0)
|
|
{
|
|
c.hpPercentage = 0;
|
|
chart.enemyConfigList[i] = c;
|
|
}
|
|
currentSignature.Add(0L);
|
|
continue;
|
|
}
|
|
|
|
if (c.hpPercentage < 0) c.hpPercentage = 0;
|
|
if (c.hpPercentage > 100) c.hpPercentage = 100;
|
|
chart.enemyConfigList[i] = c;
|
|
activeIndices.Add(i);
|
|
currentSignature.Add(((long)c.enemyID << 32) | (uint)c.hpPercentage);
|
|
}
|
|
|
|
int activeCount = activeIndices.Count;
|
|
if (activeCount == 1)
|
|
{
|
|
int idx = activeIndices[0];
|
|
var c = chart.enemyConfigList[idx];
|
|
c.hpPercentage = 100;
|
|
chart.enemyConfigList[idx] = c;
|
|
}
|
|
else if (activeCount > 1)
|
|
{
|
|
int changedIndex = -1;
|
|
int changedEnemyID = 0;
|
|
|
|
if (enemyConfigSignatureCache.TryGetValue(chart.difficulty, out var oldSignature) &&
|
|
oldSignature != null &&
|
|
oldSignature.Count == currentSignature.Count)
|
|
{
|
|
for (int i = 0; i < currentSignature.Count; i++)
|
|
{
|
|
if (oldSignature[i] != currentSignature[i])
|
|
{
|
|
changedIndex = i;
|
|
changedEnemyID = chart.enemyConfigList[i].enemyID;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
int remainderIndex = activeIndices[activeIndices.Count - 1];
|
|
if (changedIndex >= 0)
|
|
{
|
|
int candidate = -1;
|
|
for (int i = activeIndices.Count - 1; i >= 0; i--)
|
|
{
|
|
int idx = activeIndices[i];
|
|
if (idx == changedIndex) continue;
|
|
if (chart.enemyConfigList[idx].enemyID != changedEnemyID) { candidate = idx; break; }
|
|
}
|
|
if (candidate == -1)
|
|
{
|
|
for (int i = activeIndices.Count - 1; i >= 0; i--)
|
|
{
|
|
int idx = activeIndices[i];
|
|
if (idx == changedIndex) continue;
|
|
candidate = idx;
|
|
break;
|
|
}
|
|
}
|
|
if (candidate != -1) remainderIndex = candidate;
|
|
}
|
|
|
|
int sumOthers = 0;
|
|
for (int i = 0; i < activeIndices.Count; i++)
|
|
{
|
|
int idx = activeIndices[i];
|
|
if (idx == remainderIndex) continue;
|
|
sumOthers += chart.enemyConfigList[idx].hpPercentage;
|
|
}
|
|
|
|
int overflow = sumOthers - 100;
|
|
if (overflow > 0)
|
|
{
|
|
for (int i = activeIndices.Count - 1; i >= 0 && overflow > 0; i--)
|
|
{
|
|
int idx = activeIndices[i];
|
|
if (idx == remainderIndex) continue;
|
|
if (idx == changedIndex) continue;
|
|
var c = chart.enemyConfigList[idx];
|
|
int reduce = Mathf.Min(overflow, c.hpPercentage);
|
|
if (reduce > 0)
|
|
{
|
|
c.hpPercentage -= reduce;
|
|
overflow -= reduce;
|
|
chart.enemyConfigList[idx] = c;
|
|
}
|
|
}
|
|
|
|
if (overflow > 0 && changedIndex >= 0 && changedIndex != remainderIndex)
|
|
{
|
|
var c = chart.enemyConfigList[changedIndex];
|
|
int reduce = Mathf.Min(overflow, c.hpPercentage);
|
|
if (reduce > 0)
|
|
{
|
|
c.hpPercentage -= reduce;
|
|
overflow -= reduce;
|
|
chart.enemyConfigList[changedIndex] = c;
|
|
}
|
|
}
|
|
}
|
|
|
|
sumOthers = 0;
|
|
for (int i = 0; i < activeIndices.Count; i++)
|
|
{
|
|
int idx = activeIndices[i];
|
|
if (idx == remainderIndex) continue;
|
|
sumOthers += chart.enemyConfigList[idx].hpPercentage;
|
|
}
|
|
|
|
int remainder = 100 - sumOthers;
|
|
if (remainder < 0) remainder = 0;
|
|
if (remainder > 100) remainder = 100;
|
|
var r = chart.enemyConfigList[remainderIndex];
|
|
r.hpPercentage = remainder;
|
|
chart.enemyConfigList[remainderIndex] = r;
|
|
}
|
|
|
|
currentSignature.Clear();
|
|
for (int i = 0; i < chart.enemyConfigList.Count; i++)
|
|
{
|
|
var c = chart.enemyConfigList[i];
|
|
if (c.enemyID == 0) currentSignature.Add(0L);
|
|
else currentSignature.Add(((long)c.enemyID << 32) | (uint)c.hpPercentage);
|
|
}
|
|
enemyConfigSignatureCache[chart.difficulty] = currentSignature;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
if (difficultyNumberMap == null) difficultyNumberMap = new Dictionary<int, int>();
|
|
if (personalRecordMap == null) personalRecordMap = new Dictionary<int, int>();
|
|
if (idolRecordMap == null) idolRecordMap = new Dictionary<int, int>();
|
|
if (chartScoreMap == null) chartScoreMap = new Dictionary<int, int>();
|
|
if (chartFileMap == null) chartFileMap = new Dictionary<int, TextAsset>();
|
|
if (chartFiles == null) chartFiles = new List<ChartFileEntry>();
|
|
|
|
SyncRecordsFromChartFiles();
|
|
SyncChartFileMap();
|
|
}
|
|
|
|
public int CalculateHighestPersonalRecord()
|
|
{
|
|
if (personalRecordMap == null) personalRecordMap = new Dictionary<int, int>();
|
|
if (idolRecordMap == null) idolRecordMap = new Dictionary<int, int>();
|
|
|
|
int highest = 0;
|
|
foreach (var kvp in personalRecordMap)
|
|
{
|
|
int diff = kvp.Key;
|
|
int p = kvp.Value;
|
|
int i = idolRecordMap.ContainsKey(diff) ? idolRecordMap[diff] : 0;
|
|
int combined = p + i;
|
|
if (combined > highest)
|
|
highest = combined;
|
|
}
|
|
|
|
personalRecord = highest;
|
|
return highest;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 将数据保存到持久化存储,并附加 MD5 校验和防止篡改。
|
|
/// </summary>
|
|
public void SavePersistent()
|
|
{
|
|
try
|
|
{
|
|
string path = System.IO.Path.Combine(Application.persistentDataPath, $"SongData_{songID}.json");
|
|
SongDataSerializable serializable = new SongDataSerializable(this);
|
|
|
|
// 1. 序列化基础数据
|
|
string jsonWithoutHash = JsonUtility.ToJson(serializable);
|
|
|
|
// 2. 计算 MD5 (使用自定义盐值提高安全性)
|
|
serializable.dataHash = CalculateMD5(jsonWithoutHash + "bansonic2026@fudongyouxi");
|
|
|
|
// 3. 再次序列化包含 Hash 的最终数据
|
|
string finalJson = JsonUtility.ToJson(serializable, true);
|
|
System.IO.File.WriteAllText(path, finalJson);
|
|
|
|
#if UNITY_EDITOR
|
|
if (!Application.isPlaying)
|
|
{
|
|
UnityEditor.EditorUtility.SetDirty(this);
|
|
UnityEditor.AssetDatabase.SaveAssets();
|
|
}
|
|
#endif
|
|
Debug.Log($"[SongData] {songName} saved with hash validation.");
|
|
}
|
|
catch (System.Exception e)
|
|
{
|
|
Debug.LogError($"[SongData] Save failed: {e.Message}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 从持久化 JSON 恢复数据。
|
|
/// 校验逻辑已迁移至 DataCheck 脚本,此处仅执行基础加载。
|
|
/// </summary>
|
|
public void LoadPersistent()
|
|
{
|
|
string path = System.IO.Path.Combine(Application.persistentDataPath, $"SongData_{songID}.json");
|
|
if (System.IO.File.Exists(path))
|
|
{
|
|
try
|
|
{
|
|
string json = System.IO.File.ReadAllText(path);
|
|
// 尝试解析数据
|
|
SongDataSerializable serializable = JsonUtility.FromJson<SongDataSerializable>(json);
|
|
if (serializable != null)
|
|
{
|
|
serializable.ApplyTo(this);
|
|
// Debug.Log($"[SongData] {songName} data restored.");
|
|
}
|
|
}
|
|
catch (System.Exception e)
|
|
{
|
|
Debug.LogWarning($"[SongData] {songName} 基础加载跳过: {e.Message}");
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// 当检测到篡改或文件损坏时,重置所有动态记录并立即重新保存文件以恢复合法性。
|
|
/// </summary>
|
|
private void ResetToZeroAndSave()
|
|
{
|
|
// 1. 重置所有动态数值字段
|
|
game_enterTimes = 0;
|
|
time_totalPlayingTime = 0;
|
|
current_levelProgress = 0;
|
|
_if_level_is_EASE = false;
|
|
max_comboRecord = 0;
|
|
personalRecord = 0;
|
|
|
|
// 2. 清空并确保初始化所有动态字典映射
|
|
if (difficultyNumberMap == null) difficultyNumberMap = new Dictionary<int, int>();
|
|
else difficultyNumberMap.Clear();
|
|
|
|
if (personalRecordMap == null) personalRecordMap = new Dictionary<int, int>();
|
|
else personalRecordMap.Clear();
|
|
|
|
if (idolRecordMap == null) idolRecordMap = new Dictionary<int, int>();
|
|
else idolRecordMap.Clear();
|
|
|
|
if (chartScoreMap == null) chartScoreMap = new Dictionary<int, int>();
|
|
else chartScoreMap.Clear();
|
|
|
|
// 3. 立即调用保存方法,生成一个新的、带有正确哈希值的合法文件
|
|
SavePersistent();
|
|
|
|
Debug.LogWarning($"[SongData] {songName} has been fully reset to zero due to data integrity failure.");
|
|
}
|
|
|
|
/// <summary>
|
|
/// 静态校验方法,可在异步线程调用,判断 JSON 内容是否合法。
|
|
/// </summary>
|
|
public static bool VerifyJsonIntegrity(string json, string salt, out SongDataSerializable result)
|
|
{
|
|
result = null;
|
|
try
|
|
{
|
|
SongDataSerializable serializable = JsonUtility.FromJson<SongDataSerializable>(json);
|
|
if (serializable == null) return false;
|
|
|
|
string savedHash = serializable.dataHash;
|
|
serializable.dataHash = "";
|
|
string currentJson = JsonUtility.ToJson(serializable);
|
|
|
|
// 使用静态 MD5 计算
|
|
string calculatedHash = StaticCalculateMD5(currentJson + salt);
|
|
|
|
result = serializable;
|
|
return savedHash == calculatedHash;
|
|
}
|
|
catch
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static string StaticCalculateMD5(string input)
|
|
{
|
|
using (System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create())
|
|
{
|
|
byte[] inputBytes = System.Text.Encoding.UTF8.GetBytes(input);
|
|
byte[] hashBytes = md5.ComputeHash(inputBytes);
|
|
return System.BitConverter.ToString(hashBytes).Replace("-", "").ToLower();
|
|
}
|
|
}
|
|
|
|
private string CalculateMD5(string input)
|
|
{
|
|
return StaticCalculateMD5(input);
|
|
}
|
|
|
|
public void UpdateDifficultyRecord(int difficulty, int pmScore, int idolScore)
|
|
{
|
|
if (personalRecordMap == null) personalRecordMap = new Dictionary<int, int>();
|
|
if (idolRecordMap == null) idolRecordMap = new Dictionary<int, int>();
|
|
|
|
int currentBestTotal = GetPersonalRecord(difficulty) + GetIdolRecord(difficulty);
|
|
int newTotal = pmScore + idolScore;
|
|
if (newTotal <= currentBestTotal)
|
|
return;
|
|
|
|
personalRecordMap[difficulty] = pmScore;
|
|
idolRecordMap[difficulty] = idolScore;
|
|
|
|
ChartFileEntry entry = chartFiles != null ? chartFiles.Find(e => e != null && e.difficulty == difficulty) : null;
|
|
if (entry != null)
|
|
{
|
|
entry.chartPersonalRecordForThisDifficulty = pmScore;
|
|
entry.idolPersonalRecordForThisDifficulty = idolScore;
|
|
entry.totalPersonalRecordForThisDifficulty = newTotal;
|
|
}
|
|
|
|
CalculateHighestPersonalRecord();
|
|
}
|
|
|
|
public void ApplySettlementResult(int difficulty, int pmScore, int idolScore, int maxScoreSum)
|
|
{
|
|
if (difficulty < 0) return;
|
|
|
|
if (personalRecordMap == null) personalRecordMap = new Dictionary<int, int>();
|
|
if (idolRecordMap == null) idolRecordMap = new Dictionary<int, int>();
|
|
if (chartScoreMap == null) chartScoreMap = new Dictionary<int, int>();
|
|
|
|
int total = pmScore + idolScore;
|
|
int currentBestTotal = GetPersonalRecord(difficulty) + GetIdolRecord(difficulty);
|
|
bool isNewTotalRecord = total > currentBestTotal;
|
|
|
|
if (isNewTotalRecord)
|
|
{
|
|
personalRecordMap[difficulty] = pmScore;
|
|
idolRecordMap[difficulty] = idolScore;
|
|
}
|
|
|
|
ChartFileEntry entry = chartFiles != null ? chartFiles.Find(e => e != null && e.difficulty == difficulty) : null;
|
|
if (entry != null)
|
|
{
|
|
if (isNewTotalRecord)
|
|
{
|
|
entry.chartPersonalRecordForThisDifficulty = pmScore;
|
|
entry.idolPersonalRecordForThisDifficulty = idolScore;
|
|
entry.totalPersonalRecordForThisDifficulty = total;
|
|
}
|
|
|
|
float newProgress = maxScoreSum > 0 ? Mathf.Clamp01((float)total / (float)maxScoreSum) : 0f;
|
|
if (newProgress > entry.levelProgressForThisDifficulty)
|
|
{
|
|
entry.levelProgressForThisDifficulty = newProgress;
|
|
}
|
|
|
|
entry.lastScoreForThisDifficulty = total;
|
|
}
|
|
|
|
chartScoreMap[difficulty] = total;
|
|
|
|
UpdateOverallRecordsFromEntries();
|
|
ApplySerializableRoundTrip();
|
|
SavePersistent();
|
|
}
|
|
|
|
public void GetAbsoluteHighestScore(out int highestScore, out int bestDifficulty, out string bestDifficultyName)
|
|
{
|
|
highestScore = 0;
|
|
bestDifficulty = -1;
|
|
bestDifficultyName = "";
|
|
|
|
if (chartFiles != null)
|
|
{
|
|
for (int i = 0; i < chartFiles.Count; i++)
|
|
{
|
|
ChartFileEntry entry = chartFiles[i];
|
|
if (entry == null) continue;
|
|
|
|
int total = GetPersonalRecord(entry.difficulty) + GetIdolRecord(entry.difficulty);
|
|
if (total <= 0) total = entry.totalPersonalRecordForThisDifficulty;
|
|
if (total <= 0) total = entry.chartPersonalRecordForThisDifficulty + entry.idolPersonalRecordForThisDifficulty;
|
|
|
|
if (total > highestScore || bestDifficulty == -1)
|
|
{
|
|
highestScore = total;
|
|
bestDifficulty = entry.difficulty;
|
|
bestDifficultyName = !string.IsNullOrEmpty(entry.difficultyName) ? entry.difficultyName : GetDifficultyDefaultName(entry.difficulty);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (bestDifficulty != -1 || personalRecordMap == null)
|
|
return;
|
|
|
|
foreach (var kvp in personalRecordMap)
|
|
{
|
|
int diff = kvp.Key;
|
|
int total = kvp.Value + GetIdolRecord(diff);
|
|
if (total > highestScore || bestDifficulty == -1)
|
|
{
|
|
highestScore = total;
|
|
bestDifficulty = diff;
|
|
bestDifficultyName = GetDifficultyDefaultName(diff);
|
|
}
|
|
}
|
|
}
|
|
|
|
private string GetDifficultyDefaultName(int difficulty)
|
|
{
|
|
switch (difficulty)
|
|
{
|
|
case 0: return "Easy";
|
|
case 1: return "Hard";
|
|
case 2: return "Incredible";
|
|
case 3: return "Impossible";
|
|
default: return "Unknown";
|
|
}
|
|
}
|
|
|
|
public void UpdatePersonalRecord(int difficulty, int newScore)
|
|
{
|
|
if (personalRecordMap == null) personalRecordMap = new Dictionary<int, int>();
|
|
if (!personalRecordMap.ContainsKey(difficulty) || newScore > personalRecordMap[difficulty])
|
|
personalRecordMap[difficulty] = newScore;
|
|
|
|
ChartFileEntry entry = chartFiles != null ? chartFiles.Find(e => e != null && e.difficulty == difficulty) : null;
|
|
if (entry != null)
|
|
{
|
|
entry.chartPersonalRecordForThisDifficulty = personalRecordMap[difficulty];
|
|
int idol = idolRecordMap != null && idolRecordMap.ContainsKey(difficulty) ? idolRecordMap[difficulty] : 0;
|
|
entry.totalPersonalRecordForThisDifficulty = personalRecordMap[difficulty] + idol;
|
|
}
|
|
|
|
CalculateHighestPersonalRecord();
|
|
}
|
|
|
|
private void UpdateOverallRecordsFromEntries()
|
|
{
|
|
int highestTotal = 0;
|
|
float highestProgress = 0f;
|
|
|
|
if (chartFiles != null && chartFiles.Count > 0)
|
|
{
|
|
for (int i = 0; i < chartFiles.Count; i++)
|
|
{
|
|
ChartFileEntry entry = chartFiles[i];
|
|
if (entry == null) continue;
|
|
|
|
int total = entry.totalPersonalRecordForThisDifficulty;
|
|
if (total <= 0)
|
|
{
|
|
int p = GetPersonalRecord(entry.difficulty);
|
|
int idol = GetIdolRecord(entry.difficulty);
|
|
total = p + idol;
|
|
}
|
|
|
|
if (total > highestTotal)
|
|
{
|
|
highestTotal = total;
|
|
}
|
|
|
|
if (entry.levelProgressForThisDifficulty > highestProgress)
|
|
{
|
|
highestProgress = entry.levelProgressForThisDifficulty;
|
|
}
|
|
}
|
|
|
|
personalRecord = highestTotal;
|
|
current_levelProgress = highestProgress;
|
|
return;
|
|
}
|
|
|
|
if (personalRecordMap != null && personalRecordMap.Count > 0)
|
|
{
|
|
foreach (var kvp in personalRecordMap)
|
|
{
|
|
int diff = kvp.Key;
|
|
int total = kvp.Value + GetIdolRecord(diff);
|
|
if (total > highestTotal) highestTotal = total;
|
|
}
|
|
personalRecord = highestTotal;
|
|
}
|
|
}
|
|
|
|
private void ApplySerializableRoundTrip()
|
|
{
|
|
SongDataSerializable serializable = new SongDataSerializable(this);
|
|
string json = JsonUtility.ToJson(serializable);
|
|
SongDataSerializable roundTrip = JsonUtility.FromJson<SongDataSerializable>(json);
|
|
if (roundTrip != null) roundTrip.ApplyTo(this);
|
|
}
|
|
|
|
public void UpdateIdolRecord(int difficulty, int newIdolScore)
|
|
{
|
|
if (idolRecordMap == null) idolRecordMap = new Dictionary<int, int>();
|
|
if (!idolRecordMap.ContainsKey(difficulty) || newIdolScore > idolRecordMap[difficulty])
|
|
idolRecordMap[difficulty] = newIdolScore;
|
|
|
|
ChartFileEntry entry = chartFiles != null ? chartFiles.Find(e => e != null && e.difficulty == difficulty) : null;
|
|
if (entry != null)
|
|
{
|
|
entry.idolPersonalRecordForThisDifficulty = idolRecordMap[difficulty];
|
|
int personal = personalRecordMap != null && personalRecordMap.ContainsKey(difficulty) ? personalRecordMap[difficulty] : 0;
|
|
entry.totalPersonalRecordForThisDifficulty = personal + idolRecordMap[difficulty];
|
|
}
|
|
|
|
CalculateHighestPersonalRecord();
|
|
}
|
|
|
|
public void UpdateChartScore(int difficulty, int newChartScore)
|
|
{
|
|
if (chartScoreMap == null) chartScoreMap = new Dictionary<int, int>();
|
|
chartScoreMap[difficulty] = newChartScore;
|
|
|
|
ChartFileEntry entry = chartFiles != null ? chartFiles.Find(e => e != null && e.difficulty == difficulty) : null;
|
|
if (entry != null)
|
|
entry.lastScoreForThisDifficulty = newChartScore;
|
|
}
|
|
|
|
public int GetPersonalRecord(int difficulty)
|
|
{
|
|
if (personalRecordMap == null) return 0;
|
|
return personalRecordMap.TryGetValue(difficulty, out int v) ? v : 0;
|
|
}
|
|
|
|
public int GetIdolRecord(int difficulty)
|
|
{
|
|
if (idolRecordMap == null) return 0;
|
|
return idolRecordMap.TryGetValue(difficulty, out int v) ? v : 0;
|
|
}
|
|
|
|
public int GetChartScore(int difficulty)
|
|
{
|
|
if (chartScoreMap == null) return 0;
|
|
return chartScoreMap.TryGetValue(difficulty, out int v) ? v : 0;
|
|
}
|
|
|
|
public TextAsset GetChartFile(int difficulty)
|
|
{
|
|
if (chartFiles != null)
|
|
{
|
|
for (int i = 0; i < chartFiles.Count; i++)
|
|
{
|
|
ChartFileEntry entry = chartFiles[i];
|
|
if (entry != null && entry.difficulty == difficulty)
|
|
return entry.chartFile;
|
|
}
|
|
}
|
|
|
|
if (chartFileMap != null && chartFileMap.TryGetValue(difficulty, out TextAsset mapped))
|
|
return mapped;
|
|
|
|
return null;
|
|
}
|
|
|
|
public void SyncChartFileMap()
|
|
{
|
|
if (chartFileMap == null) chartFileMap = new Dictionary<int, TextAsset>();
|
|
chartFileMap.Clear();
|
|
|
|
if (chartFiles == null) return;
|
|
for (int i = 0; i < chartFiles.Count; i++)
|
|
{
|
|
ChartFileEntry entry = chartFiles[i];
|
|
if (entry != null && entry.chartFile != null)
|
|
chartFileMap[entry.difficulty] = entry.chartFile;
|
|
}
|
|
}
|
|
|
|
public void SyncRecordsFromChartFiles()
|
|
{
|
|
if (personalRecordMap == null) personalRecordMap = new Dictionary<int, int>();
|
|
if (idolRecordMap == null) idolRecordMap = new Dictionary<int, int>();
|
|
if (chartScoreMap == null) chartScoreMap = new Dictionary<int, int>();
|
|
|
|
if (chartFiles == null) return;
|
|
|
|
for (int i = 0; i < chartFiles.Count; i++)
|
|
{
|
|
ChartFileEntry entry = chartFiles[i];
|
|
if (entry == null) continue;
|
|
|
|
if (!difficultyNumberMap.ContainsKey(entry.difficulty))
|
|
difficultyNumberMap[entry.difficulty] = Mathf.RoundToInt(entry.difficultyLEVEL);
|
|
|
|
if (!personalRecordMap.ContainsKey(entry.difficulty) || entry.chartPersonalRecordForThisDifficulty > personalRecordMap[entry.difficulty])
|
|
personalRecordMap[entry.difficulty] = entry.chartPersonalRecordForThisDifficulty;
|
|
|
|
if (!idolRecordMap.ContainsKey(entry.difficulty) || entry.idolPersonalRecordForThisDifficulty > idolRecordMap[entry.difficulty])
|
|
idolRecordMap[entry.difficulty] = entry.idolPersonalRecordForThisDifficulty;
|
|
|
|
if (!chartScoreMap.ContainsKey(entry.difficulty) || entry.lastScoreForThisDifficulty > chartScoreMap[entry.difficulty])
|
|
chartScoreMap[entry.difficulty] = entry.lastScoreForThisDifficulty;
|
|
|
|
int p = personalRecordMap.ContainsKey(entry.difficulty) ? personalRecordMap[entry.difficulty] : 0;
|
|
int idol = idolRecordMap.ContainsKey(entry.difficulty) ? idolRecordMap[entry.difficulty] : 0;
|
|
entry.totalPersonalRecordForThisDifficulty = p + idol;
|
|
}
|
|
|
|
CalculateHighestPersonalRecord();
|
|
}
|
|
}
|