diff --git a/Assets/AddressableAssetsData/AssetGroups/sfx.asset b/Assets/AddressableAssetsData/AssetGroups/sfx.asset index bdb254f9e6..ce60e1e060 100644 --- a/Assets/AddressableAssetsData/AssetGroups/sfx.asset +++ b/Assets/AddressableAssetsData/AssetGroups/sfx.asset @@ -9330,6 +9330,11 @@ MonoBehaviour: m_ReadOnly: 0 m_SerializedLabels: [] FlaggedDuringContentUpdateRestriction: 0 + - m_GUID: b052c37c53745f84ab3c7bb0e3c410b0 + m_Address: Assets/ModelRenderer/Art/sfx/music/music/theme_c.mp3 + m_ReadOnly: 0 + m_SerializedLabels: [] + FlaggedDuringContentUpdateRestriction: 0 - m_GUID: b069390864138b445b51557b94886527 m_Address: "skill/02mage/\u5947\u95E8\u62A4\u7532_a" m_ReadOnly: 0 @@ -12625,6 +12630,11 @@ MonoBehaviour: m_ReadOnly: 0 m_SerializedLabels: [] FlaggedDuringContentUpdateRestriction: 0 + - m_GUID: e6da5caa83084c446b019f91ef4c3349 + m_Address: Assets/ModelRenderer/Art/sfx/music/music/theme_a.mp3 + m_ReadOnly: 0 + m_SerializedLabels: [] + FlaggedDuringContentUpdateRestriction: 0 - m_GUID: e6df1ea9e172c414da99d57d3f22b935 m_Address: "monster/\u6218\u6597\u884C\u52A8/\u82B1\u8349\u7C7B\u8FD0\u52A82" m_ReadOnly: 0 @@ -12905,6 +12915,11 @@ MonoBehaviour: m_ReadOnly: 0 m_SerializedLabels: [] FlaggedDuringContentUpdateRestriction: 0 + - m_GUID: eb201c0efb391fa4797948562ef08604 + m_Address: Assets/ModelRenderer/Art/sfx/music/music/theme_b.mp3 + m_ReadOnly: 0 + m_SerializedLabels: [] + FlaggedDuringContentUpdateRestriction: 0 - m_GUID: eb223a6970aaa9c45903924622374999 m_Address: "creature/monster/\u795D\u878D/\u6B7B\u4EA1_\u6C34\u4E2D" m_ReadOnly: 0 diff --git a/Assets/ModelRenderer/Art/sfx/music/music/theme_a.mp3 b/Assets/ModelRenderer/Art/sfx/music/music/theme_a.mp3 new file mode 100644 index 0000000000..39f597f287 Binary files /dev/null and b/Assets/ModelRenderer/Art/sfx/music/music/theme_a.mp3 differ diff --git a/Assets/ModelRenderer/Art/sfx/music/music/theme_a.mp3.meta b/Assets/ModelRenderer/Art/sfx/music/music/theme_a.mp3.meta new file mode 100644 index 0000000000..bf81c9c8ef --- /dev/null +++ b/Assets/ModelRenderer/Art/sfx/music/music/theme_a.mp3.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: e6da5caa83084c446b019f91ef4c3349 +AudioImporter: + externalObjects: {} + serializedVersion: 8 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 0 + sampleRateOverride: 44100 + compressionFormat: 1 + quality: 1 + conversionMode: 0 + preloadAudioData: 0 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ModelRenderer/Art/sfx/music/music/theme_b.mp3 b/Assets/ModelRenderer/Art/sfx/music/music/theme_b.mp3 new file mode 100644 index 0000000000..dd077de344 Binary files /dev/null and b/Assets/ModelRenderer/Art/sfx/music/music/theme_b.mp3 differ diff --git a/Assets/ModelRenderer/Art/sfx/music/music/theme_b.mp3.meta b/Assets/ModelRenderer/Art/sfx/music/music/theme_b.mp3.meta new file mode 100644 index 0000000000..993f29ccf2 --- /dev/null +++ b/Assets/ModelRenderer/Art/sfx/music/music/theme_b.mp3.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: eb201c0efb391fa4797948562ef08604 +AudioImporter: + externalObjects: {} + serializedVersion: 8 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 0 + sampleRateOverride: 44100 + compressionFormat: 1 + quality: 1 + conversionMode: 0 + preloadAudioData: 0 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/ModelRenderer/Art/sfx/music/music/theme_c.mp3 b/Assets/ModelRenderer/Art/sfx/music/music/theme_c.mp3 new file mode 100644 index 0000000000..0be944baca Binary files /dev/null and b/Assets/ModelRenderer/Art/sfx/music/music/theme_c.mp3 differ diff --git a/Assets/ModelRenderer/Art/sfx/music/music/theme_c.mp3.meta b/Assets/ModelRenderer/Art/sfx/music/music/theme_c.mp3.meta new file mode 100644 index 0000000000..5aa3af1cbe --- /dev/null +++ b/Assets/ModelRenderer/Art/sfx/music/music/theme_c.mp3.meta @@ -0,0 +1,23 @@ +fileFormatVersion: 2 +guid: b052c37c53745f84ab3c7bb0e3c410b0 +AudioImporter: + externalObjects: {} + serializedVersion: 8 + defaultSettings: + serializedVersion: 2 + loadType: 0 + sampleRateSetting: 0 + sampleRateOverride: 44100 + compressionFormat: 1 + quality: 1 + conversionMode: 0 + preloadAudioData: 0 + platformSettingOverrides: {} + forceToMono: 0 + normalize: 1 + loadInBackground: 0 + ambisonic: 0 + 3D: 1 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/PerfectWorld/Scene/LoginScene.unity b/Assets/PerfectWorld/Scene/LoginScene.unity index 857b9fb373..4de3721598 100644 --- a/Assets/PerfectWorld/Scene/LoginScene.unity +++ b/Assets/PerfectWorld/Scene/LoginScene.unity @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:631a23da0c12055ef55e35b21fac40b752599bdbb43d0d2c1c7fd90674d4b791 -size 118853 +oid sha256:bc028fc3c6b7fe9d9851f84da3d784923ccfb38af77605dd57c1e7e12e4c5817 +size 113080 diff --git a/Assets/PerfectWorld/Scripts/UI/Login/LoginScreenUI.cs b/Assets/PerfectWorld/Scripts/UI/Login/LoginScreenUI.cs index b9f3def29b..e19fe6fe1a 100644 --- a/Assets/PerfectWorld/Scripts/UI/Login/LoginScreenUI.cs +++ b/Assets/PerfectWorld/Scripts/UI/Login/LoginScreenUI.cs @@ -1,440 +1,426 @@ -using System; -using System.Collections.Generic; -using System.Threading; -using System.Threading.Tasks; -using BrewMonster.Network; -using BrewMonster.Scripts; -using CSNetwork.Protocols; -using CSNetwork.Protocols.RPCData; -using TMPro; -using UnityEngine; -using UnityEngine.SceneManagement; -using UnityEngine.UI; - -namespace BrewMonster.UI -{ - /// - /// Login Flow: - /// 1. Enter username and password - /// 2. Click login button - /// 3. Login success, get the list of characters - /// 4. Open the select character screen - /// - public class LoginScreenUI : MonoBehaviour - { - [SerializeField] private TMP_InputField _usernameInputField; - [SerializeField] private TMP_InputField _passwordInputField; - [SerializeField] private Button _loginButton; - [SerializeField] private SelecScreenCharacter _selectCharacterScreen; - - private List _roleInfos; - private List _currentRoles; - private RoleInfo _pendingCreatedRole; - private bool _loginInProgress; - bool isDoneWorldRender = false; - bool isDoneNPCRender = false; - private SynchronizationContext context; - public AudioClip loginBGM; - - void Awake() - { - // Ensure wrapper created early (Tech3C SDK). - _ = Tech3CSDKWrapper.Instance; - - #if UNITY_EDITOR - _usernameInputField.gameObject.SetActive(true); - _passwordInputField.gameObject.SetActive(true); - #else - _usernameInputField.gameObject.SetActive(false); - _passwordInputField.gameObject.SetActive(false); - #endif - } - - void OnEnable() - { - Tech3CSDKWrapper.Instance.SetLoginCallback(OnLoginCallback); - Tech3CSDKWrapper.Instance.SetLogoutCallback(OnLogoutCallback); - } - - private void OnDisable() - { - Tech3CSDKWrapper.Instance.RemoveLoginCallback(); - Tech3CSDKWrapper.Instance.RemoveLogoutCallback(); - } - - void Start() - { - AudioManager.Instance.PlayBGM(loginBGM, 1.5f); - _loginButton.onClick.AddListener(OnLoginButtonClicked); - context = SynchronizationContext.Current; -#if UNITY_EDITOR - // only load the username and password from the player prefs if in editor - _usernameInputField.text = PlayerPrefs.GetString("username", ""); - _passwordInputField.text = PlayerPrefs.GetString("password", ""); -#endif - - // Default: login UI first, select-role hidden until login succeeds. - if (_selectCharacterScreen != null) - _selectCharacterScreen.gameObject.SetActive(false); - - // ApplyLoginEntry(LogoutFlowState.ConsumeNextLoginEntry()); - } - - // Update is called once per frame - void Update() - { - if (_roleInfos != null) - { - _selectCharacterScreen.InitScreen(_roleInfos, OnClickSelectCharacter, OnCreateCharacterComplete); - _roleInfos = null; - } - -#if UNITY_EDITOR - if (Input.GetKeyUp(KeyCode.LeftAlt)) - { - _usernameInputField.text = "test016"; - _passwordInputField.text = "123456"; - OnLoginButtonClicked(); - } - - if (Input.GetKeyUp(KeyCode.Tab)) - { - _usernameInputField.text = "test017"; - _passwordInputField.text = "123456"; - OnLoginButtonClicked(); - } -#endif - } - - - public async void OnLoginButtonClicked() - { - if (_loginInProgress) - { - BMLogger.LogWarning("[LoginScreenUI] Login already in progress (ignored click)."); - return; - } - - _loginInProgress = true; - if (_loginButton != null) _loginButton.interactable = false; - - // If username or password is empty, use Tech3C SDK login UI. - if (string.IsNullOrEmpty(_usernameInputField.text) || string.IsNullOrEmpty(_passwordInputField.text)) - { - // Use Tech3C SDK login UI. - bool started = Tech3CSDKWrapper.Instance.Login(); - if (!started) - { - // Fallback: manual username/password login (useful in dev if SDK not configured). - BMLogger.LogWarning("[LoginScreenUI] Tech3CSDKWrapper.Login() failed, fallback to manual login."); - await BeginGameLoginAsync(_usernameInputField.text, _passwordInputField.text); - } - } - else - { - // otherwise use manual username/password login. - BMLogger.LogError("[LoginScreenUI] Username/password empty."); - await BeginGameLoginAsync(_usernameInputField.text, _passwordInputField.text); - } - - } - - private async Task BeginGameLoginAsync(string username, string password) - { - if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password)) - { - BMLogger.LogError("[LoginScreenUI] Username/password empty."); - _loginInProgress = false; - if (_loginButton != null) _loginButton.interactable = true; - return; - } - - BMLogger.Log("OnLoginButtonClicked"); - UnityGameSession.SetConnectionInfo("103.51.120.195", 29000); - PlayerPrefs.SetString("username", username); - PlayerPrefs.SetString("password", password); - PlayerPrefs.Save(); - - BMLogger.Log($"[LoginScreenUI] Connecting+login start user='{username}'"); - await UnityGameSession.Login(username, password, OnLoginComplete); - } - - /// - /// Apply how LoginScene should look after a logout flow. - /// Call this when LoginScene is already loaded (additive) and you need to switch UI without reloading the scene. - /// - public void ApplyLoginEntry(BrewMonster.Network.LogoutFlowState.LoginEntryTarget entry) - { - _loginInProgress = false; - if (_loginButton != null) _loginButton.interactable = true; - - // Always refresh fields from PlayerPrefs (LogoutAccount clears them). - if (_usernameInputField != null) _usernameInputField.text = PlayerPrefs.GetString("username", ""); - if (_passwordInputField != null) _passwordInputField.text = PlayerPrefs.GetString("password", ""); - - if (_selectCharacterScreen != null) - _selectCharacterScreen.gameObject.SetActive(false); - - if (entry == BrewMonster.Network.LogoutFlowState.LoginEntryTarget.SelectRole) - { - // If we're returning to select role, skip straight to select role without showing login UI again, since we never fully left the game session. - OnLoginComplete(true); - return; - - // Auto-login to reach Select Role like the original client, without showing Tech3C auth UI again. - if (!string.IsNullOrEmpty(_usernameInputField.text) && !string.IsNullOrEmpty(_passwordInputField.text)) - { - BMLogger.Log("[LoginScreenUI] Auto-login triggered (return-to-select-role)."); - _loginInProgress = true; - if (_loginButton != null) _loginButton.interactable = false; - _ = BeginGameLoginAsync(_usernameInputField.text, _passwordInputField.text); - } - } - } - - /// - /// Callback when the login is complete. - /// Then get the list of characters - /// - private void OnLoginComplete(bool result) - { - BMLogger.Log($"[LoginScreenUI] OnLoginComplete result={result}"); - if (!result) - { - BMLogger.LogError("Login failed"); - if (_selectCharacterScreen != null) - _selectCharacterScreen.gameObject.SetActive(false); - _loginInProgress = false; - if (_loginButton != null) _loginButton.interactable = true; - return; - } - - if (_selectCharacterScreen != null) - _selectCharacterScreen.gameObject.SetActive(true); - UnityGameSession.GetRoleListAsync(OnGetRoleListComplete); - } - - /// - /// Callback when the list of characters is retrieved. - /// Then move to the select character screen - /// - private void OnGetRoleListComplete(List roleInfos) - { - if (roleInfos == null) - { - BMLogger.LogError("OnGetRoleListComplete: roleInfos is null"); - // Keep whatever is currently shown; don't overwrite UI state with null. - _loginInProgress = false; - if (_loginButton != null) _loginButton.interactable = true; - return; - } - - // Merge pending created role in case backend list hasn't updated yet. - if (_pendingCreatedRole != null) - { - bool exists = false; - for (int i = 0; i < roleInfos.Count; i++) - { - if (roleInfos[i].roleid == _pendingCreatedRole.roleid) - { - exists = true; - break; - } - } - - if (!exists) - { - // Copy list so we don't mutate a list owned elsewhere. - var merged = new List(roleInfos.Count + 1); - merged.AddRange(roleInfos); - merged.Add(_pendingCreatedRole); - roleInfos = merged; - } - else - { - // Backend now includes the role; clear pending. - _pendingCreatedRole = null; - } - } - - BMLogger.Log($"OnGetRoleListComplete: roles={roleInfos.Count}"); - _roleInfos = roleInfos; - _currentRoles = roleInfos; - - // Login flow finished; keep login button disabled (origin-like) once you're at select role. - _loginInProgress = false; - } - - private void OnClickSelectCharacter(RoleInfo roleInfo) - { - LoadingSceneController.Instance.ShowLoadingScene(true); - UnityGameSession.SelectRoleAsync(roleInfo, OnSelectRoleComplete); - } - - /// - /// Callback when a new character is created. - /// Refreshes the role list and keeps the character selection screen visible. - /// - private void OnCreateCharacterComplete(RoleInfo createdRole) - { - BMLogger.Log("Character created, refreshing role list..."); - if (_selectCharacterScreen != null) - { - _selectCharacterScreen.gameObject.SetActive(true); - } - - // Ensure the newly created role is visible immediately even if the server role list - // hasn't updated yet. - if (createdRole != null) - { - _pendingCreatedRole = createdRole; - if (_currentRoles == null) - { - _currentRoles = new List(); - } - - bool exists = false; - for (int i = 0; i < _currentRoles.Count; i++) - { - if (_currentRoles[i].roleid == createdRole.roleid) - { - exists = true; - break; - } - } - - if (!exists) - { - _currentRoles.Add(createdRole); - } - - _roleInfos = _currentRoles; - } - else - { - BMLogger.LogError("OnCreateCharacterComplete: createdRole is null (create-role callback returned null)"); - } - - // NOTE: - // Immediately requesting the role list after create has been observed to disconnect - // in some server builds. We rely on the createdRole callback to update UI instantly. - // A server sync can be done later (e.g., next time you open this screen / re-login). - } - - private void OnSelectRoleComplete(RoleInfo roleInfo) - { - context.Post(_ => - { - isDoneWorldRender = false; - isDoneNPCRender = false; - Action actLoadChar = () => - { - if (!isDoneNPCRender || !isDoneWorldRender) - { - return; - } - }; - SceneLoader.SceneLoadProcess = SceneLoadProcess.Loading; - SceneLoader.LoadingProgress = 0; -#if TESTFAST - string nameScene = "LoginScene"; - SceneManager.UnloadSceneAsync(nameScene); - isDoneNPCRender = true; - isDoneWorldRender = true; - actLoadChar?.Invoke(); - WorldMusicController.Instance.InitForWorld(roleInfo.worldtag); - UnityGameSession.EnterWorldAsync(roleInfo, OnEnterWorldComplete); -#else - string nameScene = UnityGameSession.Instance.GetWorldInstanceName(); - UnityGameSession.Instance.LoadScene(nameScene, LoadSceneMode.Single, - (progress) => - { - LoadingSceneController.Instance.SetProgress(progress); - }, - (value) => - { - isDoneWorldRender = value; - isDoneNPCRender = true; - isDoneWorldRender = true; - actLoadChar?.Invoke(); - WorldMusicController.Instance.InitForWorld(roleInfo.worldtag); - UnityGameSession.EnterWorldAsync(roleInfo, OnEnterWorldComplete); - }); -#endif - }, null); - } - - private async void OnEnterWorldComplete() - { - await Task.Delay(2000); - // Request all known packages: 0=Inventory,1=Equipment,2=Task - UnityGameSession.RequestAllInventoriesAsync(() => { /*BMLogger.Log("Sent Inventory Detail Requests (all packs)");*/ }, 0, 1, 2); - await Task.Delay(1000); - UnityGameSession.RequestCheckSecurityPassWd(""); - // C++ friend_GetList(); required before Add Friend - await Task.Delay(1000); - UnityGameSession.Friend_GetList(); - } - - //private void OnInventoryReceived(List inventoryData) - //{ - // _inventoryUI.DisplayInventory(inventoryData); - //} - -#if UNITY_EDITOR - private void OnValidate() - { - if (_usernameInputField == null) - { - // find childrend with name "username" - _usernameInputField = transform.Find("username").GetComponent(); - } - - if (_passwordInputField == null) - { - // find childrend with name "password" - _passwordInputField = transform.Find("password").GetComponent(); - } - - if (_loginButton == null) - { - // find childrend with name "LoginBtn" - _loginButton = transform.Find("LoginBtn").GetComponent