Files
test/Assets/PerfectWorld/Scripts/MainFiles/EC_Game.cs
T
2026-01-09 15:11:42 +07:00

406 lines
14 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using BrewMonster;
using BrewMonster.Scripts.Task;
using CSNetwork;
using ModelRenderer.Scripts.GameData;
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using UnityEngine;
using UnityEngine.AddressableAssets;
namespace BrewMonster.Network
{
public partial class EC_Game
{
#region Fields
private static CECFactionMan m_pFactionMan; // Faction manager
public static bool g_bEnableFortressDeclareWar = false;
private static ATaskTemplMan m_pTaskMan; // Task template manager
private static elementdataman m_pElementDataMan; // global element templates manager
private static CECGameRun m_pGameRun => CECGameRun.Instance; // Game running object
private static CECGFXCaster m_pGFXCaster; // GFX caster
private static BrewMonster.CECStringTab m_FixedMsgs; // Fixed message table
private static BrewMonster.CECStringTab m_ItemDesc; // Item desciption string table
private static BrewMonster.CECStringTab m_ItemExtDesc; // Item extend description string table
private static BrewMonster.CECStringTab m_SkillDesc = new CECStringTab(); // Skill description string table
private static BrewMonster.CECStringTab m_BuffDesc; // Buff description string table
private static Dictionary<int, ItemMsgMapEntry> m_ItemMsgMap; // TemplateId -> (MessageId, DisplayMode)
private static CECConfigs m_pConfigs;
private static int m_iCurCursor; // Current cursor
#endregion
#region Properties
public static ATaskTemplMan GetTaskTemplateMan()
{
return m_pTaskMan;
}
public static elementdataman GetElementDataMan()
{
return m_pElementDataMan;
}
// String table getters
public static CECFactionMan GetFactionMan() { return m_pFactionMan; }
public static BrewMonster.CECStringTab GetFixedMsgs()
{
return m_FixedMsgs;
}
public static BrewMonster.CECStringTab GetItemDesc()
{
return m_ItemDesc;
}
public static BrewMonster.CECStringTab GetItemExtDesc()
{
return m_ItemExtDesc;
}
public static BrewMonster.CECStringTab GetSkillDesc()
{
return m_SkillDesc;
}
public static BrewMonster.CECStringTab GetBuffDesc()
{
return m_BuffDesc;
}
public static bool TryGetItemMsg(int templateId, out int messageId, out int displayMode)
{
messageId = 0;
displayMode = 0;
if (m_ItemMsgMap != null && m_ItemMsgMap.TryGetValue(templateId, out var entry))
{
messageId = entry.MessageId;
displayMode = entry.DisplayMode;
return true;
}
return false;
}
#endregion
#region Public Methods
public static bool Init()
{
m_pElementDataMan = ElementDataManProvider.GetElementDataMan();
// Load task templates
// if (m_pTaskMan == null) m_pTaskMan = new ATaskTemplMan();
m_pTaskMan = new ATaskTemplMan();
m_pTaskMan.Init(m_pElementDataMan);
m_pConfigs = new CECConfigs(); /*ElementClient.g_GameCfgs*/;
if (!m_pTaskMan.InitStorageTask())
{
BMLogger.LogError("[Dat]- CECGame::Init, Storage task Init Failed!");
// return false;
}
// Create GFX caster
if (m_pGFXCaster == null)
{
m_pGFXCaster = new CECGFXCaster();
// return false;
}
GetGameRun().Init();
InitializeStringTables();
// Load coord_data.txt (C++: Configs/Coord_data.txt) for clickable task links auto-move.
// 加载 coord_data.txtC++Configs/Coord_data.txt)用于任务可点击链接的自动移动。
LoadObjectCoord();
return true;
}
public static CECConfigs GetConfigs() { return m_pConfigs; }
//todo release?
/// <summary>
/// Initialize all string tables with their respective data files
/// </summary>
private static void InitializeStringTables()
{
// Initialize string table instances
m_FixedMsgs = new BrewMonster.CECStringTab();
m_ItemDesc = new BrewMonster.CECStringTab();
m_ItemExtDesc = new BrewMonster.CECStringTab();
m_SkillDesc = new BrewMonster.CECStringTab();
m_BuffDesc = new BrewMonster.CECStringTab();
try
{
// Addressables-only loading (no StreamingAssets/configs file IO).
// These must match the Addressables "Address" values configured in `Assets/AddressableAssetsData/...`.
Addressables.InitializeAsync().WaitForCompletion();
var fixedMsgTa = Addressables.LoadAssetAsync<TextAsset>("Assets/Addressable/fixed_msg.txt").WaitForCompletion();
if (!m_FixedMsgs.InitFromTextAsset(fixedMsgTa, true))
{
Debug.LogWarning("[EC_Game] Failed to load fixed_msg.txt");
}
var itemDescTa = Addressables.LoadAssetAsync<TextAsset>("Assets/Addressable/item_desc.txt").WaitForCompletion();
if (!m_ItemDesc.InitFromTextAsset(itemDescTa, true))
{
Debug.LogWarning("[EC_Game] Failed to load item_desc.txt");
}
var itemExtDescTa = Addressables.LoadAssetAsync<TextAsset>("Assets/Addressable/item_ext_desc.txt").WaitForCompletion();
if (!m_ItemExtDesc.InitFromTextAsset(itemExtDescTa, true))
{
Debug.LogWarning("[EC_Game] Failed to load item_ext_desc.txt");
}
var skillStrTa = Addressables.LoadAssetAsync<TextAsset>("Assets/Addressable/skillstr.txt").WaitForCompletion();
if (!m_SkillDesc.InitFromTextAsset(skillStrTa, true))
{
Debug.LogWarning("[EC_Game] Failed to load skillstr.txt");
}
// Note: There's no buff_desc.txt file in the configs folder
// You may need to create this file or use a different source for buff descriptions
// (If you add it to Addressables later, load it here.)
// Load item message map (template -> message id)
LoadItemMsgMap();
Debug.Log("[EC_Game] String tables initialized successfully");
}
catch (System.Exception ex)
{
Debug.LogError($"[EC_Game] Error initializing string tables: {ex.Message}");
}
}
private struct ItemMsgMapEntry
{
public int MessageId;
public int DisplayMode;
}
private static void LoadItemMsgMap()
{
m_ItemMsgMap = new Dictionary<int, ItemMsgMapEntry>();
try
{
Addressables.InitializeAsync().WaitForCompletion();
var mapTa = Addressables.LoadAssetAsync<TextAsset>("Assets/Addressable/item_msg_map.txt").WaitForCompletion();
if (mapTa == null || string.IsNullOrEmpty(mapTa.text))
{
Debug.LogWarning(
"[EC_Game] item_msg_map.txt not found; descriptions will fall back to template IDs");
return;
}
using var sr = new StringReader(mapTa.text);
string raw;
while ((raw = sr.ReadLine()) != null)
{
var line = raw.Trim();
if (line.Length == 0) continue;
if (line.StartsWith("//")) continue;
// Expect: templateId <ws> messageId <ws> displayMode
var parts = line.Split(new char[] { '\t', ' ' }, System.StringSplitOptions.RemoveEmptyEntries);
if (parts.Length < 2) continue;
if (!int.TryParse(parts[0], out int templateId)) continue;
if (!int.TryParse(parts[1], out int messageId)) continue;
int displayMode = 0;
if (parts.Length >= 3) int.TryParse(parts[2], out displayMode);
m_ItemMsgMap[templateId] = new ItemMsgMapEntry { MessageId = messageId, DisplayMode = displayMode };
}
}
catch (System.Exception ex)
{
Debug.LogWarning($"[EC_Game] Failed to load item_msg_map: {ex.Message}");
}
}
public static CECGameRun GetGameRun()
{
return m_pGameRun;
}
public static CECGFXCaster GetGFXCaster()
{
if (m_pGFXCaster == null) m_pGFXCaster = new CECGFXCaster();
return m_pGFXCaster;
}
// Change current cursor
public static int ChangeCursor(int iCursor)
{
if (iCursor == m_iCurCursor)
return iCursor;
// if (m_aCursors[iCursor])
// m_pA3DDevice->SetCursor(m_aCursors[iCursor]);
//
// // force show this cursor
// ShowCursor(g_pGame->GetA3DDevice()->GetShowCursor());
//
// if( l_idMainThread != GetCurrentThreadId() )
// {
// // ::SetCursor must be called from main thread to take effects, so here we should post a WM_SETCURSOR message
// // to ensure the main thread receive WM_SETCURSOR and update the cursor again
// PostMessage(m_GameInit.hWnd, WM_SETCURSOR, (WPARAM)m_GameInit.hWnd, MAKELPARAM(HTCLIENT, WM_MOUSEMOVE));
// }
int iOldCursor = m_iCurCursor;
m_iCurCursor = iCursor;
return iOldCursor;
}
// Get server GMT(UTC) time
public static int GetServerGMTTime()
{
long unixTime = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
return (int)unixTime + m_iTimeError;
}
////////////////////////////////////////////////////////////////////////////////
//
// Coord_data.txt support (C++: Configs/Coord_data.txt, CECGame::LoadObjectCoord/GetObjectCoord)
//
////////////////////////////////////////////////////////////////////////////////
private struct OBJECT_COORD
{
public string strMap;
public Vector3 vPos;
}
private static readonly Dictionary<string, List<OBJECT_COORD>> m_CoordTab =
new Dictionary<string, List<OBJECT_COORD>>(StringComparer.OrdinalIgnoreCase);
private static bool m_bCoordLoaded = false;
public static bool LoadObjectCoord()
{
if (m_bCoordLoaded)
{
return true;
}
try
{
Addressables.InitializeAsync().WaitForCompletion();
var ta = Addressables.LoadAssetAsync<TextAsset>("Assets/Addressable/coord_data.txt").WaitForCompletion();
if (ta == null)
{
Debug.LogError("[EC_Game] LoadObjectCoord: failed to load Addressable 'Assets/Addressable/coord_data.txt'");
return false;
}
ParseCoordDataText(ta.text);
m_bCoordLoaded = true;
Debug.Log($"[EC_Game] LoadObjectCoord: loaded {m_CoordTab.Count} coord keys from coord_data.txt");
return true;
}
catch (Exception ex)
{
Debug.LogError($"[EC_Game] LoadObjectCoord exception: {ex}");
return false;
}
}
private static void ParseCoordDataText(string text)
{
m_CoordTab.Clear();
if (string.IsNullOrEmpty(text))
{
return;
}
using var sr = new StringReader(text);
string line;
int lineNo = 0;
while ((line = sr.ReadLine()) != null)
{
lineNo++;
if (string.IsNullOrWhiteSpace(line))
{
continue;
}
line = line.Trim();
if (line.StartsWith("#", StringComparison.Ordinal) || line.StartsWith("//", StringComparison.Ordinal))
{
continue;
}
if (lineNo == 1 && line.StartsWith("ID", StringComparison.OrdinalIgnoreCase))
{
continue;
}
string[] parts = line.Split((char[])null, StringSplitOptions.RemoveEmptyEntries);
if (parts.Length < 5)
{
continue;
}
string key = parts[0];
string map = parts[1];
if (!float.TryParse(parts[2], NumberStyles.Float, CultureInfo.InvariantCulture, out float x) ||
!float.TryParse(parts[3], NumberStyles.Float, CultureInfo.InvariantCulture, out float y) ||
!float.TryParse(parts[4], NumberStyles.Float, CultureInfo.InvariantCulture, out float z))
{
continue;
}
var coord = new OBJECT_COORD
{
strMap = map,
vPos = new Vector3(x, y, z),
};
if (!m_CoordTab.TryGetValue(key, out var list))
{
list = new List<OBJECT_COORD>(1);
m_CoordTab[key] = list;
}
list.Add(coord);
}
}
public static bool TryGetFirstObjectCoord(string targetId, out Vector3 pos, out string map)
{
pos = default;
map = null;
if (string.IsNullOrWhiteSpace(targetId))
{
return false;
}
if (!m_bCoordLoaded)
{
LoadObjectCoord();
}
if (!m_CoordTab.TryGetValue(targetId, out var list) || list == null || list.Count == 0)
{
return false;
}
pos = list[0].vPos;
map = list[0].strMap;
return true;
}
#endregion
}
}