拼ui 一些业务逻辑x实现
This commit is contained in:
@@ -90,6 +90,8 @@ public class AllyHero_SO : ScriptableObject
|
||||
[Header("Inspector")]
|
||||
public int ally_currentEXP;
|
||||
public int ally_battleDeployCount;
|
||||
public int ally_finishCount;
|
||||
public int ally_mvpCount;
|
||||
|
||||
[Header("Skills")]
|
||||
public SkillDefinition[] availableSkills;
|
||||
@@ -209,7 +211,10 @@ public class AllyHero_SO : ScriptableObject
|
||||
if (isUnlocked == value) return;
|
||||
isUnlocked = value;
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.EditorUtility.SetDirty(this);
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
UnityEditor.EditorUtility.SetDirty(this);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -218,7 +223,10 @@ public class AllyHero_SO : ScriptableObject
|
||||
if (amount <= 0) return;
|
||||
AllyHeroDeployLedger.EnsureInstance().IncrementDeployCount(this, amount);
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.EditorUtility.SetDirty(this);
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
UnityEditor.EditorUtility.SetDirty(this);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -231,4 +239,28 @@ public class AllyHero_SO : ScriptableObject
|
||||
{
|
||||
AllyHeroDeployLedger.EnsureInstance().SaveNow();
|
||||
}
|
||||
|
||||
public void IncrementFinishCount(int amount = 1)
|
||||
{
|
||||
if (amount <= 0) return;
|
||||
AllyHeroDeployLedger.EnsureInstance().IncrementFinishCount(this, amount);
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
UnityEditor.EditorUtility.SetDirty(this);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public void IncrementMvpCount(int amount = 1)
|
||||
{
|
||||
if (amount <= 0) return;
|
||||
AllyHeroDeployLedger.EnsureInstance().IncrementMvpCount(this, amount);
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
UnityEditor.EditorUtility.SetDirty(this);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,7 +189,10 @@ public class Player_SO : ScriptableObject
|
||||
private void PersistEditorChanges()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
UnityEditor.EditorUtility.SetDirty(this);
|
||||
if (!Application.isPlaying)
|
||||
{
|
||||
UnityEditor.EditorUtility.SetDirty(this);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4986,7 +4986,7 @@ MonoBehaviour:
|
||||
showLevel_prefab: {fileID: 775714823646948286, guid: 4c26aec0fc471c24d94487eff6821e14, type: 3}
|
||||
store_prefab: {fileID: 3878406062860244594, guid: d94caf56bd6dff64fa606eeeb6e06fa9, type: 3}
|
||||
settings_prefab: {fileID: 4801108313180107556, guid: 8db6dd820b152984980f7fd2124138c3, type: 3}
|
||||
userInfo_prefab: {fileID: 0}
|
||||
userInfo_prefab: {fileID: 5155954718781159675, guid: 18f4d2367ef2dff429599f1580fd6bad, type: 3}
|
||||
email_prefab: {fileID: 3756075665884320709, guid: 41f4ea31b64f18d48aeef21b79930a6c, type: 3}
|
||||
notice_prefab: {fileID: 8527835049849151044, guid: 06bb6d3a45697374ab4f5ff36356d138, type: 3}
|
||||
back_navButton: {fileID: 0}
|
||||
|
||||
@@ -10,6 +10,11 @@ using Steamworks;
|
||||
|
||||
public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
{
|
||||
public static event System.Action<bool> GlobalSettingsVisibilityChanged;
|
||||
public static bool CurrentSettingsVisible { get; private set; }
|
||||
|
||||
public event System.Action<bool> SettingsVisibilityChanged;
|
||||
|
||||
[Header("player unique so")]
|
||||
public Player_SO player_SO;
|
||||
public Text playerCoins_legacy;
|
||||
@@ -98,6 +103,7 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
|
||||
// cached reference to the settings instance to ensure only one exists
|
||||
private GameObject settingsInstance;
|
||||
private GameObject userInfoInstance;
|
||||
private GameObject storeInstance;
|
||||
private GameObject showLevelInstance;
|
||||
private GameObject emailInstance;
|
||||
@@ -106,6 +112,7 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
private Coroutine musicPicFade;
|
||||
private bool musicPicVisible = true;
|
||||
private bool navSceneLoading = false;
|
||||
private bool lastSettingsVisibilityState;
|
||||
private readonly Dictionary<string, int> guideIndexByScene = new Dictionary<string, int>();
|
||||
private string currentGuideScene = string.Empty;
|
||||
|
||||
@@ -137,7 +144,7 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
}
|
||||
}
|
||||
instantiateSettings = () => ToggleSettingsPrefab();
|
||||
instantiateUserInfo = () => { gNotice.recommendation.display("功能即将上线,敬请期待"); };
|
||||
instantiateUserInfo = () => ToggleUserInfoPrefab();
|
||||
instantiateStore = () => ShowStorePrefab();
|
||||
instantiateShowLevel = () => { gNotice.error.display("功能即将下线,禁止访问"); };
|
||||
// instantiateShowLevel = () => ShowLevelPrefab();
|
||||
@@ -202,6 +209,7 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
{
|
||||
settingsInstance = Instantiate(settings_prefab, putPrefabsHere.transform);
|
||||
EnsureSettingsEnterAnimator(settingsInstance);
|
||||
EnsureSettingsLastSibling();
|
||||
settingsInstance.SetActive(false);
|
||||
|
||||
// try to set canvas camera now as in previous behavior
|
||||
@@ -225,10 +233,39 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
{
|
||||
// ensure it's parented correctly under putPrefabsHere
|
||||
settingsInstance.transform.SetParent(putPrefabsHere.transform, false);
|
||||
EnsureSettingsLastSibling();
|
||||
EnsureSettingsEnterAnimator(settingsInstance);
|
||||
settingsInstance.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (userInfo_prefab != null && putPrefabsHere != null)
|
||||
{
|
||||
if (userInfoInstance == null)
|
||||
{
|
||||
var existing = GameObject.Find(userInfo_prefab.name + "(Clone)");
|
||||
if (existing != null)
|
||||
{
|
||||
userInfoInstance = existing;
|
||||
}
|
||||
}
|
||||
|
||||
if (userInfoInstance == null)
|
||||
{
|
||||
userInfoInstance = Instantiate(userInfo_prefab, putPrefabsHere.transform);
|
||||
TryAssignCanvasCamera(userInfoInstance);
|
||||
PlacePanelBelowSettings(userInfoInstance);
|
||||
userInfoInstance.SetActive(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
userInfoInstance.transform.SetParent(putPrefabsHere.transform, false);
|
||||
PlacePanelBelowSettings(userInfoInstance);
|
||||
userInfoInstance.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
lastSettingsVisibilityState = IsSettingsPanelVisible;
|
||||
}
|
||||
|
||||
|
||||
@@ -240,6 +277,26 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!IsUiUiSceneActive())
|
||||
{
|
||||
if (CurrentSettingsVisible)
|
||||
{
|
||||
BroadcastSettingsVisibility(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
bool visible = IsSettingsPanelVisible;
|
||||
if (visible == lastSettingsVisibilityState)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
BroadcastSettingsVisibility(visible);
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void ToggleMusicPic()
|
||||
@@ -581,6 +638,7 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
{
|
||||
settingsInstance = Instantiate(settings_prefab, putPrefabsHere.transform);
|
||||
EnsureSettingsEnterAnimator(settingsInstance);
|
||||
EnsureSettingsLastSibling();
|
||||
|
||||
// attempt to set canvas camera
|
||||
try
|
||||
@@ -600,43 +658,111 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
catch { }
|
||||
|
||||
settingsInstance.SetActive(true);
|
||||
EnsureSettingsLastSibling();
|
||||
BroadcastSettingsVisibility(true);
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureSettingsEnterAnimator(settingsInstance);
|
||||
settingsInstance.transform.SetParent(putPrefabsHere.transform, false);
|
||||
EnsureSettingsLastSibling();
|
||||
|
||||
// Toggle active state
|
||||
bool active = settingsInstance.activeSelf;
|
||||
settingsInstance.SetActive(!active);
|
||||
if (settingsInstance.activeSelf)
|
||||
{
|
||||
EnsureSettingsLastSibling();
|
||||
}
|
||||
BroadcastSettingsVisibility(settingsInstance.activeSelf);
|
||||
}
|
||||
|
||||
public bool IsSettingsPanelVisible
|
||||
{
|
||||
get { return settingsInstance != null && settingsInstance.activeInHierarchy; }
|
||||
}
|
||||
|
||||
private void ToggleUserInfoPrefab()
|
||||
{
|
||||
if (userInfo_prefab == null || putPrefabsHere == null) return;
|
||||
|
||||
if (userInfoInstance == null)
|
||||
{
|
||||
userInfoInstance = Instantiate(userInfo_prefab, putPrefabsHere.transform);
|
||||
TryAssignCanvasCamera(userInfoInstance);
|
||||
PlacePanelBelowSettings(userInfoInstance);
|
||||
userInfoInstance.SetActive(true);
|
||||
return;
|
||||
}
|
||||
|
||||
userInfoInstance.transform.SetParent(putPrefabsHere.transform, false);
|
||||
userInfoInstance.SetActive(!userInfoInstance.activeSelf);
|
||||
if (userInfoInstance.activeSelf)
|
||||
{
|
||||
PlacePanelBelowSettings(userInfoInstance);
|
||||
}
|
||||
}
|
||||
|
||||
private void BroadcastSettingsVisibility(bool visible)
|
||||
{
|
||||
lastSettingsVisibilityState = visible;
|
||||
if (CurrentSettingsVisible == visible)
|
||||
{
|
||||
SettingsVisibilityChanged?.Invoke(visible);
|
||||
return;
|
||||
}
|
||||
|
||||
CurrentSettingsVisible = visible;
|
||||
SettingsVisibilityChanged?.Invoke(visible);
|
||||
GlobalSettingsVisibilityChanged?.Invoke(visible);
|
||||
}
|
||||
|
||||
private bool IsUiUiSceneActive()
|
||||
{
|
||||
string sceneName = SceneManager.GetActiveScene().name;
|
||||
string targetScene = string.IsNullOrWhiteSpace(uiSceneName) ? "UI_UI" : uiSceneName;
|
||||
return string.Equals(sceneName, targetScene, System.StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private void ShowLevelPrefab()
|
||||
{
|
||||
ShowPrefab(showLevel_prefab, ref showLevelInstance);
|
||||
CloseInfoPanels(showLevelInstance);
|
||||
bool opened = ShowPrefab(showLevel_prefab, ref showLevelInstance);
|
||||
if (opened)
|
||||
{
|
||||
CloseInfoPanels(showLevelInstance);
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowStorePrefab()
|
||||
{
|
||||
ShowPrefab(store_prefab, ref storeInstance);
|
||||
CloseInfoPanels(storeInstance);
|
||||
bool opened = ShowPrefab(store_prefab, ref storeInstance);
|
||||
if (opened)
|
||||
{
|
||||
CloseInfoPanels(storeInstance);
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowEmailPrefab()
|
||||
{
|
||||
ShowPrefab(email_prefab, ref emailInstance);
|
||||
CloseInfoPanels(emailInstance);
|
||||
bool opened = ShowPrefab(email_prefab, ref emailInstance);
|
||||
if (opened)
|
||||
{
|
||||
CloseInfoPanels(emailInstance);
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowNoticePrefab()
|
||||
{
|
||||
ShowPrefab(notice_prefab, ref noticeInstance);
|
||||
CloseInfoPanels(noticeInstance);
|
||||
bool opened = ShowPrefab(notice_prefab, ref noticeInstance);
|
||||
if (opened)
|
||||
{
|
||||
CloseInfoPanels(noticeInstance);
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowPrefab(GameObject prefab, ref GameObject instance)
|
||||
private bool ShowPrefab(GameObject prefab, ref GameObject instance)
|
||||
{
|
||||
if (prefab == null || putPrefabsHere == null) return;
|
||||
if (prefab == null || putPrefabsHere == null) return false;
|
||||
|
||||
if (instance == null)
|
||||
{
|
||||
@@ -652,8 +778,48 @@ public class btmandtopController : MonoBehaviour, ICancelHandler
|
||||
}
|
||||
}
|
||||
|
||||
instance.SetActive(true);
|
||||
instance.transform.SetAsLastSibling();
|
||||
bool shouldOpen = !instance.activeSelf;
|
||||
instance.SetActive(shouldOpen);
|
||||
if (!shouldOpen)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
PlacePanelBelowSettings(instance);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void EnsureSettingsLastSibling()
|
||||
{
|
||||
if (settingsInstance == null || putPrefabsHere == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
settingsInstance.transform.SetParent(putPrefabsHere.transform, false);
|
||||
settingsInstance.transform.SetAsLastSibling();
|
||||
}
|
||||
|
||||
private void PlacePanelBelowSettings(GameObject instance)
|
||||
{
|
||||
if (instance == null || putPrefabsHere == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
instance.transform.SetParent(putPrefabsHere.transform, false);
|
||||
|
||||
if (settingsInstance == null || instance == settingsInstance)
|
||||
{
|
||||
instance.transform.SetAsLastSibling();
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureSettingsLastSibling();
|
||||
int settingsIndex = settingsInstance.transform.GetSiblingIndex();
|
||||
int targetIndex = Mathf.Clamp(settingsIndex, 0, putPrefabsHere.transform.childCount - 1);
|
||||
instance.transform.SetSiblingIndex(targetIndex);
|
||||
EnsureSettingsLastSibling();
|
||||
}
|
||||
|
||||
private void CloseInfoPanels(GameObject keep)
|
||||
|
||||
@@ -11,7 +11,12 @@ public class loadtopandbottomPrefab: MonoBehaviour
|
||||
{
|
||||
if (top_and_bottom_Panel != null && gameobject_to_Instantiate_below != null)
|
||||
{
|
||||
GameObject instantiated = Instantiate(top_and_bottom_Panel, gameobject_to_Instantiate_below.transform);
|
||||
GameObject instantiated = FindExistingPanelInstance();
|
||||
if (instantiated == null)
|
||||
{
|
||||
instantiated = Instantiate(top_and_bottom_Panel, gameobject_to_Instantiate_below.transform);
|
||||
}
|
||||
|
||||
Canvas canvas = instantiated.GetComponent<Canvas>();
|
||||
if (canvas != null)
|
||||
{
|
||||
@@ -30,6 +35,34 @@ public class loadtopandbottomPrefab: MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
GameObject FindExistingPanelInstance()
|
||||
{
|
||||
if (gameobject_to_Instantiate_below == null || top_and_bottom_Panel == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
string prefabName = top_and_bottom_Panel.name;
|
||||
Transform parent = gameobject_to_Instantiate_below.transform;
|
||||
for (int i = 0; i < parent.childCount; i++)
|
||||
{
|
||||
Transform child = parent.GetChild(i);
|
||||
if (child == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool nameMatches = child.name == prefabName || child.name == prefabName + "(Clone)";
|
||||
bool hasBars = child.Find("TOP") != null || child.Find("BTM") != null;
|
||||
if (nameMatches && hasBars)
|
||||
{
|
||||
return child.gameObject;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
void Bind_Main_Panel(GameObject instantiated)
|
||||
{
|
||||
if (instantiated == null)
|
||||
|
||||
@@ -9,6 +9,8 @@ public sealed class AllyHeroDeployLedger : MonoBehaviour
|
||||
public static AllyHeroDeployLedger Instance { get; private set; }
|
||||
|
||||
private readonly Dictionary<int, int> deployCountsByHeroId = new Dictionary<int, int>();
|
||||
private readonly Dictionary<int, int> finishCountsByHeroId = new Dictionary<int, int>();
|
||||
private readonly Dictionary<int, int> mvpCountsByHeroId = new Dictionary<int, int>();
|
||||
private bool initialized;
|
||||
private bool loadedFromSave;
|
||||
|
||||
@@ -69,7 +71,6 @@ public sealed class AllyHeroDeployLedger : MonoBehaviour
|
||||
loadedFromSave = AllyHeroDeployLedgerStorage.TryLoad(out payload);
|
||||
RebuildFromPayload(payload);
|
||||
initialized = true;
|
||||
SeedFromHeroAssetsIfNeeded();
|
||||
SyncAllMirrorFlags();
|
||||
SaveNow();
|
||||
}
|
||||
@@ -81,6 +82,20 @@ public sealed class AllyHeroDeployLedger : MonoBehaviour
|
||||
return deployCountsByHeroId.TryGetValue(heroId, out count) ? count : 0;
|
||||
}
|
||||
|
||||
public int GetFinishCount(int heroId)
|
||||
{
|
||||
InitializeIfNeeded();
|
||||
int count;
|
||||
return finishCountsByHeroId.TryGetValue(heroId, out count) ? count : 0;
|
||||
}
|
||||
|
||||
public int GetMvpCount(int heroId)
|
||||
{
|
||||
InitializeIfNeeded();
|
||||
int count;
|
||||
return mvpCountsByHeroId.TryGetValue(heroId, out count) ? count : 0;
|
||||
}
|
||||
|
||||
public void IncrementDeployCount(AllyHero_SO hero, int amount = 1)
|
||||
{
|
||||
if (hero == null || hero.ally_heroID <= 0 || amount <= 0)
|
||||
@@ -97,6 +112,38 @@ public sealed class AllyHeroDeployLedger : MonoBehaviour
|
||||
SaveNow();
|
||||
}
|
||||
|
||||
public void IncrementFinishCount(AllyHero_SO hero, int amount = 1)
|
||||
{
|
||||
if (hero == null || hero.ally_heroID <= 0 || amount <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
InitializeIfNeeded();
|
||||
int current = GetFinishCount(hero.ally_heroID);
|
||||
long next = (long)current + amount;
|
||||
finishCountsByHeroId[hero.ally_heroID] = next > int.MaxValue ? int.MaxValue : (int)next;
|
||||
hero.ally_finishCount = finishCountsByHeroId[hero.ally_heroID];
|
||||
MarkDirty(hero);
|
||||
SaveNow();
|
||||
}
|
||||
|
||||
public void IncrementMvpCount(AllyHero_SO hero, int amount = 1)
|
||||
{
|
||||
if (hero == null || hero.ally_heroID <= 0 || amount <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
InitializeIfNeeded();
|
||||
int current = GetMvpCount(hero.ally_heroID);
|
||||
long next = (long)current + amount;
|
||||
mvpCountsByHeroId[hero.ally_heroID] = next > int.MaxValue ? int.MaxValue : (int)next;
|
||||
hero.ally_mvpCount = mvpCountsByHeroId[hero.ally_heroID];
|
||||
MarkDirty(hero);
|
||||
SaveNow();
|
||||
}
|
||||
|
||||
public void SaveNow()
|
||||
{
|
||||
if (!initialized)
|
||||
@@ -111,6 +158,8 @@ public sealed class AllyHeroDeployLedger : MonoBehaviour
|
||||
private void RebuildFromPayload(AllyHeroDeployLedgerPayload payload)
|
||||
{
|
||||
deployCountsByHeroId.Clear();
|
||||
finishCountsByHeroId.Clear();
|
||||
mvpCountsByHeroId.Clear();
|
||||
if (payload == null || payload.entries == null)
|
||||
{
|
||||
return;
|
||||
@@ -125,39 +174,8 @@ public sealed class AllyHeroDeployLedger : MonoBehaviour
|
||||
}
|
||||
|
||||
deployCountsByHeroId[entry.heroId] = Mathf.Max(0, entry.deployCount);
|
||||
}
|
||||
}
|
||||
|
||||
private void SeedFromHeroAssetsIfNeeded()
|
||||
{
|
||||
AllyHero_SO[] heroes = Resources.LoadAll<AllyHero_SO>(string.Empty);
|
||||
bool changed = false;
|
||||
|
||||
for (int i = 0; i < heroes.Length; i++)
|
||||
{
|
||||
AllyHero_SO hero = heroes[i];
|
||||
if (hero == null || hero.ally_heroID <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (deployCountsByHeroId.ContainsKey(hero.ally_heroID))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hero.ally_battleDeployCount <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
deployCountsByHeroId[hero.ally_heroID] = Mathf.Max(0, hero.ally_battleDeployCount);
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed && !loadedFromSave)
|
||||
{
|
||||
SaveNow();
|
||||
finishCountsByHeroId[entry.heroId] = Mathf.Max(0, entry.finishCount);
|
||||
mvpCountsByHeroId[entry.heroId] = Mathf.Max(0, entry.mvpCount);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,25 +196,71 @@ public sealed class AllyHeroDeployLedger : MonoBehaviour
|
||||
count = 0;
|
||||
}
|
||||
|
||||
if (hero.ally_battleDeployCount == count)
|
||||
int finishCount;
|
||||
if (!finishCountsByHeroId.TryGetValue(hero.ally_heroID, out finishCount))
|
||||
{
|
||||
continue;
|
||||
finishCount = 0;
|
||||
}
|
||||
|
||||
hero.ally_battleDeployCount = count;
|
||||
MarkDirty(hero);
|
||||
int mvpCount;
|
||||
if (!mvpCountsByHeroId.TryGetValue(hero.ally_heroID, out mvpCount))
|
||||
{
|
||||
mvpCount = 0;
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
if (hero.ally_battleDeployCount != count)
|
||||
{
|
||||
hero.ally_battleDeployCount = count;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (hero.ally_finishCount != finishCount)
|
||||
{
|
||||
hero.ally_finishCount = finishCount;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (hero.ally_mvpCount != mvpCount)
|
||||
{
|
||||
hero.ally_mvpCount = mvpCount;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
MarkDirty(hero);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private AllyHeroDeployLedgerPayload BuildPayload()
|
||||
{
|
||||
AllyHeroDeployLedgerPayload payload = AllyHeroDeployLedgerStorage.CreateDefaultPayload();
|
||||
HashSet<int> allHeroIds = new HashSet<int>();
|
||||
foreach (KeyValuePair<int, int> pair in deployCountsByHeroId)
|
||||
{
|
||||
allHeroIds.Add(pair.Key);
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<int, int> pair in finishCountsByHeroId)
|
||||
{
|
||||
allHeroIds.Add(pair.Key);
|
||||
}
|
||||
|
||||
foreach (KeyValuePair<int, int> pair in mvpCountsByHeroId)
|
||||
{
|
||||
allHeroIds.Add(pair.Key);
|
||||
}
|
||||
|
||||
foreach (int heroId in allHeroIds)
|
||||
{
|
||||
payload.entries.Add(new AllyHeroDeployEntry
|
||||
{
|
||||
heroId = pair.Key,
|
||||
deployCount = Mathf.Max(0, pair.Value)
|
||||
heroId = heroId,
|
||||
deployCount = Mathf.Max(0, GetDeployCount(heroId)),
|
||||
finishCount = Mathf.Max(0, GetFinishCount(heroId)),
|
||||
mvpCount = Mathf.Max(0, GetMvpCount(heroId))
|
||||
});
|
||||
}
|
||||
|
||||
@@ -206,7 +270,7 @@ public sealed class AllyHeroDeployLedger : MonoBehaviour
|
||||
private static void MarkDirty(AllyHero_SO hero)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (hero != null)
|
||||
if (!Application.isPlaying && hero != null)
|
||||
{
|
||||
EditorUtility.SetDirty(hero);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ public class AllyHeroDeployEntry
|
||||
{
|
||||
public int heroId;
|
||||
public int deployCount;
|
||||
public int finishCount;
|
||||
public int mvpCount;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
|
||||
@@ -82,16 +82,7 @@ public sealed class DushMaterialLedger : MonoBehaviour
|
||||
|
||||
InitializeIfNeeded();
|
||||
boundPlayerData = playerData;
|
||||
|
||||
if (!loadedFromSave)
|
||||
{
|
||||
SeedFromPlayerSo(playerData, false);
|
||||
loadedFromSave = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
SyncToPlayerData();
|
||||
}
|
||||
SyncToPlayerData();
|
||||
}
|
||||
|
||||
public int GetCount(DushMaterialKind kind)
|
||||
|
||||
@@ -93,16 +93,7 @@ public sealed class ExpBottleLedger : MonoBehaviour
|
||||
|
||||
InitializeIfNeeded();
|
||||
boundPlayerData = playerData;
|
||||
|
||||
if (!loadedFromSave)
|
||||
{
|
||||
SeedFromPlayerSo(playerData, false);
|
||||
loadedFromSave = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
SyncToPlayerData();
|
||||
}
|
||||
SyncToPlayerData();
|
||||
}
|
||||
|
||||
public int GetCount(ExpBottleKind kind)
|
||||
|
||||
@@ -83,15 +83,8 @@ public sealed class PlayerEconomyLedger : MonoBehaviour
|
||||
InitializeIfNeeded();
|
||||
boundPlayerData = playerData;
|
||||
|
||||
if (!loadedFromSave)
|
||||
{
|
||||
payload.coins = Mathf.Max(0, playerData.Coins);
|
||||
payload.material = Mathf.Max(0, playerData.Material);
|
||||
SaveNow();
|
||||
loadedFromSave = true;
|
||||
}
|
||||
|
||||
SyncToPlayerData();
|
||||
GlobalAchievementService.EnsureInstance().ReportCurrentCoins(payload.coins);
|
||||
NotifyEconomyChanged();
|
||||
}
|
||||
|
||||
@@ -128,6 +121,7 @@ public sealed class PlayerEconomyLedger : MonoBehaviour
|
||||
InitializeIfNeeded();
|
||||
long next = (long)payload.coins + amount;
|
||||
payload.coins = next > int.MaxValue ? int.MaxValue : (int)next;
|
||||
GlobalAchievementService.EnsureInstance().ReportCoinsEarned(amount);
|
||||
SaveNow();
|
||||
}
|
||||
|
||||
@@ -175,6 +169,7 @@ public sealed class PlayerEconomyLedger : MonoBehaviour
|
||||
InitializeIfNeededForSave();
|
||||
PlayerEconomyStorage.TrySave(payload);
|
||||
SyncToPlayerData();
|
||||
GlobalAchievementService.EnsureInstance().ReportCurrentCoins(payload.coins);
|
||||
NotifyEconomyChanged();
|
||||
}
|
||||
|
||||
|
||||
@@ -5,12 +5,19 @@ using System.Collections.Generic;
|
||||
public class RecentPlayRecord
|
||||
{
|
||||
public string playedAt;
|
||||
public string playedAtUtc;
|
||||
public int songID;
|
||||
public string songName;
|
||||
public string difficultyDisplay;
|
||||
public float accuracy;
|
||||
public float srks;
|
||||
public int totalScore;
|
||||
public int chartScore;
|
||||
public int idolScore;
|
||||
public bool hasScoreBreakdown;
|
||||
public int rankIndex;
|
||||
public int rankTierCount;
|
||||
public bool hasRankMarker;
|
||||
public bool scoreReadable;
|
||||
public bool wasEarlySettlement;
|
||||
public bool wasAllPerfect;
|
||||
|
||||
@@ -14,6 +14,7 @@ public sealed class StoreOwnershipLedger : MonoBehaviour
|
||||
private readonly Dictionary<int, StoreOwnershipEntry> entriesByItemId = new Dictionary<int, StoreOwnershipEntry>();
|
||||
private readonly List<storeItemSO> cachedStoreItems = new List<storeItemSO>();
|
||||
private bool initialized;
|
||||
private int lastSaveFrame = -1;
|
||||
|
||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||
private static void Bootstrap()
|
||||
@@ -68,13 +69,12 @@ public sealed class StoreOwnershipLedger : MonoBehaviour
|
||||
return;
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
StoreOwnershipPayload payload;
|
||||
StoreOwnershipStorage.TryLoad(out payload);
|
||||
RebuildFromPayload(payload);
|
||||
LoadStoreItems();
|
||||
SeedFromCurrentMirrorFlags();
|
||||
SyncAllMirrorFlags();
|
||||
initialized = true;
|
||||
SaveNow();
|
||||
}
|
||||
|
||||
@@ -137,6 +137,7 @@ public sealed class StoreOwnershipLedger : MonoBehaviour
|
||||
}
|
||||
|
||||
ApplyEntryToItem(itemSO, entry);
|
||||
GlobalAchievementService.EnsureInstance().RefreshDerivedMetrics();
|
||||
SaveNow();
|
||||
return true;
|
||||
}
|
||||
@@ -154,6 +155,12 @@ public sealed class StoreOwnershipLedger : MonoBehaviour
|
||||
return;
|
||||
}
|
||||
|
||||
if (Application.isPlaying && lastSaveFrame == Time.frameCount)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
lastSaveFrame = Application.isPlaying ? Time.frameCount : -1;
|
||||
StoreOwnershipStorage.TrySave(CreatePayload());
|
||||
}
|
||||
|
||||
@@ -314,6 +321,8 @@ public sealed class StoreOwnershipLedger : MonoBehaviour
|
||||
|
||||
private void SyncAllMirrorFlags()
|
||||
{
|
||||
ResetAllMirrorFlags();
|
||||
|
||||
for (int i = 0; i < cachedStoreItems.Count; i++)
|
||||
{
|
||||
var item = cachedStoreItems[i];
|
||||
@@ -332,6 +341,68 @@ public sealed class StoreOwnershipLedger : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
private void ResetAllMirrorFlags()
|
||||
{
|
||||
var seenHeroIds = new HashSet<int>();
|
||||
var seenSongIds = new HashSet<int>();
|
||||
var seenStoryIds = new HashSet<int>();
|
||||
|
||||
for (int i = 0; i < cachedStoreItems.Count; i++)
|
||||
{
|
||||
var item = cachedStoreItems[i];
|
||||
if (item == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (item.itemType == storeItemSO.ItemType.character && item.associatedAllyHero != null && seenHeroIds.Add(item.associatedAllyHero.ally_heroID))
|
||||
{
|
||||
if (item.associatedAllyHero.isUnlocked)
|
||||
{
|
||||
item.associatedAllyHero.isUnlocked = false;
|
||||
MarkDirty(item.associatedAllyHero);
|
||||
}
|
||||
}
|
||||
else if (item.itemType == storeItemSO.ItemType.song && item.associatedSong != null && seenSongIds.Add(item.associatedSong.songID))
|
||||
{
|
||||
if (item.associatedSong.isUnlocked)
|
||||
{
|
||||
item.associatedSong.isUnlocked = false;
|
||||
MarkDirty(item.associatedSong);
|
||||
}
|
||||
}
|
||||
else if (item.itemType == storeItemSO.ItemType.storyPassage && item.associatedStoryPassage != null && seenStoryIds.Add(item.associatedStoryPassage.class_id))
|
||||
{
|
||||
var story = item.associatedStoryPassage;
|
||||
bool changed = false;
|
||||
|
||||
if (story.isUnlocked)
|
||||
{
|
||||
story.isUnlocked = false;
|
||||
changed = true;
|
||||
}
|
||||
|
||||
if (story.sonList != null)
|
||||
{
|
||||
for (int sonIndex = 0; sonIndex < story.sonList.Count; sonIndex++)
|
||||
{
|
||||
var son = story.sonList[sonIndex];
|
||||
if (son != null && son.son_isUnlocked)
|
||||
{
|
||||
son.son_isUnlocked = false;
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (changed)
|
||||
{
|
||||
MarkDirty(story);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool ValidateGrantTarget(storeItemSO itemSO, out string failureMessage)
|
||||
{
|
||||
failureMessage = string.Empty;
|
||||
@@ -647,7 +718,7 @@ public sealed class StoreOwnershipLedger : MonoBehaviour
|
||||
private static void MarkDirty(UnityEngine.Object target)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (target != null)
|
||||
if (!Application.isPlaying && target != null)
|
||||
{
|
||||
EditorUtility.SetDirty(target);
|
||||
}
|
||||
|
||||
@@ -150,6 +150,7 @@ public class settlementController : MonoBehaviour
|
||||
private Vector3 cachedIntroMvpBaseLocalPos;
|
||||
private bool hasCachedIntroMvpBaseLocalPos;
|
||||
private bool settlementHistoryRecorded;
|
||||
private bool settlementHeroStatsRecorded;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
@@ -187,6 +188,7 @@ public class settlementController : MonoBehaviour
|
||||
|
||||
RegisterCurrentLineupDeployCount();
|
||||
settlementHistoryRecorded = false;
|
||||
settlementHeroStatsRecorded = false;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
@@ -303,6 +305,179 @@ public class settlementController : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
private void RecordSettlementHeroStats()
|
||||
{
|
||||
if (settlementHeroStatsRecorded)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
settlementHeroStatsRecorded = true;
|
||||
|
||||
List<AllyHero_SO> lineupHeroes = ResolveCurrentLineupHeroSOs();
|
||||
for (int i = 0; i < lineupHeroes.Count; i++)
|
||||
{
|
||||
AllyHero_SO hero = lineupHeroes[i];
|
||||
if (hero == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
hero.IncrementFinishCount();
|
||||
}
|
||||
|
||||
AllyHero_SO mvpHero = ResolveMvpHeroFromTopScorer();
|
||||
if (mvpHero != null)
|
||||
{
|
||||
mvpHero.IncrementMvpCount();
|
||||
}
|
||||
}
|
||||
|
||||
private List<AllyHero_SO> ResolveCurrentLineupHeroSOs()
|
||||
{
|
||||
List<AllyHero_SO> result = new List<AllyHero_SO>();
|
||||
HashSet<int> uniqueHeroIds = new HashSet<int>();
|
||||
|
||||
if (teamUIController.Instance != null && teamUIController.Instance.allySlotIds != null)
|
||||
{
|
||||
for (int i = 0; i < teamUIController.Instance.allySlotIds.Count; i++)
|
||||
{
|
||||
int heroId = teamUIController.Instance.allySlotIds[i];
|
||||
if (heroId > 0)
|
||||
{
|
||||
uniqueHeroIds.Add(heroId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (uniqueHeroIds.Count == 0)
|
||||
{
|
||||
for (int slotIndex = 1; slotIndex <= 5; slotIndex++)
|
||||
{
|
||||
int heroId = PlayerPrefs.GetInt("selected_heroSlot0" + slotIndex + "_heroID", 0);
|
||||
if (heroId > 0)
|
||||
{
|
||||
uniqueHeroIds.Add(heroId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EnsureCachedAllyHeroSOs();
|
||||
|
||||
foreach (int heroId in uniqueHeroIds)
|
||||
{
|
||||
AllyHero_SO hero = FindAllyHeroSOById(heroId);
|
||||
if (hero != null)
|
||||
{
|
||||
result.Add(hero);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private AllyHero_SO ResolveMvpHeroFromTopScorer()
|
||||
{
|
||||
int topIndex = -1;
|
||||
int[] scores = new int[5];
|
||||
|
||||
if (sm != null)
|
||||
{
|
||||
scores[0] = sm.red_idolScore_sum;
|
||||
scores[1] = sm.green_idolScore_sum;
|
||||
scores[2] = sm.yellow_idolScore_sum;
|
||||
scores[3] = sm.purple_idolScore_sum;
|
||||
scores[4] = sm.blue_idolScore_sum;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 5; i++)
|
||||
{
|
||||
GameObject go = GameObject.Find($"ally_0{i + 1}");
|
||||
if (go != null)
|
||||
{
|
||||
AllyCombatant ac = go.GetComponent<AllyCombatant>();
|
||||
scores[i] = ac != null ? ac.currentScore : 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
scores[i] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int max = -1;
|
||||
for (int i = 0; i < scores.Length; i++)
|
||||
{
|
||||
if (scores[i] > max)
|
||||
{
|
||||
max = scores[i];
|
||||
topIndex = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (topIndex < 0 || max <= 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
AllyHero_SO heroSO = null;
|
||||
if (SkillBuilder.Instance != null)
|
||||
{
|
||||
try { heroSO = SkillBuilder.Instance.GetAllyHeroSOBySlot(topIndex); }
|
||||
catch { heroSO = null; }
|
||||
}
|
||||
|
||||
if (heroSO == null && teamUIController.Instance != null && teamUIController.Instance.allySlotIds != null)
|
||||
{
|
||||
int allyId = -1;
|
||||
if (topIndex >= 0 && topIndex < teamUIController.Instance.allySlotIds.Count)
|
||||
{
|
||||
allyId = teamUIController.Instance.allySlotIds[topIndex];
|
||||
}
|
||||
|
||||
if (allyId > 0)
|
||||
{
|
||||
heroSO = FindAllyHeroSOById(allyId);
|
||||
}
|
||||
}
|
||||
|
||||
return heroSO;
|
||||
}
|
||||
|
||||
private static void EnsureCachedAllyHeroSOs()
|
||||
{
|
||||
if (_cachedAllyHeroSOs == null || _cachedAllyHeroSOs.Length == 0)
|
||||
{
|
||||
_cachedAllyHeroSOs = Resources.LoadAll<AllyHero_SO>(string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
private static AllyHero_SO FindAllyHeroSOById(int allyId)
|
||||
{
|
||||
if (allyId <= 0)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
EnsureCachedAllyHeroSOs();
|
||||
if (_cachedAllyHeroSOs == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _cachedAllyHeroSOs.Length; i++)
|
||||
{
|
||||
AllyHero_SO hero = _cachedAllyHeroSOs[i];
|
||||
if (hero != null && hero.ally_heroID == allyId)
|
||||
{
|
||||
return hero;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void startSettlement_uiUpdate()
|
||||
{
|
||||
if (settlementUiInitialized)
|
||||
@@ -312,6 +487,7 @@ public class settlementController : MonoBehaviour
|
||||
}
|
||||
settlementUiInitialized = true;
|
||||
settlementHistoryRecorded = false;
|
||||
settlementHeroStatsRecorded = false;
|
||||
|
||||
// Documentation text normalized.
|
||||
InitializeSettlementCanvas();
|
||||
@@ -518,6 +694,7 @@ public class settlementController : MonoBehaviour
|
||||
|
||||
// Documentation text normalized.
|
||||
// Documentation text normalized.
|
||||
RecordSettlementHeroStats();
|
||||
SetMvpHeroImageFromTopScorer();
|
||||
StartMusicTransition();
|
||||
|
||||
@@ -537,6 +714,7 @@ public class settlementController : MonoBehaviour
|
||||
var record = new RecentPlayRecord
|
||||
{
|
||||
playedAt = System.DateTime.Now.ToString("MM-dd, HH:mm"),
|
||||
playedAtUtc = System.DateTime.UtcNow.ToString("o"),
|
||||
songID = thisSong_so != null ? thisSong_so.songID : 0,
|
||||
songName = thisSong_so != null && !string.IsNullOrWhiteSpace(thisSong_so.songName)
|
||||
? thisSong_so.songName
|
||||
@@ -545,6 +723,12 @@ public class settlementController : MonoBehaviour
|
||||
accuracy = targetAccuracyPercent,
|
||||
srks = CalculateSongRankingScore(noteCountRaw),
|
||||
totalScore = targetTotalScore,
|
||||
chartScore = targetPmScore,
|
||||
idolScore = targetIdolScore,
|
||||
hasScoreBreakdown = true,
|
||||
rankIndex = CalculateRankIndex(targetTotalScore),
|
||||
rankTierCount = GetRankTierCount(),
|
||||
hasRankMarker = true,
|
||||
scoreReadable = true,
|
||||
wasEarlySettlement = IsEarlySettlement(noteCountRaw),
|
||||
wasAllPerfect = IsAllPerfectRun(noteCountRaw)
|
||||
@@ -598,6 +782,48 @@ public class settlementController : MonoBehaviour
|
||||
}
|
||||
}
|
||||
|
||||
private int GetRankTierCount()
|
||||
{
|
||||
if (rankConfig == null || rankConfig.thresholds == null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
return Mathf.Max(0, rankConfig.thresholds.Count);
|
||||
}
|
||||
|
||||
private int CalculateRankIndex(int score)
|
||||
{
|
||||
if (rankConfig == null || rankConfig.thresholds == null || rankConfig.thresholds.Count == 0 || score <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int bestLevel = 0;
|
||||
float highestMatchingPercent = -1f;
|
||||
int thresholdCount = rankConfig.thresholds.Count;
|
||||
|
||||
for (int i = 0; i < thresholdCount; i++)
|
||||
{
|
||||
RankThreshold threshold = rankConfig.thresholds[i];
|
||||
if (threshold == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
float requiredScore = rankConfig.baseScore * threshold.thresholdPercent;
|
||||
if (score < requiredScore || threshold.thresholdPercent <= highestMatchingPercent)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
highestMatchingPercent = threshold.thresholdPercent;
|
||||
bestLevel = thresholdCount - i;
|
||||
}
|
||||
|
||||
return bestLevel;
|
||||
}
|
||||
|
||||
private float CalculateSongRankingScore(int noteCountRaw)
|
||||
{
|
||||
int totalNotes = Mathf.Max(1, noteCountRaw);
|
||||
|
||||
Reference in New Issue
Block a user