File diff suppressed because it is too large
Load Diff
@@ -1,52 +0,0 @@
|
||||
# Perfect World Port Architecture
|
||||
|
||||
## Overview
|
||||
|
||||
Project này port client Perfect World từ C++ sang Unity C# và xây dựng server mới bằng .NET.
|
||||
|
||||
Architecture gồm 3 layer chính:
|
||||
|
||||
Client Layer
|
||||
Unity project chịu trách nhiệm:
|
||||
|
||||
- UI
|
||||
- rendering
|
||||
- input
|
||||
- local gameplay logic
|
||||
- network client
|
||||
|
||||
Server Layer
|
||||
|
||||
.NET 8 server sử dụng LiteNetLib.
|
||||
|
||||
Server chịu trách nhiệm:
|
||||
|
||||
- authoritative game state
|
||||
- player session
|
||||
- snapshot replication
|
||||
- chat routing
|
||||
|
||||
Shared Layer
|
||||
|
||||
Game.Shared chứa:
|
||||
|
||||
- protocol definitions
|
||||
- shared data types
|
||||
- serialization logic
|
||||
|
||||
## Architecture Diagram
|
||||
|
||||
Unity Client
|
||||
↓
|
||||
Game.Shared (protocol)
|
||||
↓
|
||||
LiteNetLib transport
|
||||
↓
|
||||
Game.Server
|
||||
|
||||
## Main Goals
|
||||
|
||||
- giữ gameplay logic từ Perfect World
|
||||
- thay engine bằng Unity
|
||||
- thay network stack
|
||||
- modernize architecture
|
||||
@@ -1,63 +0,0 @@
|
||||
# Chat System
|
||||
|
||||
Chat system gốc của Perfect World gồm các bước:
|
||||
|
||||
Network Protocol
|
||||
↓
|
||||
GameSession
|
||||
↓
|
||||
GameUIMan
|
||||
↓
|
||||
CECPateText
|
||||
↓
|
||||
Render
|
||||
|
||||
## Components
|
||||
|
||||
ChatMessage
|
||||
|
||||
network protocol chứa:
|
||||
|
||||
channel
|
||||
roleid
|
||||
msg
|
||||
emotion
|
||||
|
||||
GameSession::OnPrtcChatMessage
|
||||
|
||||
nhận packet từ network.
|
||||
|
||||
GameUIMan::AddChatMessage
|
||||
|
||||
thêm message vào UI.
|
||||
|
||||
CECPateText
|
||||
|
||||
parse text thành các item:
|
||||
|
||||
TEXT
|
||||
EMOTION
|
||||
ITEM LINK
|
||||
|
||||
## Emotion System
|
||||
|
||||
Emotion được encode trong text:
|
||||
|
||||
format:
|
||||
|
||||
emotionSet:index
|
||||
|
||||
Example:
|
||||
|
||||
1:5
|
||||
|
||||
## Rendering
|
||||
|
||||
CECPateText chia text thành item list.
|
||||
|
||||
Item gồm:
|
||||
|
||||
type
|
||||
index
|
||||
color
|
||||
position
|
||||
@@ -1,21 +0,0 @@
|
||||
# Common Code Patterns
|
||||
|
||||
Pattern: Player Name Lookup
|
||||
|
||||
C++
|
||||
|
||||
Name2IDTable
|
||||
ID2NameTable
|
||||
|
||||
C#
|
||||
|
||||
Dictionary<string, int>
|
||||
Dictionary<int, string>
|
||||
|
||||
Pattern: Chat Rendering
|
||||
|
||||
Parse text
|
||||
↓
|
||||
create item list
|
||||
↓
|
||||
render UI
|
||||
@@ -1,33 +0,0 @@
|
||||
# Data Types Mapping
|
||||
|
||||
Perfect World sử dụng nhiều custom types.
|
||||
|
||||
Mapping sang C#:
|
||||
|
||||
ACString → string
|
||||
|
||||
ACHAR → wchar_t / char
|
||||
|
||||
A3DCOLOR → UnityEngine.Color hoặc Color32
|
||||
|
||||
Octets → byte[]
|
||||
|
||||
pair_type → Tuple hoặc struct
|
||||
|
||||
AArray<T> → List<T>
|
||||
|
||||
DWORD → uint
|
||||
|
||||
BYTE → byte
|
||||
|
||||
BOOL → bool
|
||||
|
||||
## Important Note
|
||||
|
||||
ACString trong C++ hỗ trợ:
|
||||
|
||||
- formatting
|
||||
- substring
|
||||
- concat
|
||||
|
||||
C# string là immutable nên cần cẩn thận performance.
|
||||
@@ -1,68 +0,0 @@
|
||||
# C++ to C# Porting Rules
|
||||
|
||||
Rule 1
|
||||
|
||||
const ACHAR* → string
|
||||
|
||||
Rule 2
|
||||
|
||||
output parameters
|
||||
|
||||
C++:
|
||||
|
||||
int& value
|
||||
|
||||
C#:
|
||||
|
||||
ref int value
|
||||
|
||||
Rule 3
|
||||
|
||||
pointer
|
||||
|
||||
T* → reference
|
||||
|
||||
Rule 4
|
||||
|
||||
array
|
||||
|
||||
ACHAR buffer[1024]
|
||||
|
||||
C#:
|
||||
|
||||
Span<char> hoặc string builder
|
||||
|
||||
Rule 5
|
||||
|
||||
container
|
||||
|
||||
AArray → List
|
||||
|
||||
Rule 6
|
||||
|
||||
memory ownership
|
||||
|
||||
C++ có delete
|
||||
|
||||
C# dùng GC
|
||||
|
||||
Rule 7
|
||||
|
||||
Chat Message Handling
|
||||
|
||||
C++:
|
||||
g_pGame->GetGameRun()->AddChatMessage(str, p->channel, p->srcroleid, NULL, 0, p->emotion,pItem ? pItem->Clone() : NULL, strMsgOrigion);
|
||||
|
||||
|
||||
C#:
|
||||
EC_Game.GetGameRun().AddChatMessage(str, p.Channel, p.Srcroleid,null, 0, p.Emotion, null, strMsgOrigion);
|
||||
|
||||
Rule 8
|
||||
|
||||
Chat Bubble on Top Player
|
||||
|
||||
C++:
|
||||
pPlayer.SetLastSaidWords(strTemp, p.Emotion);
|
||||
|
||||
C#:
|
||||
EventBus.PublishChannel(p.Srcroleid, new EventChatMessageOnTopPlayer(p.Srcroleid, strTemp));
|
||||
@@ -1,31 +0,0 @@
|
||||
# Network Protocol
|
||||
|
||||
Protocol gốc sử dụng GNET.
|
||||
|
||||
Structure:
|
||||
|
||||
Protocol
|
||||
↓
|
||||
Rpc::Data
|
||||
↓
|
||||
Octets serialization
|
||||
|
||||
## Example
|
||||
|
||||
ChatMessage
|
||||
|
||||
fields:
|
||||
|
||||
channel
|
||||
srcroleid
|
||||
srclevel
|
||||
msg
|
||||
emotion
|
||||
|
||||
## Serialization
|
||||
|
||||
Octets chứa raw byte array.
|
||||
|
||||
C# equivalent:
|
||||
|
||||
byte[]
|
||||
-11617
File diff suppressed because it is too large
Load Diff
@@ -7,7 +7,7 @@ QualitySettings:
|
||||
m_CurrentQuality: 0
|
||||
m_QualitySettings:
|
||||
- serializedVersion: 4
|
||||
name: High
|
||||
name: Mobile
|
||||
pixelLightCount: 2
|
||||
shadows: 2
|
||||
shadowResolution: 1
|
||||
@@ -17,7 +17,7 @@ QualitySettings:
|
||||
shadowNearPlaneOffset: 3
|
||||
shadowCascade2Split: 0.33333334
|
||||
shadowCascade4Split: {x: 0.06666667, y: 0.2, z: 0.46666667}
|
||||
shadowmaskMode: 1
|
||||
shadowmaskMode: 0
|
||||
skinWeights: 2
|
||||
globalTextureMipmapLimit: 0
|
||||
textureMipmapLimitSettings: []
|
||||
@@ -25,12 +25,12 @@ QualitySettings:
|
||||
antiAliasing: 0
|
||||
softParticles: 0
|
||||
softVegetation: 1
|
||||
realtimeReflectionProbes: 1
|
||||
realtimeReflectionProbes: 0
|
||||
billboardsFaceCameraPosition: 1
|
||||
useLegacyDetailDistribution: 0
|
||||
useLegacyDetailDistribution: 1
|
||||
adaptiveVsync: 0
|
||||
vSyncCount: 1
|
||||
realtimeGICPUUsage: 50
|
||||
vSyncCount: 0
|
||||
realtimeGICPUUsage: 100
|
||||
adaptiveVsyncExtraA: 0
|
||||
adaptiveVsyncExtraB: 0
|
||||
lodBias: 1
|
||||
@@ -47,7 +47,7 @@ QualitySettings:
|
||||
asyncUploadBufferSize: 16
|
||||
asyncUploadPersistentBuffer: 1
|
||||
resolutionScalingFixedDPIFactor: 1
|
||||
customRenderPipeline: {fileID: 0}
|
||||
customRenderPipeline: {fileID: 11400000, guid: 5e6cbd92db86f4b18aec3ed561671858, type: 2}
|
||||
terrainQualityOverrides: 0
|
||||
terrainPixelError: 1
|
||||
terrainDetailDensityScale: 1
|
||||
@@ -57,25 +57,7 @@ QualitySettings:
|
||||
terrainBillboardStart: 50
|
||||
terrainFadeLength: 5
|
||||
terrainMaxTrees: 50
|
||||
excludedTargetPlatforms: []
|
||||
excludedTargetPlatforms:
|
||||
- Standalone
|
||||
m_TextureMipmapLimitGroupNames: []
|
||||
m_PerPlatformDefaultQuality:
|
||||
Android: 2
|
||||
EmbeddedLinux: 5
|
||||
GameCoreScarlett: 5
|
||||
GameCoreXboxOne: 5
|
||||
Kepler: 5
|
||||
LinuxHeadlessSimulation: 5
|
||||
Nintendo Switch: 5
|
||||
Nintendo Switch 2: 5
|
||||
PS4: 5
|
||||
PS5: 5
|
||||
QNX: 5
|
||||
Server: 5
|
||||
Standalone: 5
|
||||
VisionOS: 5
|
||||
WebGL: 3
|
||||
Windows Store Apps: 5
|
||||
XboxOne: 5
|
||||
iPhone: 2
|
||||
tvOS: 2
|
||||
m_PerPlatformDefaultQuality: {}
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,10 +0,0 @@
|
||||
import os
|
||||
|
||||
try:
|
||||
with open(r'd:\perfect-world-source\perfect-world-source\CElement\CElementClient\EC_Player.cpp', 'r', encoding='gbk') as f:
|
||||
content = f.read()
|
||||
with open(r'c:\Unity\CuongNV\perfect-world-unity\EC_Player_clean.cpp', 'w', encoding='utf-8') as f2:
|
||||
f2.write(content.replace('\r', ''))
|
||||
print("Cleaned EC_Player.cpp successfully.")
|
||||
except Exception as e:
|
||||
print("Error:", e)
|
||||
BIN
Binary file not shown.
Binary file not shown.
@@ -1,13 +0,0 @@
|
||||
3289: void CECGameUIMan::AddChatMessage(const ACHAR *pszMsg,
|
||||
|
||||
3290: char cChannel, int idPlayer, const ACHAR *pszPlayer, char byFlag, char cEmotion, CECIvtrItem *pItem,const ACHAR *pszMsgOrigion)
|
||||
|
||||
3291: {
|
||||
|
||||
3292: auto_delete<CECIvtrItem> tmp(pItem);
|
||||
|
||||
3293:
|
||||
|
||||
3294: bool bIsKing = false;
|
||||
|
||||
3295: if( cChannel == GP_CHAT_COUNTRY && (cEmotion & 0x80) )
|
||||
@@ -1,212 +0,0 @@
|
||||
3289: void CECGameUIMan::AddChatMessage(const ACHAR *pszMsg,
|
||||
3290: char cChannel, int idPlayer, const ACHAR *pszPlayer, char byFlag, char cEmotion, CECIvtrItem *pItem,const ACHAR *pszMsgOrigion)
|
||||
3291: {
|
||||
3292: auto_delete<CECIvtrItem> tmp(pItem);
|
||||
3293:
|
||||
3294: bool bIsKing = false;
|
||||
3295: if( cChannel == GP_CHAT_COUNTRY && (cEmotion & 0x80) )
|
||||
3296: {
|
||||
3297: cEmotion &= ~0x80;
|
||||
3298: bIsKing = true;
|
||||
3299: }
|
||||
3300:
|
||||
3301: // 修正表情
|
||||
3302: ACString strModified = FilterEmotionSet(pszMsg, cEmotion);
|
||||
3303:
|
||||
3304: // 修正给GM的额外信息
|
||||
3305: ACString GM_MsgShow;
|
||||
3306: ACHAR GM_MsgType(0);
|
||||
3307: bool GM_MsgValid(false);
|
||||
3308: if (g_pGame->GetGameRun()->GetHostPlayer()->IsGM() &&
|
||||
3309: GP_CHAT_WHISPER == cChannel)
|
||||
3310: {
|
||||
3311: int nSymbolPos = strModified.Find(GM_HELP_MSG_TYPE_BASE);
|
||||
3312: if (nSymbolPos >= 0 && nSymbolPos+1 < strModified.GetLength())
|
||||
3313: {
|
||||
3314: ACHAR type = strModified[nSymbolPos + 1];
|
||||
3315: if (TheGMHelpMsgArray::Instance()->FindByType(type, NULL))
|
||||
3316: {
|
||||
3317: GM_MsgValid = true;
|
||||
3318: GM_MsgType = type;
|
||||
3319: GM_MsgShow = strModified;
|
||||
3320: GM_MsgShow.CutLeft(nSymbolPos + 2);
|
||||
3321:
|
||||
3322: strModified = strModified.Left(nSymbolPos) + strModified.Right(strModified.GetLength() - (nSymbolPos+2));
|
||||
3323: }
|
||||
3324: }
|
||||
3325: }
|
||||
3326:
|
||||
3327: // 考虑本地化对某些内容不显示的要求,当ingame.stf找不到相关字符串、并导致此处字符中为空时,隐藏显示
|
||||
3328: if (strModified.IsEmpty())
|
||||
3329: return;
|
||||
3330:
|
||||
3331: // 标明来自GT频道的消息
|
||||
3332: if (byFlag == CHANNEL_GAMETALK)
|
||||
3333: strModified += GetStringFromTable(9312);
|
||||
3334:
|
||||
3335: pszMsg = strModified;
|
||||
3336:
|
||||
3337: if( PlayerIsBlack(idPlayer) )
|
||||
3338: return;
|
||||
3339: if( cChannel == GP_CHAT_SYSTEM && a_stricmp(pszMsg, GetStringFromTable(809)) == 0 )
|
||||
3340: return;
|
||||
3341:
|
||||
3342: if( byFlag == CHANNEL_FRIEND || byFlag == CHANNEL_FRIEND_RE || byFlag == CHANNEL_GAMETALK)
|
||||
3343: {
|
||||
3344: AddFriendMessage(pszMsg, idPlayer, pszPlayer, byFlag, cEmotion, pItem ? pItem->Clone() : NULL,pszMsgOrigion);
|
||||
3345: return;
|
||||
3346: }
|
||||
3347: else if( byFlag == CHANNEL_USERINFO )
|
||||
3348: {
|
||||
3349: if( pszMsg[0] == 'R' )
|
||||
3350: {
|
||||
3351: CECFriendMan *pMan = g_pGame->GetGameRun()->GetHostPlayer()->GetFriendMan();
|
||||
3352: if (!pMan)
|
||||
3353: return;
|
||||
3354: if( pMan->GetFriendByID(idPlayer) )
|
||||
3355: FriendAction(idPlayer, -1, CDlgFriendList::FRIEND_ACTION_INFO_REFRESH, 0);
|
||||
3356: }
|
||||
3357: else if( pszMsg[0] == 'L' )
|
||||
3358: FriendAction(idPlayer, -1, CDlgFriendList::FRIEND_ACTION_INFO_LEVEL, a_atoi(pszMsg + 1));
|
||||
3359: else if( pszMsg[0] == 'A' )
|
||||
3360: FriendAction(idPlayer, -1, CDlgFriendList::FRIEND_ACTION_INFO_AREA, a_atoi(pszMsg + 1));
|
||||
3361: return;
|
||||
3362: }
|
||||
3363:
|
||||
3364: ACHAR *pszText;
|
||||
3365: CDlgChat::CHAT_MSG msg;
|
||||
3366: ACHAR szText[512], szMsg[512];
|
||||
3367: CDlgChat *pChat1 = m_pDlgChat;
|
||||
3368: CDlgChat *pChat2 = m_pDlgChat2;
|
||||
3369: CDlgChat *pChat3 = m_pDlgChat3;
|
||||
3370: EC_GAME_SETTING gs = g_pGame->GetConfigs()->GetGameSettings();
|
||||
3371: PAUITEXTAREA pShow1 = dynamic_cast<PAUITEXTAREA>(pChat1->GetDlgItem("Txt_Content"));
|
||||
3372: PAUITEXTAREA pShow2 = dynamic_cast<PAUITEXTAREA>(pChat2->GetDlgItem("Txt_Content"));
|
||||
3373: PAUITEXTAREA pShow3 = dynamic_cast<PAUITEXTAREA>(pChat3->GetDlgItem("Txt_Content"));
|
||||
3374: abase::vector<CDlgChat::CHAT_MSG> &vecChatMsg = m_pDlgChat->GetAllChatMsgs();
|
||||
3375: abase::vector<CDlgChat::CHAT_MSG> &superFarCryMsg = m_pDlgChat->GetSuperFarCryMsgs();
|
||||
3376: abase::vector<CDlgChat::LINKED_MSG> &whisperMsg = m_pDlgChat->GetWhisperChatMsgs();
|
||||
3377:
|
||||
3378: msg.idPlayer = idPlayer;
|
||||
3379: msg.strMsg = pszMsg;
|
||||
3380: msg.cChannel = cChannel;
|
||||
3381: msg.cEmotion = cEmotion;
|
||||
3382: msg.strMsgOrigion = pszMsgOrigion;
|
||||
3383: if( cChannel == GP_CHAT_LOCAL ||
|
||||
3384: cChannel == GP_CHAT_FARCRY ||
|
||||
3385: cChannel == GP_CHAT_TEAM ||
|
||||
3386: cChannel == GP_CHAT_FACTION ||
|
||||
3387: cChannel == GP_CHAT_WHISPER ||
|
||||
3388: cChannel == GP_CHAT_TRADE ||
|
||||
3389: cChannel == GP_CHAT_SUPERFARCRY ||
|
||||
3390: cChannel == GP_CHAT_BATTLE ||
|
||||
3391: cChannel == GP_CHAT_COUNTRY)
|
||||
3392: {
|
||||
3393: if (ISPLAYERID(idPlayer)){
|
||||
3394: g_pGame->GetGameRun()->GetUIManager()->FilterBadWords(msg.strMsg);
|
||||
3395: }
|
||||
3396: }
|
||||
3397:
|
||||
3398: int nMsgLen = a_strlen(pszMsg);
|
||||
3399: // Booth Message
|
||||
3400: if( cChannel == GP_CHAT_WHISPER &&
|
||||
3401: pszMsg[nMsgLen - 2] == '!' &&
|
||||
3402: pszMsg[nMsgLen - 1] == '#' )
|
||||
3403: {
|
||||
3404: if( m_pDlgBooth1->IsShow() )
|
||||
3405: m_pDlgBooth1->AddBoothMessage(pszMsg);
|
||||
3406: return;
|
||||
3407: }
|
||||
3408:
|
||||
3409: ACString strName;
|
||||
3410: A3DCOLOR clrName;
|
||||
3411: TransformNameColor(pItem, strName, clrName);
|
||||
3412: AWString msgWithColor = _AL("");
|
||||
3413: if( ISNPCID(idPlayer) )
|
||||
3414: msgWithColor += _AL("^C8FF64");
|
||||
3415: else
|
||||
3416: {
|
||||
3417: if( cChannel == GP_CHAT_COUNTRY && bIsKing )
|
||||
3418: msgWithColor += CDlgChat::m_pszKingColor;
|
||||
3419: else
|
||||
3420: msgWithColor += CDlgChat::GetChatColor(cChannel, idPlayer);
|
||||
3421: }
|
||||
3422:
|
||||
3423: msgWithColor += GetChatChannelImage(cChannel);
|
||||
3424: if( cChannel == GP_CHAT_COUNTRY && bIsKing )
|
||||
3425: msgWithColor += GetStringFromTable(10310);
|
||||
3426: msgWithColor += msg.strMsg;
|
||||
3427:
|
||||
3428: if( cChannel == GP_CHAT_WHISPER &&
|
||||
3429: (int)m_pDlgChatWhisper->GetData() == idPlayer )
|
||||
3430: {
|
||||
3431: pShow1 = dynamic_cast<PAUITEXTAREA>(m_pDlgChatWhisper->GetDlgItem("Txt_Chat"));
|
||||
3432: pszText = (ACHAR *)pShow1->GetText();
|
||||
3433:
|
||||
3434: if( a_strlen(pShow1->GetText()) > 0 )
|
||||
3435: pShow1->AppendText(_AL("\r"));
|
||||
3436:
|
||||
3437: pShow1->AppendText(msgWithColor, pItem ? CDlgChat::m_nMsgIndex : 0, strName, clrName);
|
||||
3438:
|
||||
3439: if( !m_pDlgChat->IsLocked() )
|
||||
3440: {
|
||||
3441: pShow1->ScrollToTop();
|
||||
3442: pShow1->ScrollToBottom();
|
||||
3443: }
|
||||
3444: if( !m_pDlgChatWhisper->IsShow() )
|
||||
3445: m_pMiniBarMgr->FlashDialog(m_pDlgChatWhisper);
|
||||
3446:
|
||||
3447: // 将可点击的消息,保存起来供点击查询
|
||||
3448: if (pItem)
|
||||
3449: {
|
||||
3450: CDlgChat::LINKED_MSG linkedMsg;
|
||||
3451: linkedMsg.pItem = pItem;
|
||||
3452: tmp._ptr = NULL;
|
||||
3453: linkedMsg.nMsgIndex = CDlgChat::m_nMsgIndex++;
|
||||
3454:
|
||||
3455: whisperMsg.push_back(linkedMsg);
|
||||
3456: if( (int)whisperMsg.size() >= CECGAMEUIMAN_MAX_MSGS )
|
||||
3457: {
|
||||
3458: CDlgChat::LINKED_MSG &msgDelete = *(whisperMsg.begin());
|
||||
3459: delete msgDelete.pItem;
|
||||
3460: msgDelete.pItem = NULL;
|
||||
3461: whisperMsg.erase(whisperMsg.begin());
|
||||
3462: }
|
||||
3463: }
|
||||
3464: }
|
||||
3465: else
|
||||
3466: {
|
||||
3467: msg.pItem = pItem;
|
||||
3468: msg.nMsgIndex = CDlgChat::m_nMsgIndex++;
|
||||
3469: tmp._ptr = NULL;
|
||||
3470: msg.strMsg = msgWithColor;
|
||||
3471:
|
||||
3472: int nActiveChannelSet = m_pDlgChat->GetActiveChannelSet();
|
||||
3473: if( gs.bChannel[nActiveChannelSet][cChannel] )
|
||||
3474: {
|
||||
3475: pszText = (ACHAR *)pShow1->GetText();
|
||||
3476:
|
||||
3477: /*
|
||||
3478: if( m_pDlgChat->GetMsgCount(1) >= CECGAMEUIMAN_MAX_MSGS )
|
||||
3479: {
|
||||
3480: pch = a_strstr(pszText, _AL("\r"));
|
||||
3481: if( pch )
|
||||
3482: {
|
||||
3483: ACString strText = pszText;
|
||||
3484: strText.CutLeft(pch - pszText + 1);
|
||||
3485: pShow1->SetText(strText);
|
||||
3486: }
|
||||
3487: }
|
||||
3488: */
|
||||
3489:
|
||||
3490: if( glb_IsTextNotEmpty(pShow1))
|
||||
3491: pShow1->AppendText(_AL("\r"));
|
||||
3492:
|
||||
3493: pShow1->AppendText(msgWithColor, msg.nMsgIndex, strName, clrName);
|
||||
3494:
|
||||
3495: if( !pChat1->IsLocked() )
|
||||
3496: {
|
||||
3497: pShow1->ScrollToTop();
|
||||
3498: pShow1->ScrollToBottom();
|
||||
3499: }
|
||||
3500:
|
||||
@@ -1,32 +0,0 @@
|
||||
# Project Context & Tracking (Antigravity/Gemini)
|
||||
|
||||
## 🎯 Project Overview
|
||||
- **Main Objective:** Porting features (like Task/Chat) from the Perfect World C++ Client to Unity (C#).
|
||||
- **C++ Source Repository:** `d:\perfect-world-source\perfect-world-source\CElement\CElementClient`
|
||||
- **Unity Target Repository:** `c:\Unity\CuongNV\perfect-world-unity`
|
||||
|
||||
## 📊 Current Status
|
||||
- **Active Focus:** Chuyển đổi hệ thống Task/Chat (đang phân tích `DlgTaskTrace.cpp` và `ChatInputHandler.cs`).
|
||||
|
||||
## 🛠️ Trạng thái Công việc (TODOs)
|
||||
- [x] Phân tích logic của `DlgTaskTrace.cpp`
|
||||
- [x] Triển khai `HeadChatBubble.cs` cơ bản.
|
||||
- [ ] Hoàn thiện luồng Chat cơ bản trong `GameSession.cs` (Bỏ qua Task/Policy/Filter).
|
||||
- [ ] Kiểm thử hiển thị chat trên đầu nhân vật.
|
||||
|
||||
## 📌 Quy ước Code (Guidelines)
|
||||
*(Ghi chú các quy tắc code, kiến trúc, hoặc lưu ý đặc biệt đối với dự án Unity tại đây)*
|
||||
- Sử dụng chuẩn C# cho Unity.
|
||||
- Tối ưu hóa UI/Sự kiện (Events).
|
||||
- Thêm log debug ở cả 2 dự án theo quy tắc: `[Cuong] + Tên hàm + Nội dung (nếu có)`.
|
||||
- Ví dụ C++: `a_LogOutput(1, "[Cuong] Method Tick %s", szTxt);`
|
||||
- Ví dụ C#: `Debug.Log("[Cuong] Method Tick " + szTxt);`
|
||||
|
||||
## ⚙️ Quy trình Build & Deploy
|
||||
- **C++ Client (`CElementClient`)**: Sau khi build, cần copy ghi đè các file thay đổi từ thư mục build sang thư mục client.
|
||||
- **Nguồn**: `D:\perfect-world-source\perfect-world-source\CElement\CBin`
|
||||
- **Đích**: `D:\perfect-world-source\perfect-world-source\PW_client\client\element`
|
||||
- *(Đã tạo sẵn script tự động: `D:\perfect-world-source\perfect-world-source\CElement\CopyBuild.bat`)*
|
||||
|
||||
---
|
||||
*File này được tạo để theo dõi tiến độ và lưu giữ ngữ cảnh của dự án. File sẽ được cập nhật liên tục khi chúng ta xử lý các task mới.*
|
||||
Generated
-6
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"name": "perfect-world-unity",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {}
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import os
|
||||
import sys
|
||||
|
||||
def read_file(path, lines=250):
|
||||
encodings = ['utf-8', 'gbk', 'utf-16', 'latin1', 'utf-8-sig']
|
||||
content = ""
|
||||
for enc in encodings:
|
||||
try:
|
||||
with open(path, 'r', encoding=enc) as f:
|
||||
content = f.read()
|
||||
print(f"--- SUCCESS reading {os.path.basename(path)} with encoding {enc} ---")
|
||||
break
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if content:
|
||||
lines_list = content.splitlines()
|
||||
print(f"Total lines: {len(lines_list)}")
|
||||
print("\n".join(lines_list[:lines]))
|
||||
print("...\n" if len(lines_list) > lines else "\n")
|
||||
else:
|
||||
print(f"FAILED to read {path}\n")
|
||||
|
||||
read_file(r"d:\perfect-world-source\perfect-world-source\CElement\CElementClient\DlgTaskTrace.cpp")
|
||||
read_file(r"c:\Unity\CuongNV\perfect-world-unity\Assets\Scripts\ChatInputHandler.cs")
|
||||
Reference in New Issue
Block a user