406 lines
14 KiB
C#
406 lines
14 KiB
C#
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.txt(C++: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
|
||
}
|
||
} |