Files
bansonic_beta_main/Assets/songsDatabase/SongData.cs
T

959 lines
36 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
{
private const string SecureSaveCategory = "song_runtime";
public string usernameID = "user_TestUser@FloatGaming";
public string songName;
public int songID;
public bool isUnlocked;
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, float> levelProgressMap = new Dictionary<int, float>();
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;
private bool _isPersistentDataLoaded = false;
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 (levelProgressMap == null) levelProgressMap = new Dictionary<int, float>();
if (chartFileMap == null) chartFileMap = new Dictionary<int, TextAsset>();
if (chartFiles == null) chartFiles = new List<ChartFileEntry>();
// 灏濊瘯浠庢寔涔呭寲瀛樺偍鍔犺浇鏁版嵁
LoadPersistent();
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()
{
if (songID == 0)
{
Debug.LogWarning($"[SongData] {songName} has songID=0. Saving to 'SongData_0.json' may overwrite other songs!");
}
try
{
// 鍦ㄤ繚瀛樺墠纭繚 chartFiles 宸插悓姝ワ紝杩欐牱鍦ㄧ紪杈戝櫒涓煡鐪?SO 鏃舵暟鎹篃鏄渶鏂扮殑
SyncEntriesFromMaps();
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);
SecureSaveVault.SaveRawJson(SecureSaveCategory, songID.ToString(), finalJson, GetLegacySavePath());
Debug.Log($"[SongData] {songName} (ID:{songID}) saved to secure vault.");
#if UNITY_EDITOR
if (!Application.isPlaying)
{
UnityEditor.EditorUtility.SetDirty(this);
UnityEditor.AssetDatabase.SaveAssets();
}
#endif
}
catch (System.Exception e)
{
Debug.LogError($"[SongData] Save failed: {e.Message}");
}
}
public void SetUnlocked(bool value)
{
if (isUnlocked == value)
{
return;
}
isUnlocked = value;
#if UNITY_EDITOR
if (!Application.isPlaying)
{
UnityEditor.EditorUtility.SetDirty(this);
}
#endif
}
/// <summary>
/// 浠庢寔涔呭寲 JSON 鎭㈠鏁版嵁銆? /// 鏍¢獙閫昏緫宸茶縼绉昏嚦 DataCheck 鑴氭湰锛屾澶勪粎鎵ц鍩虹鍔犺浇銆? /// </summary>
public void LoadPersistent()
{
if (_isPersistentDataLoaded) return;
string json;
if (SecureSaveVault.TryLoadRawJson(SecureSaveCategory, songID.ToString(), out json, GetLegacySavePath()))
{
try
{
// 灏濊瘯瑙f瀽鏁版嵁
SongDataSerializable serializable = JsonUtility.FromJson<SongDataSerializable>(json);
if (serializable != null)
{
serializable.ApplyTo(this);
SyncEntriesFromMaps();
_isPersistentDataLoaded = true;
Debug.Log($"[SongData] {songName} (ID:{songID}) data restored from persistent storage.");
}
}
catch (System.Exception e)
{
Debug.LogWarning($"[SongData] {songName} 鍩虹鍔犺浇澶辫触: {e.Message}");
}
}
else
{
ResetRuntimeProgressStateWithoutSaving();
_isPersistentDataLoaded = true;
}
}
public void ClearSaveDataAndReload()
{
if (personalRecordMap != null) personalRecordMap.Clear();
else personalRecordMap = new Dictionary<int, int>();
if (idolRecordMap != null) idolRecordMap.Clear();
else idolRecordMap = new Dictionary<int, int>();
if (chartScoreMap != null) chartScoreMap.Clear();
else chartScoreMap = new Dictionary<int, int>();
if (levelProgressMap != null) levelProgressMap.Clear();
else levelProgressMap = new Dictionary<int, float>();
if (chartFiles != null)
{
for (int i = 0; i < chartFiles.Count; i++)
{
ChartFileEntry entry = chartFiles[i];
if (entry == null) continue;
entry.lastScoreForThisDifficulty = 0;
entry.chartPersonalRecordForThisDifficulty = 0;
entry.idolPersonalRecordForThisDifficulty = 0;
entry.totalPersonalRecordForThisDifficulty = 0;
entry.levelProgressForThisDifficulty = 0f;
int diff = entry.difficulty;
personalRecordMap[diff] = 0;
idolRecordMap[diff] = 0;
chartScoreMap[diff] = 0;
levelProgressMap[diff] = 0f;
}
}
if (difficultyNumberMap != null && difficultyNumberMap.Count > 0)
{
foreach (var kvp in difficultyNumberMap)
{
int diff = kvp.Key;
if (!personalRecordMap.ContainsKey(diff)) personalRecordMap[diff] = 0;
if (!idolRecordMap.ContainsKey(diff)) idolRecordMap[diff] = 0;
if (!chartScoreMap.ContainsKey(diff)) chartScoreMap[diff] = 0;
if (!levelProgressMap.ContainsKey(diff)) levelProgressMap[diff] = 0f;
}
}
game_enterTimes = 0;
time_totalPlayingTime = 0f;
current_levelProgress = 0f;
_if_level_is_EASE = false;
max_comboRecord = 0;
personalRecord = 0;
UpdateOverallRecordsFromEntries();
SecureSaveVault.Delete(SecureSaveCategory, songID.ToString(), GetLegacySavePath());
SavePersistent();
#if UNITY_EDITOR
if (!Application.isPlaying)
{
UnityEditor.EditorUtility.SetDirty(this);
}
#endif
}
/// <summary>
/// 褰撴娴嬪埌绡℃敼鎴栨枃浠舵崯鍧忔椂锛岄噸缃墍鏈夊姩鎬佽褰曞苟绔嬪嵆閲嶆柊淇濆瓨鏂囦欢浠ユ仮澶嶅悎娉曟€с€? /// </summary>
private string GetLegacySavePath()
{
return System.IO.Path.Combine(Application.persistentDataPath, $"SongData_{songID}.json");
}
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();
if (levelProgressMap == null) levelProgressMap = new Dictionary<int, float>();
else levelProgressMap.Clear();
// 3. 绔嬪嵆璋冪敤淇濆瓨鏂规硶锛岀敓鎴愪竴涓柊鐨勩€佸甫鏈夋纭搱甯屽€肩殑鍚堟硶鏂囦欢
SavePersistent();
Debug.LogWarning($"[SongData] {songName} has been fully reset to zero due to data integrity failure.");
}
private void ResetRuntimeProgressStateWithoutSaving()
{
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();
if (levelProgressMap == null) levelProgressMap = new Dictionary<int, float>();
else levelProgressMap.Clear();
if (chartFiles != null)
{
for (int i = 0; i < chartFiles.Count; i++)
{
ChartFileEntry entry = chartFiles[i];
if (entry == null) continue;
entry.lastScoreForThisDifficulty = 0;
entry.chartPersonalRecordForThisDifficulty = 0;
entry.idolPersonalRecordForThisDifficulty = 0;
entry.totalPersonalRecordForThisDifficulty = 0;
entry.levelProgressForThisDifficulty = 0f;
}
}
game_enterTimes = 0;
time_totalPlayingTime = 0f;
current_levelProgress = 0f;
_if_level_is_EASE = false;
max_comboRecord = 0;
personalRecord = 0;
UpdateOverallRecordsFromEntries();
}
/// <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>();
if (levelProgressMap == null) levelProgressMap = new Dictionary<int, float>();
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 ? (float)total / (float)maxScoreSum : 0f;
if (newProgress > entry.levelProgressForThisDifficulty)
{
entry.levelProgressForThisDifficulty = newProgress;
}
if (!levelProgressMap.ContainsKey(difficulty) || newProgress > levelProgressMap[difficulty])
{
levelProgressMap[difficulty] = newProgress;
}
entry.lastScoreForThisDifficulty = total;
}
chartScoreMap[difficulty] = total;
SyncEntriesFromMaps();
SavePersistent();
if (Application.isPlaying)
{
GlobalAchievementService.EnsureInstance().RefreshOwnedSongCountAndScores();
}
}
/// <summary>
/// 灏?Dictionary 涓殑鏁版嵁鍚屾鍥?ChartFileEntry 鍒楄〃锛岀‘淇?SO 鍐呭瓨鏁版嵁涓庢寔涔呭寲鏁版嵁涓€鑷淬€? /// </summary>
public void SyncEntriesFromMaps()
{
if (chartFiles == null) return;
foreach (var entry in chartFiles)
{
if (entry == null) continue;
int diff = entry.difficulty;
if (personalRecordMap != null && personalRecordMap.ContainsKey(diff))
entry.chartPersonalRecordForThisDifficulty = personalRecordMap[diff];
if (idolRecordMap != null && idolRecordMap.ContainsKey(diff))
entry.idolPersonalRecordForThisDifficulty = idolRecordMap[diff];
if (personalRecordMap != null && personalRecordMap.ContainsKey(diff) && idolRecordMap != null && idolRecordMap.ContainsKey(diff))
entry.totalPersonalRecordForThisDifficulty = personalRecordMap[diff] + idolRecordMap[diff];
else if (personalRecordMap != null && personalRecordMap.ContainsKey(diff))
entry.totalPersonalRecordForThisDifficulty = personalRecordMap[diff];
if (levelProgressMap != null && levelProgressMap.ContainsKey(diff))
entry.levelProgressForThisDifficulty = levelProgressMap[diff];
if (chartScoreMap != null && chartScoreMap.ContainsKey(diff))
entry.lastScoreForThisDifficulty = chartScoreMap[diff];
}
UpdateOverallRecordsFromEntries();
}
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);
SyncEntriesFromMaps();
}
}
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 (levelProgressMap == null) levelProgressMap = new Dictionary<int, float>();
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;
if (!levelProgressMap.ContainsKey(entry.difficulty) || entry.levelProgressForThisDifficulty > levelProgressMap[entry.difficulty])
levelProgressMap[entry.difficulty] = entry.levelProgressForThisDifficulty;
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();
}
}