for tesst
This commit is contained in:
@@ -3,10 +3,12 @@ namespace BrewMonster
|
||||
partial class CECPlayer
|
||||
|
||||
{
|
||||
protected int m_iMoneyCnt; // Amount of money the player has
|
||||
protected uint m_iMoneyCnt; // Amount of money the player has
|
||||
protected int m_iMaxMoney;
|
||||
public int GetMoneyAmount() { return m_iMoneyCnt; }
|
||||
public uint GetMoneyAmount() { return m_iMoneyCnt; }
|
||||
public int GetMaxMoneyAmount() { return m_iMaxMoney; }
|
||||
public void SetMoneyAmount(uint iMoneyCnt) { m_iMoneyCnt = iMoneyCnt; }
|
||||
|
||||
public byte GetShapeMask()
|
||||
{
|
||||
// restore the original data from 8~15 bit
|
||||
|
||||
@@ -543,7 +543,8 @@ namespace BrewMonster.Scripts.Skills
|
||||
ElementSkill s = ElementSkill.Create((uint)skillID, level);
|
||||
// giả định GetRequiredSkill() trả về List<KeyValuePair<uint,int>> hoặc IReadOnlyList<...>
|
||||
Dictionary<uint, int> skills = s.GetRequiredSkill();
|
||||
|
||||
if (skills == null || skills.Count == 0)
|
||||
return null;
|
||||
foreach (var skill in skills)
|
||||
{
|
||||
if (skill.Key != 0)
|
||||
@@ -586,7 +587,7 @@ namespace BrewMonster.Scripts.Skills
|
||||
CECSkillPanelChange.enumChangeMask.CHANGE_SKILL_OVERRIDDEN,
|
||||
skillID,
|
||||
skillLevel);
|
||||
EventBus.PublishClass(change);
|
||||
EventBus.Publish(change);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -594,7 +595,7 @@ namespace BrewMonster.Scripts.Skills
|
||||
CECSkillPanelChange.enumChangeMask.CHANGE_SKILL_LEVEL_UP,
|
||||
skillID,
|
||||
skillLevel);
|
||||
EventBus.PublishClass(change);
|
||||
EventBus.Publish(change);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -619,7 +620,7 @@ namespace BrewMonster.Scripts.Skills
|
||||
SKILL_EVIL, // �ɼ��� / Immortal skill
|
||||
SKILL_GOD, // ħ���� / Demonic skill
|
||||
}
|
||||
public class CECSkillPanelChange : CECObservableChange
|
||||
public struct CECSkillPanelChange
|
||||
{
|
||||
public enum enumChangeMask
|
||||
{
|
||||
@@ -639,5 +640,4 @@ namespace BrewMonster.Scripts.Skills
|
||||
m_skillLevel = level;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -242,12 +242,13 @@ namespace BrewMonster.Scripts.Skills
|
||||
}
|
||||
// ѧϰ����ȼ�?
|
||||
public virtual int GetRequiredRealmLevel() { return 0; }
|
||||
// ǰ�Ἴ��
|
||||
|
||||
public virtual Dictionary<uint, int> GetRequiredSkill() => new Dictionary<uint, int>();
|
||||
// ��ʾ˳��
|
||||
|
||||
public virtual int GetShowOrder() { return 0; }
|
||||
// ���ü��ܼ���
|
||||
|
||||
public virtual int SetLevel(int level) { return 0; }
|
||||
|
||||
public static int SetLevel(uint id, int level)
|
||||
{
|
||||
return SkillWrapper.Instance.SetLevel(id, level);
|
||||
|
||||
@@ -11,6 +11,7 @@ namespace BrewMonster
|
||||
[SerializeField] private UnityEngine.UI.Button okButton;
|
||||
private void Awake()
|
||||
{
|
||||
okButton.onClick.RemoveAllListeners();
|
||||
okButton.onClick.AddListener(OnOkClicked);
|
||||
}
|
||||
private void OnOkClicked()
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace BrewMonster.UI
|
||||
{
|
||||
m_contentRoot = transform as RectTransform;
|
||||
}
|
||||
|
||||
EventBus.Subscribe<CECSkillPanelChange>(OnModelChange);
|
||||
CacheTemplateInfo();
|
||||
HideTemplates();
|
||||
}
|
||||
@@ -214,7 +214,7 @@ namespace BrewMonster.UI
|
||||
subListItem.Show(true);
|
||||
if (GetSelectedSkillID() == skillID)
|
||||
{
|
||||
// 选中时可在此扩展树状展示 / Hook skill tree here if needed
|
||||
//GetGameUIMan()->m_pDlgSkillAction->ShowSkillTree(skillID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -476,13 +476,12 @@ namespace BrewMonster.UI
|
||||
}
|
||||
|
||||
// �м��ܱ������ˣ���Ҫ������������ / Handle model change notifications
|
||||
public void OnModelChange(CECHostSkillModel p, CECSkillPanelChange q)
|
||||
public void OnModelChange(CECSkillPanelChange q)
|
||||
{
|
||||
if (q == null)
|
||||
/* if (!GetGameUIMan().m_pDlgSkillAction.IsShow())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
}*/
|
||||
if (q.m_changeMask == CECSkillPanelChange.enumChangeMask.CHANGE_SKILL_OVERRIDDEN)
|
||||
{
|
||||
ResetDialog();
|
||||
@@ -503,7 +502,7 @@ namespace BrewMonster.UI
|
||||
}
|
||||
else if (q.m_changeMask == CECSkillPanelChange.enumChangeMask.CHANGE_SKILL_NPC)
|
||||
{
|
||||
// NPC变化时原逻辑隐藏技能树 / Original logic hides skill tree when NPC changes
|
||||
//GetGameUIMan()->m_pDlgSkillAction->Show(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,10 +26,10 @@ namespace BrewMonster
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
m_upgradeBtn.onClick.RemoveAllListeners();
|
||||
m_upgradeBtn.onClick.AddListener(OnCommand_Upgrade);
|
||||
|
||||
}
|
||||
|
||||
private void OnCommand_Upgrade()
|
||||
{
|
||||
CECHostPlayer player = GetHostPlayer();
|
||||
@@ -142,6 +142,7 @@ namespace BrewMonster
|
||||
}
|
||||
else
|
||||
{
|
||||
skillIcon.color = Color.white;
|
||||
/* skillDsc = model.GetSkillDescription(m_skillID, m_curLevel);
|
||||
reqLevel = GNET::ElementSkill::GetRequiredLevel(m_skillID, m_curLevel);
|
||||
reqRealmLevel = GNET::ElementSkill::GetRequiredRealmLevel(m_skillID, m_curLevel);*/
|
||||
@@ -180,13 +181,15 @@ namespace BrewMonster
|
||||
int needMoney = model.GetSkillMoney(m_skillID, m_curLevel + 1);
|
||||
|
||||
int curSp = GetHostPlayer().GetBasicProps().iSP;
|
||||
int curMoney = GetHostPlayer().GetMoneyAmount();
|
||||
uint curMoney = GetHostPlayer().GetMoneyAmount();
|
||||
|
||||
bool spOK = curSp >= needSp;
|
||||
bool moneyOK = curMoney >= needMoney;
|
||||
bool preSkillOK = true;
|
||||
|
||||
var requiredSkill = model.GetRequiredSkill(m_skillID, m_curLevel + 1);
|
||||
if (requiredSkill != null && requiredSkill.Count > 0)
|
||||
{
|
||||
foreach (var skill in requiredSkill)
|
||||
{
|
||||
if (!model.CheckPreSkillLevel((int)skill.Key, skill.Value))
|
||||
@@ -195,7 +198,7 @@ namespace BrewMonster
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (spOK && moneyOK && preSkillOK)
|
||||
{
|
||||
m_upgradeBtn.interactable = true;
|
||||
|
||||
@@ -2165,6 +2165,9 @@ namespace BrewMonster
|
||||
try
|
||||
{
|
||||
var money = GPDataTypeHelper.FromBytes<CSNetwork.GPDataType.cmd_get_own_money>(data);
|
||||
|
||||
SetMoneyAmount(money.amount);
|
||||
|
||||
var ui = GameObject.FindFirstObjectByType<BrewMonster.Scripts.Managers.EC_InventoryUI>();
|
||||
if (ui == null)
|
||||
{
|
||||
@@ -6330,7 +6333,7 @@ namespace BrewMonster
|
||||
|
||||
Info.level = GetMaxLevelSofar();
|
||||
Info.sp = m_BasicProps.iSP;
|
||||
Info.money = m_iMoneyCnt;
|
||||
Info.money = (int)m_iMoneyCnt;
|
||||
Info.profession = m_iProfession;
|
||||
Info.rank = m_BasicProps.iLevel2;
|
||||
Info.realm_level = GetRealmLevel();
|
||||
|
||||
@@ -31,6 +31,7 @@ public class CECUIManager : MonoSingleton<CECUIManager>
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
EventBus.Subscribe<CECHostPlayer.NPCINFO>(ShowUINPC);
|
||||
EventBus.Subscribe<NPCDiedEvent>(TryHideUINPC);
|
||||
EventBus.Subscribe<MessageBoxEvent>(OnMessageBox);
|
||||
@@ -57,6 +58,7 @@ public class CECUIManager : MonoSingleton<CECUIManager>
|
||||
{
|
||||
EventBus.Unsubscribe<CECHostPlayer.NPCINFO>(ShowUINPC);
|
||||
EventBus.Unsubscribe<NPCDiedEvent>(TryHideUINPC);
|
||||
EventBus.Subscribe<MessageBoxEvent>(OnMessageBox);
|
||||
|
||||
}
|
||||
|
||||
|
||||
+939
-10
File diff suppressed because one or more lines are too long
@@ -0,0 +1,438 @@
|
||||
# C++ to C# Unity String Format Conversion Guide
|
||||
|
||||
## Overview
|
||||
|
||||
This guide explains how to convert the C++ string formatting pattern used in Perfect World Online to C# Unity.
|
||||
|
||||
---
|
||||
|
||||
## The Original C++ Code
|
||||
|
||||
From `DlgSkillSubListItem.cpp`, line 290:
|
||||
|
||||
```cpp
|
||||
int needMoney = CECHostSkillModel::Instance().GetSkillMoney(m_skillID, m_curLevel + 1);
|
||||
int needSp = CECHostSkillModel::Instance().GetSkillSp(m_skillID, m_curLevel + 1);
|
||||
ACString str;
|
||||
str.Format(GetStringFromTable(11326), needMoney, needSp);
|
||||
GetGameUIMan()->MessageBox("Game_LearnSkill", str, MB_OKCANCEL, A3DCOLORRGBA(255, 255, 255, 160), &pMsgBox);
|
||||
pMsgBox->SetData(m_skillID);
|
||||
```
|
||||
|
||||
### What This Code Does:
|
||||
|
||||
1. **Gets skill upgrade costs**: Retrieves the money and skill points needed for the next level
|
||||
2. **Formats localized string**: Uses `GetStringFromTable(11326)` to get a template string, then formats it with the cost values
|
||||
3. **Shows confirmation dialog**: Displays a message box with OK/Cancel buttons
|
||||
4. **Attaches data**: Associates the skill ID with the dialog
|
||||
|
||||
---
|
||||
|
||||
## The C# Unity Conversion
|
||||
|
||||
From `CDlgSkillSubListItem.cs`:
|
||||
|
||||
```csharp
|
||||
// Get the required money and skill points for the next level
|
||||
int needMoney = CECHostSkillModel.Instance.GetSkillMoney(m_skillID, m_curLevel + 1);
|
||||
int needSp = CECHostSkillModel.Instance.GetSkillSp(m_skillID, m_curLevel + 1);
|
||||
|
||||
// Format the confirmation message string
|
||||
// C++ equivalent: str.Format(GetStringFromTable(11326), needMoney, needSp);
|
||||
string confirmMessage = string.Format(GetStringFromTable(11326), needMoney, needSp);
|
||||
|
||||
// Show confirmation dialog with OK/Cancel buttons
|
||||
uiManager.ShowConfirmDialog(
|
||||
"Game_LearnSkill",
|
||||
confirmMessage,
|
||||
onConfirm: () => {
|
||||
// Player confirmed - learn the skill
|
||||
CECHostSkillModel.Instance.LearnSkill(m_skillID);
|
||||
},
|
||||
onCancel: null,
|
||||
skillData: m_skillID
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key Conversion Patterns
|
||||
|
||||
### 1. String Formatting
|
||||
|
||||
**C++ (ACString)**:
|
||||
```cpp
|
||||
ACString str;
|
||||
str.Format(GetStringFromTable(11326), needMoney, needSp);
|
||||
```
|
||||
|
||||
**C# (string)**:
|
||||
```csharp
|
||||
string confirmMessage = string.Format(GetStringFromTable(11326), needMoney, needSp);
|
||||
```
|
||||
|
||||
**Notes**:
|
||||
- C++'s `ACString::Format()` is a member function
|
||||
- C#'s `string.Format()` is a static function
|
||||
- Both use the same placeholder syntax: `%d` (C++) or `{0}`, `{1}` (C#)
|
||||
- If your string table uses C++ format specifiers, you may need to convert them:
|
||||
- `%d` → `{0}`, `{1}` for integers
|
||||
- `%s` → `{0}`, `{1}` for strings
|
||||
- `%f` → `{0}`, `{1}` for floats
|
||||
|
||||
### 2. Message Box with Callbacks
|
||||
|
||||
**C++ (Pointer-based)**:
|
||||
```cpp
|
||||
PAUIDIALOG pMsgBox;
|
||||
GetGameUIMan()->MessageBox("Game_LearnSkill", str, MB_OKCANCEL,
|
||||
A3DCOLORRGBA(255, 255, 255, 160), &pMsgBox);
|
||||
pMsgBox->SetData(m_skillID);
|
||||
|
||||
// Later, in message handler:
|
||||
void OnMessageBox_OK(const char* szName) {
|
||||
if (strcmp(szName, "Game_LearnSkill") == 0) {
|
||||
PAUIDIALOG pMsgBox = GetGameUIMan()->GetDialog(szName);
|
||||
int skillID = pMsgBox->GetData();
|
||||
// Learn skill...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**C# (Callback-based)**:
|
||||
```csharp
|
||||
uiManager.ShowConfirmDialog(
|
||||
"Game_LearnSkill",
|
||||
confirmMessage,
|
||||
onConfirm: () => {
|
||||
// This code runs when player clicks OK
|
||||
CECHostSkillModel.Instance.LearnSkill(m_skillID);
|
||||
},
|
||||
onCancel: () => {
|
||||
// This code runs when player clicks Cancel (optional)
|
||||
},
|
||||
skillData: m_skillID
|
||||
);
|
||||
```
|
||||
|
||||
**Key Differences**:
|
||||
- C++ uses pointers and manual dialog lookup
|
||||
- C# uses lambda callbacks (closures) that capture variables
|
||||
- C# is more straightforward - no need to check dialog names or retrieve data manually
|
||||
|
||||
### 3. Localized String Table
|
||||
|
||||
**Both versions use the same approach**:
|
||||
|
||||
```csharp
|
||||
// Get localized string template from string table
|
||||
// String ID 11326 might contain: "学习此技能需要 {0} 金钱和 {1} 技能点,确定学习吗?"
|
||||
// English: "Learning this skill requires {0} money and {1} skill points, confirm?"
|
||||
string template = GetStringFromTable(11326);
|
||||
|
||||
// Format with actual values
|
||||
string message = string.Format(template, needMoney, needSp);
|
||||
// Result: "Learning this skill requires 2480 money and 34200 skill points, confirm?"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Complete Example Comparison
|
||||
|
||||
### C++ Version (Original)
|
||||
|
||||
```cpp
|
||||
void CDlgSkillSubListItem::OnCommand_Upgrade(const char* szCommand) {
|
||||
CECHostPlayer* player = GetHostPlayer();
|
||||
PAUIDIALOG pMsgBox;
|
||||
|
||||
// Check player state...
|
||||
if (player->IsDead() || player->IsSitting() || /* ... */) {
|
||||
GetGameUIMan()->MessageBox("", GetGameUIMan()->GetStringFromTable(11327),
|
||||
MB_OK, A3DCOLORRGBA(255, 255, 255, 160), &pMsgBox);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check learning conditions...
|
||||
int nCondition = CECHostSkillModel::Instance().CheckLearnCondition(m_skillID);
|
||||
int nCheckCode = 0;
|
||||
|
||||
if (1 == nCondition) {
|
||||
nCheckCode = 270;
|
||||
} else if (6 == nCondition) {
|
||||
nCheckCode = 527;
|
||||
}
|
||||
// ... more conditions ...
|
||||
|
||||
if (nCheckCode == 0) {
|
||||
// Show confirmation dialog
|
||||
int needMoney = CECHostSkillModel::Instance().GetSkillMoney(m_skillID, m_curLevel + 1);
|
||||
int needSp = CECHostSkillModel::Instance().GetSkillSp(m_skillID, m_curLevel + 1);
|
||||
ACString str;
|
||||
str.Format(GetStringFromTable(11326), needMoney, needSp);
|
||||
GetGameUIMan()->MessageBox("Game_LearnSkill", str, MB_OKCANCEL,
|
||||
A3DCOLORRGBA(255, 255, 255, 160), &pMsgBox);
|
||||
pMsgBox->SetData(m_skillID);
|
||||
|
||||
if (!GetGameUIMan()->m_pDlgSkillAction->IsReceivedNPCGreeting()) {
|
||||
CECHostSkillModel::Instance().SendHelloToSkillLearnNPC();
|
||||
}
|
||||
} else {
|
||||
// Show error message
|
||||
GetGameUIMan()->MessageBox("", GetGameUIMan()->GetStringFromTable(nCheckCode),
|
||||
MB_OK, A3DCOLORRGBA(255, 255, 255, 160), &pMsgBox);
|
||||
pMsgBox->SetLife(3);
|
||||
}
|
||||
}
|
||||
|
||||
// Separate message handler
|
||||
void CDlgSkillSubListItem::OnMessageBox_OK(const char* szName) {
|
||||
if (strcmp(szName, "Game_LearnSkill") == 0) {
|
||||
PAUIDIALOG pMsgBox = GetGameUIMan()->GetDialog(szName);
|
||||
int skillID = pMsgBox->GetData();
|
||||
|
||||
// Send learn skill command to server
|
||||
CECHostSkillModel::Instance().LearnSkill(skillID);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### C# Unity Version (Converted)
|
||||
|
||||
```csharp
|
||||
private void OnCommand_Upgrade()
|
||||
{
|
||||
CECHostPlayer player = GetHostPlayer();
|
||||
if (player == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var uiManager = CECUIManager.Instance;
|
||||
var gameUIMan = uiManager.GetInGameUIMan();
|
||||
|
||||
// Check player state...
|
||||
if (player.IsDead() ||
|
||||
player.IsSitting() ||
|
||||
player.IsChangingFace() ||
|
||||
player.IsTrading() ||
|
||||
player.GetBoothState() != 0 ||
|
||||
player.IsRooting() ||
|
||||
player.IsHangerOn() ||
|
||||
player.GetCurSkill() != null ||
|
||||
player.IsFighting())
|
||||
{
|
||||
uiManager.ShowMessageBox("MessageBox", gameUIMan.GetStringFromTable(11327));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check learning conditions...
|
||||
int nCondition = CECHostSkillModel.Instance.CheckLearnCondition(m_skillID);
|
||||
int nCheckCode = 0;
|
||||
|
||||
if (1 == nCondition)
|
||||
{
|
||||
nCheckCode = 270;
|
||||
}
|
||||
else if (6 == nCondition)
|
||||
{
|
||||
nCheckCode = 527;
|
||||
}
|
||||
// ... more conditions ...
|
||||
|
||||
if (nCheckCode == 0)
|
||||
{
|
||||
// Get the required costs
|
||||
int needMoney = CECHostSkillModel.Instance.GetSkillMoney(m_skillID, m_curLevel + 1);
|
||||
int needSp = CECHostSkillModel.Instance.GetSkillSp(m_skillID, m_curLevel + 1);
|
||||
|
||||
// Format the confirmation message
|
||||
string confirmMessage = string.Format(GetStringFromTable(11326), needMoney, needSp);
|
||||
|
||||
// Show confirmation dialog with inline callback
|
||||
uiManager.ShowConfirmDialog(
|
||||
"Game_LearnSkill",
|
||||
confirmMessage,
|
||||
onConfirm: () => {
|
||||
// This runs when player clicks OK
|
||||
// No need to look up dialog or retrieve data - it's captured in closure
|
||||
CECHostSkillModel.Instance.LearnSkill(m_skillID);
|
||||
},
|
||||
onCancel: null,
|
||||
skillData: m_skillID
|
||||
);
|
||||
|
||||
// 如果打开对话框时NPC发送的Hello消息没有收到回复,再次发送
|
||||
// If the NPC Hello message hasn't been received when opening dialog, send again
|
||||
if (!gameUIMan.IsReceivedNPCGreeting())
|
||||
{
|
||||
CECHostSkillModel.Instance.SendHelloToSkillLearnNPC();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Show error message with auto-close after 3 seconds
|
||||
uiManager.ShowMessageBox("", gameUIMan.GetStringFromTable(nCheckCode), autoCloseTime: 3f);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## String Format Examples
|
||||
|
||||
### Example 1: Simple Integer Formatting
|
||||
|
||||
**C++ String Table Entry (ID 11326)**:
|
||||
```
|
||||
"学习此技能需要 %d 金钱和 %d 技能点,确定学习吗?"
|
||||
```
|
||||
|
||||
**C# String Table Entry (ID 11326)** (if you convert to C# format):
|
||||
```
|
||||
"学习此技能需要 {0} 金钱和 {1} 技能点,确定学习吗?"
|
||||
```
|
||||
|
||||
**Usage**:
|
||||
```csharp
|
||||
string message = string.Format(GetStringFromTable(11326), 2480, 34200);
|
||||
// Result: "学习此技能需要 2480 金钱和 34200 技能点,确定学习吗?"
|
||||
// English: "Learning this skill requires 2480 money and 34200 skill points, confirm?"
|
||||
```
|
||||
|
||||
### Example 2: Mixed Types
|
||||
|
||||
**String Table**:
|
||||
```
|
||||
"Skill: {0}, Level: {1}, Cost: {2:N0} gold"
|
||||
```
|
||||
|
||||
**Usage**:
|
||||
```csharp
|
||||
string skillName = "Fireball";
|
||||
int level = 5;
|
||||
int cost = 10000;
|
||||
|
||||
string message = string.Format(GetStringFromTable(123), skillName, level, cost);
|
||||
// Result: "Skill: Fireball, Level: 5, Cost: 10,000 gold"
|
||||
```
|
||||
|
||||
### Example 3: With Colors (Unity TextMeshPro)
|
||||
|
||||
**C++**:
|
||||
```cpp
|
||||
ACString strSp;
|
||||
strSp.Format(GetStringFromTable(11402), needSp);
|
||||
|
||||
if (spOK) {
|
||||
strSp = l_colorWhite + strSp; // l_colorWhite = "^ffffff"
|
||||
} else {
|
||||
strSp = l_colorRed + strSp; // l_colorRed = "^ff0000"
|
||||
}
|
||||
```
|
||||
|
||||
**C# (Unity TextMeshPro)**:
|
||||
```csharp
|
||||
const string l_colorWhite = "<color=#ffffff>";
|
||||
const string l_colorRed = "<color=#ff0000>";
|
||||
const string l_colorClose = "</color>";
|
||||
|
||||
string strSp = string.Format(GetStringFromTable(11402), needSp);
|
||||
|
||||
if (spOK) {
|
||||
strSp = l_colorWhite + strSp + l_colorClose;
|
||||
} else {
|
||||
strSp = l_colorRed + strSp + l_colorClose;
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
### ❌ Wrong: Using C++ format specifiers in C#
|
||||
|
||||
```csharp
|
||||
// This won't work if the string uses C++ format specifiers
|
||||
string template = "Cost: %d gold"; // C++ style
|
||||
string message = string.Format(template, 1000); // Error!
|
||||
```
|
||||
|
||||
### ✅ Correct: Convert to C# format
|
||||
|
||||
```csharp
|
||||
string template = "Cost: {0} gold"; // C# style
|
||||
string message = string.Format(template, 1000); // "Cost: 1000 gold"
|
||||
```
|
||||
|
||||
### ❌ Wrong: Forgetting to capture variables in lambda
|
||||
|
||||
```csharp
|
||||
void ShowDialog(int skillID) {
|
||||
int needMoney = GetMoney(skillID);
|
||||
|
||||
// Wrong: using skillID parameter instead of captured value
|
||||
ShowConfirmDialog("Learn", "Confirm?",
|
||||
onConfirm: () => {
|
||||
LearnSkill(skillID); // This captures the parameter, which is fine
|
||||
}
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
This is actually correct, but be careful with loop variables:
|
||||
|
||||
```csharp
|
||||
// Dangerous in loops!
|
||||
for (int i = 0; i < skills.Length; i++) {
|
||||
int skillID = skills[i];
|
||||
ShowButton(skillID, () => {
|
||||
LearnSkill(skillID); // Captures skillID, which changes each iteration
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
### ✅ Correct: Capture loop variable properly
|
||||
|
||||
```csharp
|
||||
for (int i = 0; i < skills.Length; i++) {
|
||||
int currentSkillID = skills[i]; // Create a copy for this iteration
|
||||
ShowButton(currentSkillID, () => {
|
||||
LearnSkill(currentSkillID); // Captures the copy, safe!
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Checklist
|
||||
|
||||
When converting C++ string formatting to C# Unity:
|
||||
|
||||
- [ ] Replace `ACString` with `string`
|
||||
- [ ] Replace `str.Format(...)` with `string.Format(...)`
|
||||
- [ ] Convert format specifiers if needed (`%d` → `{0}`)
|
||||
- [ ] Replace pointer-based message boxes with callback-based dialogs
|
||||
- [ ] Use lambda expressions to capture context
|
||||
- [ ] Update color codes for Unity (TextMeshPro uses `<color=#RRGGBB>`)
|
||||
- [ ] Replace `pMsgBox->SetLife(seconds)` with `autoCloseTime` parameter
|
||||
- [ ] Remove manual dialog lookup code
|
||||
- [ ] Keep Chinese comments and add English translations side by side
|
||||
|
||||
---
|
||||
|
||||
## Summary
|
||||
|
||||
The key difference between C++ and C# Unity for string formatting:
|
||||
|
||||
| Aspect | C++ | C# Unity |
|
||||
|--------|-----|----------|
|
||||
| **String type** | `ACString` | `string` |
|
||||
| **Format method** | `str.Format(template, args)` | `string.Format(template, args)` |
|
||||
| **Format specifiers** | `%d`, `%s`, `%f` | `{0}`, `{1}`, `{2}` |
|
||||
| **Message box** | Pointer + callback lookup | Lambda callbacks |
|
||||
| **Data passing** | `pMsgBox->SetData(data)` | Closure captures |
|
||||
| **Colors** | `^ffffff` | `<color=#ffffff>...</color>` |
|
||||
| **Auto-close** | `pMsgBox->SetLife(seconds)` | `autoCloseTime: seconds` |
|
||||
|
||||
The C# version is generally more concise and type-safe thanks to lambda expressions and closure capture!
|
||||
Reference in New Issue
Block a user