959 lines
36 KiB
C#
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();
|
|
}
|
|
}
|
|
|