# Server time, SunMoon phase, và đồng hồ minimap (PC → Unity) Tài liệu tóm tắt luồng thời gian server, `SetTimeOfTheDay`, đồng bộ main thread, và hiển thị canh giờ trên minimap — đối chiếu `CElementClient` (C++) với `perfect-world-unity` (C#). --- ## 1. `CECGame::SetServerTime` (PC — `EC_Game.cpp`) - **`m_iTimeError = iSevTime - time(NULL)`** — lệch giây giữa Unix server và máy client. - **`m_iTimeZoneBias`** — bias múi giờ theo **phút** (ví dụ Bắc Kinh thường **-480**). - **`GetServerLocalTime()`** (không tham số): `serverTime = GetServerGMTTime()` (= `time(NULL) + m_iTimeError`), rồi `serverTime -= m_iTimeZoneBias * 60`, sau đó `gmtime` — tức “giờ địa phương server” dùng để lấy `tm_hour` / `tm_min` / `tm_sec`. - **SunMoon:** `nTimeInDay = hour*3600 + min*60 + sec`, `SetTimeOfTheDay(nTimeInDay / (4.0f * 3600.0f))` — cùng công thức đã port sang Unity. - **Lưu ý thiết kế PC:** chia `(4*3600)` + chuẩn hóa `[0,1)` làm **nhiều mốc giờ thật** có thể trùng cùng một phase (đã phân tích trong phiên làm việc); phần **UI canh giờ** trên PC lại dùng **`GetTimeOfTheDay()`** (không dùng trực tiếp `tm_hour` cho chuỗi minimap). --- ## 2. Unity — `EC_Game.Time.cs` (partial `EC_Game`) - **`SetServerTime(int iSevTime, int iTimeZoneBias)`** - Đồng bộ offset, tính phase giống PC (`iSevTime - bias*60` → giờ trong ngày → `/ (4f*3600f)`), gọi **`SetTimeOfTheDay`**. - **`SetTimeOfTheDay(float vTime)`** — forward tới `CECSunMoon.Instance.SetTimeOfTheDay`. - **`SyncSunMoonTimeOfDayFromServerClock()`** — giống cuối `CECGameRun::CreateWorld` / `CECWorld::InitNatureObjects`: lấy **`GetServerGMTTime()`** rồi áp dụng cùng công thức phase (helper nội bộ). - Log debug có thể dùng tiền tố **`[Cuong]`** theo convention dự án. --- ## 3. Nơi gọi (đối chiếu PC) | Nguồn (PC) | Unity đã nối | |------------|----------------| | Gói **`SERVER_TIME`** → `PostMessage(MSG_SERVERTIME)` → `SetServerTime` | `GameSession.cs` — **`CommandID.SERVER_TIME`**: parse `cmd_server_time`, **`PostToUnityContext`** → `EC_Game.SetServerTime` + `EC_ManMessage.PostMessage` (queue không thread-safe). | | Cuối **`CECGameRun::CreateWorld`** — set lại phase theo `GetServerLocalTime` | `LoginScreenUI.OnEnterWorldComplete` — gọi **`EC_Game.SyncSunMoonTimeOfDayFromServerClock()`**. | **Lý do `PostToUnityContext`:** `NetworkManager` nhận socket trong **`Task.Run`**; gọi trực tiếp `SetServerTime` / `CECSunMoon` / `FindFirstObjectByType` trên luồng đó là **không an toàn** với Unity API và **race** với `EC_ManMessage` queue. --- ## 4. `CECSunMoon` (Unity) - **`SetTimeOfTheDay`**: chuẩn hóa `[0,1)`, gán `m_vTimeOfTheDay`, gọi **`RefreshDayNightFactorsFromPhase()`**. - **`Update`**: tăng phase theo `TIME_SCALE` (giống hướng PC), sau đó **`RefreshDayNightFactorsFromPhase()`**. - **`RefreshDayNightFactorsFromPhase`**: port khối **`m_fDNFactor` / `m_fDNFactorDest`** từ `EC_SunMoon::UpdateWithTime` (PC), phục vụ logic minimap (ngày / sáng / hoàng hôn / đêm). - Getter: **`GetTimeOfTheDay()`**, **`GetDNFactor()`**, **`GetDNFactorDest()`**. --- ## 5. Minimap — chuỗi canh giờ giống PC (`DlgMiniMap.cpp`) Trên PC (trong `Render`), hint đồng hồ: - `nTimeIndex = (int)(12 * GetTimeOfTheDay() + 0.5) % 12` - `GetStringFromTable(1330 + nTimeIndex)` — tên **canh địa** (mười nhị canh). - `int(GetTimeOfTheDay() * 24)` — số “giờ” hiển thị (theo phase game, không phải `tm_hour` server). - `Format(GetStringFromTable(604), ...)` — template chuỗi (thường dạng `%s` + `%d` / tương đương). - **`FixFrame(nTimeItem)`** — icon theo `fDNFactor` / `fDNFactorDest`: **TIME_DAY (0), TIME_MORNING (1), TIME_DUSK (2), TIME_NIGHT (3)**. **Unity — `CDlgMiniMap.cs`:** - **`UpdateSystemClockFromPcMiniMapLogic()`** mỗi `Update`, cùng công thức trên. - SerializeField: **`_txtSystemTime`** (TMP), **`_imgSystemTime`** + **`_systemTimeSprites`** (4 sprite đúng thứ tự enum PC). - Nếu chưa có `CECGameUIMan` / thiếu string: fallback tên **子…亥** và format **`{0}({1}时)`**. **Editor:** gán TMP / Image / sprites trên prefab minimap để thấy chữ và icon; không gán thì không crash, chỉ không cập nhật UI tương ứng. --- ## 6. File chính liên quan | Vai trò | Đường dẫn (Unity) | |--------|---------------------| | Thời gian server + phase | `Assets/PerfectWorld/Scripts/MainFiles/EC_Game.Time.cs` | | SunMoon + DN factor | `Assets/PerfectWorld/Scripts/World/CECSunMoon.cs` | | Nhận `SERVER_TIME` (main thread) | `Assets/PerfectWorld/Scripts/Network/CSNetwork/GameSession.cs` | | Vào world — sync lại phase | `Assets/PerfectWorld/Scripts/UI/Login/LoginScreenUI.cs` (`OnEnterWorldComplete`) | | UI canh giờ minimap | `Assets/PerfectWorld/Scripts/UI/MiniMap/CDlgMiniMap.cs` | **PC tham chiếu:** `EC_Game.cpp` (`SetServerTime`, `GetServerLocalTime`), `EC_GameRun.cpp` (`MSG_SERVERTIME`, cuối `CreateWorld`), `Network/EC_GameDataPrtc.cpp` (`SERVER_TIME`), `DlgMiniMap.cpp` (đoạn `GetTimeOfTheDay` / string 604 / 1330), `EC_SunMoon.cpp` (`UpdateWithTime` — phần DN factor). --- *Tài liệu được tạo để handoff nhanh; cập nhật khi đổi protocol bias (phút vs giây) hoặc khi marshal toàn bộ `HandleServerDataSend` lên main thread.*