Files
test/Assets/PerfectWorld/Scripts/UI/Login/CreateCharacterScreen.cs
T
2026-03-31 15:54:59 +07:00

326 lines
11 KiB
C#

using System;
using System.Text;
using BrewMonster.Network;
using CSNetwork;
using CSNetwork.GPDataType;
using CSNetwork.Protocols;
using CSNetwork.Protocols.RPCData;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using BrewMonster.Scripts;
using BrewMonster.PerfectWorld.Scripts.Utility.ChatFilter;
namespace BrewMonster.UI
{
/// <summary>
/// UI screen for creating a new character.
/// Equivalent to CDlgCreateGenderName + CDlgCreateProfession in C++.
/// </summary>
public class CreateCharacterScreen : MonoBehaviour
{
[SerializeField] private GameObject professionSelectionPanel;
[SerializeField] private Button[] professionButtons;
[SerializeField] private Button maleGenderButton;
[SerializeField] private Button femaleGenderButton;
[SerializeField] private TMP_InputField nameInputField;
[SerializeField] private TMP_Text validationMessageText;
[SerializeField] private Button confirmButton;
[SerializeField] private Button cancelButton;
[SerializeField] private Button backButton;
[SerializeField] private CDlgMessageBox messageBoxPrefab;
private CDlgMessageBox _messageBoxInstance;
private int _currentProfession = -1;
private int _currentGender = -1;
private Action<RoleInfo> _onCreateComplete;
private Action _onCancel;
// Static array matching s_bShowMale[NUM_PROFESSION] from original C++ code (EC_ProfConfigs.cpp)
// true = show male, false = show female
private static readonly bool[] s_bShowMale = new bool[]
{
true, // 0: kiem khach (nhan toc)
false, // 1: phap su (nhan toc)
false, // 2: vu su (tich toc)
false, // 3: tien thu (thu toc)
true, // 4: than thu (thu toc)
true, // 5: thich khach (tich toc)
true, // 6: vu mang (vu toc)
false, // 7: vu linh (vu toc)
true, // 8: kiem linh (linh toc)
false, // 9: mi linh (linh toc)
true, // 10: da anh (long toc)
false, // 11: nguyet tien (long toc)
};
private void Start()
{
if (confirmButton != null)
confirmButton.onClick.AddListener(OnConfirmClicked);
if (cancelButton != null)
cancelButton.onClick.AddListener(OnCancelClicked);
if (backButton != null)
backButton.onClick.AddListener(OnCancelClicked);
if (maleGenderButton != null)
maleGenderButton.onClick.AddListener(() => OnGenderSelected(GENDER.GENDER_MALE));
if (femaleGenderButton != null)
femaleGenderButton.onClick.AddListener(() => OnGenderSelected(GENDER.GENDER_FEMALE));
// Setup profession buttons
if (professionButtons != null)
{
for (int i = 0; i < professionButtons.Length && i < 12; i++)
{
int prof = i; // Capture for closure
if (professionButtons[i] != null)
professionButtons[i].onClick.AddListener(() => OnProfessionSelected(prof));
}
}
if (nameInputField != null)
{
nameInputField.onSubmit.AddListener((text) => { if (CanConfirm()) OnConfirmClicked(); });
nameInputField.onValueChanged.AddListener((text) => ClearValidationError());
}
}
public void Show(Action<RoleInfo> onCreateComplete, Action onCancel)
{
_onCreateComplete = onCreateComplete;
_onCancel = onCancel;
_currentProfession = -1;
_currentGender = -1;
gameObject.SetActive(true);
if (nameInputField != null)
{
nameInputField.text = "";
nameInputField.Select();
}
ClearValidationError();
UpdateConfirmButtonState();
}
public void Hide()
{
gameObject.SetActive(false);
}
private void OnProfessionSelected(int profession)
{
if (profession < 0 || profession >= (int)Profession.NUM_PROFESSION)
return;
_currentProfession = profession;
// Update UI to show selected profession
if (professionButtons != null)
{
for (int i = 0; i < professionButtons.Length; i++)
{
if (professionButtons[i] != null)
{
// Visual feedback for selected profession
var colors = professionButtons[i].colors;
colors.normalColor = (i == profession) ? Color.yellow : Color.white;
professionButtons[i].colors = colors;
}
}
}
// Auto-select gender based on profession (matching original C++ logic from EC_ProfConfigs.cpp)
// This matches the s_bShowMale array in CanShowOnCreate function
int autoGender = GetDefaultGenderForProfession(profession);
OnGenderSelected(autoGender);
UpdateConfirmButtonState();
}
/// <summary>
/// Gets the default gender for a profession based on the original C++ logic.
/// Matches the s_bShowMale array from EC_ProfConfigs.cpp CanShowOnCreate function.
/// </summary>
private int GetDefaultGenderForProfession(int profession)
{
if (profession >= 0 && profession < s_bShowMale.Length)
{
return s_bShowMale[profession] ? GENDER.GENDER_MALE : GENDER.GENDER_FEMALE;
}
// Fallback to male if profession is invalid
return GENDER.GENDER_MALE;
}
private void OnGenderSelected(int gender)
{
if (gender != GENDER.GENDER_MALE && gender != GENDER.GENDER_FEMALE)
return;
_currentGender = gender;
// Update UI to show selected gender
if (maleGenderButton != null)
{
var colors = maleGenderButton.colors;
colors.normalColor = (gender == GENDER.GENDER_MALE) ? Color.yellow : Color.white;
maleGenderButton.colors = colors;
}
if (femaleGenderButton != null)
{
var colors = femaleGenderButton.colors;
colors.normalColor = (gender == GENDER.GENDER_FEMALE) ? Color.yellow : Color.white;
femaleGenderButton.colors = colors;
}
UpdateConfirmButtonState();
}
private void OnConfirmClicked()
{
if (!CanConfirm())
return;
if (!TryGetValidatedCharacterName(out string characterName))
{
return;
}
// Create RoleInfo using helper method
RoleInfo roleInfo = GameSession.CreateNewRoleInfo(characterName, _currentProfession, _currentGender);
// Create role via network
Debug.Log($"Calling CreateRoleAsync for character: {characterName}, profession: {_currentProfession}, gender: {_currentGender}");
UnityGameSession.CreateRoleAsync(roleInfo, new Octets(), (createdRole) =>
{
if (createdRole != null)
{
Debug.Log($"Character created successfully: {characterName}, RoleID: {createdRole.roleid}");
Hide();
_onCreateComplete?.Invoke(createdRole);
}
else
{
Debug.LogError($"Failed to create character: {characterName}. Check GameSession logs for error details.");
// TODO: Show error message to user
}
});
}
private void OnCancelClicked()
{
Hide();
_onCancel?.Invoke();
}
private bool TryGetValidatedCharacterName(out string characterName)
{
characterName = nameInputField != null ? nameInputField.text.Trim() : string.Empty;
if (string.IsNullOrWhiteSpace(characterName))
{
ShowValidationError("Character name cannot be empty.");
return false;
}
if (ChatFilterService.ContainsBadWord(characterName))
{
ShowValidationError("Character name contains inappropriate words.");
return false;
}
ClearValidationError();
return true;
}
private void ShowValidationError(string message)
{
if (validationMessageText != null)
{
validationMessageText.text = message;
validationMessageText.gameObject.SetActive(true);
}
var dialog = GetOrCreateMessageBoxInstance();
if (dialog != null)
{
dialog.ShowMessageBoxYes("Invalid Character Name", message, null, null);
}
else
{
CECUIManager.Instance?.ShowMessageBoxYes("Invalid Character Name", message, null, null);
}
Debug.LogWarning(message);
}
private CDlgMessageBox GetOrCreateMessageBoxInstance()
{
if (_messageBoxInstance != null)
{
return _messageBoxInstance;
}
if (messageBoxPrefab == null)
{
return null;
}
var canvas = GetComponentInParent<Canvas>();
if (canvas == null)
{
return null;
}
_messageBoxInstance = Instantiate(messageBoxPrefab, canvas.transform);
_messageBoxInstance.gameObject.SetActive(false);
return _messageBoxInstance;
}
private void ClearValidationError()
{
if (validationMessageText != null)
{
validationMessageText.text = string.Empty;
validationMessageText.gameObject.SetActive(false);
}
}
private bool CanConfirm()
{
if (_currentProfession < 0 || _currentProfession >= (int)Profession.NUM_PROFESSION)
return false;
if (_currentGender != GENDER.GENDER_MALE && _currentGender != GENDER.GENDER_FEMALE)
return false;
string name = nameInputField != null ? nameInputField.text : "";
if (string.IsNullOrWhiteSpace(name))
return false;
return true;
}
private void UpdateConfirmButtonState()
{
if (confirmButton != null)
{
confirmButton.interactable = CanConfirm();
}
}
private void Update()
{
// Update confirm button state in case name changes
if (nameInputField != null && nameInputField.isFocused)
{
UpdateConfirmButtonState();
}
}
}
}