414 lines
14 KiB
C#
414 lines
14 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;
|
|
using System.Collections.Generic;
|
|
|
|
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();
|
|
|
|
SetupRoleInfos();
|
|
}
|
|
|
|
public void Hide()
|
|
{
|
|
gameObject.SetActive(false);
|
|
}
|
|
|
|
public void OnRaceSelected(int prof)
|
|
{
|
|
if (prof < 0 || prof >= (int)Profession.NUM_PROFESSION) return;
|
|
|
|
_currentProfession = prof;
|
|
OnGenderSelected(GetDefaultGenderForProfession(prof));
|
|
}
|
|
|
|
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();
|
|
|
|
LoadShowModel(_currentProfession, _currentGender);
|
|
}
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
int[] equipmentIds = new int[]
|
|
{
|
|
// Set 0
|
|
45504, 35751, 35750, 35752, 35749, 0,
|
|
// Set 1
|
|
36348, 35763, 35762, 35764, 35761, 0,
|
|
// Set 2
|
|
36353, 35755, 35754, 35756, 35753, 0,
|
|
// Set 3
|
|
36346, 35747, 35746, 35748, 35745, 0,
|
|
// Set 4
|
|
45909, 35775, 35774, 35776, 35773, 0,
|
|
// Set 5
|
|
36354, 35743, 35742, 35744, 35741, 0,
|
|
// Set 6
|
|
36352, 35739, 35738, 35740, 35737, 42330,
|
|
// Set 7
|
|
36347, 35771, 35770, 35772, 35769, 42330,
|
|
// Set 8
|
|
36551, 35767, 35766, 35768, 35765, 0,
|
|
// Set 9
|
|
36349, 35759, 35758, 35760, 35757, 0,
|
|
// Set 10
|
|
44959, 45179, 45191, 45215, 45203, 0,
|
|
// Set 11
|
|
45043, 45170, 45171, 45173, 45172, 0
|
|
};
|
|
|
|
private const int NEWCHAR_WEAPON = 0;
|
|
private const int NEWCHAR_UPPERBODY = 1;
|
|
private const int NEWCHAR_LOWERBODY = 2;
|
|
private const int NEWCHAR_WRIST = 3;
|
|
private const int NEWCHAR_FOOT = 4;
|
|
private const int NEWCHAR_WING = 5;
|
|
private const int NEWCHAR_NUM_EQUIP = 6;
|
|
|
|
List<RoleInfo> _roleInfos = new();
|
|
// Setup all the role infor for the PlayerModelPreview
|
|
private void SetupRoleInfos()
|
|
{
|
|
List<GRoleInventory> equipments = null;
|
|
for (int i = 0; i < (int)Profession.NUM_PROFESSION; i++)
|
|
{
|
|
for (int j = 0; j < (int)Gender.NUM_GENDER; j++)
|
|
{
|
|
RoleInfo roleInfo = new();
|
|
roleInfo.roleid = i * (int)Gender.NUM_GENDER + j;
|
|
roleInfo.occupation = (byte)i;
|
|
roleInfo.gender = (byte)j;
|
|
|
|
_roleInfos.Add(roleInfo);
|
|
|
|
// now we setup the quipment
|
|
equipments = new()
|
|
{
|
|
new GRoleInventory() { id = (uint)equipmentIds[i * 6], pos = NEWCHAR_WEAPON },
|
|
new GRoleInventory() { id = (uint)equipmentIds[i * 6 + 1], pos = NEWCHAR_UPPERBODY },
|
|
new GRoleInventory() { id = (uint)equipmentIds[i * 6 + 2], pos = NEWCHAR_LOWERBODY },
|
|
new GRoleInventory() { id = (uint)equipmentIds[i * 6 + 3], pos = NEWCHAR_WRIST },
|
|
new GRoleInventory() { id = (uint)equipmentIds[i * 6 + 4], pos = NEWCHAR_FOOT },
|
|
new GRoleInventory() { id = (uint)equipmentIds[i * 6 + 5], pos = NEWCHAR_WING }
|
|
};
|
|
|
|
roleInfo.equipment = equipments;
|
|
}
|
|
}
|
|
|
|
PlayerModelPreview.Instance.ShowAllPlayerModels(_roleInfos);
|
|
}
|
|
|
|
private void LoadShowModel(int prof, int gender)
|
|
{
|
|
PlayerModelPreview .Instance.ShowPlayerModel(prof * (int)Gender.NUM_GENDER + gender);
|
|
}
|
|
}
|
|
}
|