1351 lines
48 KiB
C#
1351 lines
48 KiB
C#
using BrewMonster;
|
||
using BrewMonster.Common;
|
||
using BrewMonster.Managers;
|
||
using BrewMonster.Network;
|
||
using BrewMonster.Scripts;
|
||
using BrewMonster.Scripts.Managers;
|
||
using BrewMonster.Scripts.World;
|
||
using BrewMonster.UI;
|
||
using CSNetwork;
|
||
using CSNetwork.GPDataType;
|
||
using CSNetwork.Protocols.RPCData;
|
||
using PerfectWorld.Scripts.Shop;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Data;
|
||
using System.IO;
|
||
using System.Linq;
|
||
using System.Threading.Tasks;
|
||
using Unity.Cinemachine;
|
||
using Unity.VisualScripting;
|
||
using UnityEngine;
|
||
using UnityEngine.SceneManagement;
|
||
|
||
public partial class CECGameRun : ITickable
|
||
{
|
||
private static CECGameRun instance;
|
||
|
||
#region PROPERTIES AND FIELDS
|
||
|
||
private const uint USERCFG_VERSION = 3;
|
||
|
||
private GameObject _playerPrefab;
|
||
private GameObject _monsterPrefab;//CECMonster
|
||
private GameObject _npcServerPrefab;//CECNPCServer
|
||
private GameObject _petServerPrefab;//CECPet
|
||
private GameObject _petMountServerPrefab;//CECPetRider
|
||
|
||
private CECTeamMan m_pTeamMan; // Team manager
|
||
private CECShortcutSet m_pNormalSCS; // Normal shortcut set
|
||
private CECShortcutSet m_pTeamSCS; // Team shortcut set
|
||
private CECShortcutSet m_pTradeSCS; // Trade shortcut set
|
||
private CECShortcutSet m_pPoseSCS; // Pose shortcut set
|
||
private CECShortcutSet m_pFactionSCS; // Faction shortcut set
|
||
|
||
// private GameRunConfig _gameRunConfig;
|
||
//[SerializeField] private Transform ground;
|
||
CECHostPlayer m_pHostPlayer;
|
||
private CECWorld m_pWorld;
|
||
|
||
|
||
protected CECUIManager m_pUIManager; // UI manager
|
||
|
||
CECPendingActionArray m_pendingLogout;
|
||
|
||
#endregion
|
||
|
||
public CECWorld GetWorld()
|
||
{
|
||
if (m_pWorld == null)
|
||
{
|
||
m_pWorld = new CECWorld();
|
||
}
|
||
return m_pWorld;
|
||
}
|
||
|
||
public CECTeamMan GetTeamMan() { return m_pTeamMan; }
|
||
|
||
// Get shortcut sets
|
||
public CECShortcutSet GetGenCmdShortcuts() { return m_pNormalSCS; }
|
||
public CECShortcutSet GetTeamCmdShortcuts() { return m_pTeamSCS; }
|
||
public CECShortcutSet GetTradeCmdShortcuts() { return m_pTradeSCS; }
|
||
public CECShortcutSet GetPoseCmdShortcuts() { return m_pPoseSCS; }
|
||
public CECShortcutSet GetFactionCmdShortcuts() { return m_pFactionSCS; }
|
||
|
||
private static Dictionary<int, CECInstance> m_InstTab = new Dictionary<int, CECInstance>();
|
||
|
||
static RoleInfo l_SelRoleInfo; // Selected character's role info.
|
||
|
||
private int m_iDExpEndTime = 0;
|
||
|
||
// Cache for SaveConfigsToServer: last sent config data to skip duplicate sends
|
||
private byte[] m_pCfgDataBuf;
|
||
private int m_iCfgDataSize;
|
||
|
||
// Logout flag (C++: m_iLogoutFlag)
|
||
// Selling role ID for role trade (C++: SetSellingRoleID/GetSellingRoleID)
|
||
private int m_iSellingRoleID;
|
||
|
||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||
private static void AfterSceneLoad()
|
||
{
|
||
l_SelRoleInfo = null;
|
||
m_InstTab = new Dictionary<int, CECInstance>();
|
||
}
|
||
public void Init()
|
||
{
|
||
#if !UNITY_EDITOR
|
||
Debug.unityLogger.logEnabled = false;
|
||
QualitySettings.vSyncCount = 0;
|
||
Application.targetFrameRate = 30;
|
||
#endif
|
||
instance = this;
|
||
// _gameRunConfig = Resources.Load<GameRunConfig>("GameRunConfig");
|
||
// _playerPrefab = _gameRunConfig.PlayerPrefab;
|
||
// _monsterPrefab = _gameRunConfig.MonsterPrefab;
|
||
// _npcServerPrefab = _gameRunConfig.NpcServerPrefab;
|
||
LoadPrefabs();
|
||
m_pTeamMan = new CECTeamMan();
|
||
|
||
// LoadPrefabs();
|
||
EC_ManMessage.RegisterHandler(this);
|
||
|
||
// Load instance information
|
||
//if (!LoadInstanceInfo("Configs\\instance.txt"))
|
||
//{
|
||
// //glb_ErrorOutput(ECERR_FAILEDTOCALL, "CECGameRun::Init", __LINE__);
|
||
// //return false;
|
||
//}
|
||
var instanceOB = Resources.Load<instanceDataAsset>("instance");
|
||
for(int i = 0; i < instanceOB.items.Length; i++)
|
||
{
|
||
if (!m_InstTab.ContainsKey(instanceOB.items[i].m_id))
|
||
{
|
||
var cecInstance = new CECInstance();
|
||
cecInstance.Load(instanceOB.items[i]);
|
||
m_InstTab.Add(instanceOB.items[i].m_id, cecInstance);
|
||
}
|
||
}
|
||
AddressableManager.Instance.OnDispose += Dispose;
|
||
if (m_pWorld == null)
|
||
m_pWorld = new CECWorld();
|
||
|
||
m_pendingLogout = new CECPendingActionArray( false);
|
||
|
||
TickInvoker.Instance.RegisterTickable(this);
|
||
}
|
||
|
||
private static void Dispose()
|
||
{
|
||
TickInvoker.Instance.UnregisterTickable(instance);
|
||
instance = null;
|
||
}
|
||
|
||
private void LoadPrefabs()
|
||
{
|
||
BMLogger.LogWarning("CECGameRun::LoadPrefabs, Loading prefabs from Resources. Consider using Addressables for better performance and memory management.");
|
||
_playerPrefab = Resources.Load<GameObject>(AddressResourceConfig.PlayerPrefab);
|
||
PrefabPoolManager.Instance.InitPool(_playerPrefab);
|
||
_monsterPrefab = Resources.Load<GameObject>(AddressResourceConfig.MonsterPrefab);
|
||
PrefabPoolManager.Instance.InitPool(_monsterPrefab, defaultCapacity: 200, maxSize: 250);
|
||
_npcServerPrefab = Resources.Load<GameObject>(AddressResourceConfig.NpcServerPrefab);
|
||
PrefabPoolManager.Instance.InitPool(_npcServerPrefab, defaultCapacity: 25, maxSize: 100);
|
||
_petServerPrefab = Resources.Load<GameObject>(AddressResourceConfig.PetServerPrefab);
|
||
PrefabPoolManager.Instance.InitPool(_petServerPrefab);
|
||
_petMountServerPrefab = Resources.Load<GameObject>(AddressResourceConfig.PetMountServerPrefab);
|
||
PrefabPoolManager.Instance.InitPool(_petMountServerPrefab);
|
||
#if UNITY_EDITOR
|
||
if (_playerPrefab == null)
|
||
{
|
||
BMLogger.LogError("CECGameRun::LoadPrefabs, Failed to load player prefab.");
|
||
}
|
||
if (_monsterPrefab == null)
|
||
{
|
||
BMLogger.LogError("CECGameRun::LoadPrefabs, Failed to load _monsterPrefab prefab.");
|
||
}
|
||
if (_npcServerPrefab == null)
|
||
{
|
||
BMLogger.LogError("CECGameRun::LoadPrefabs, Failed to load _npcServerPrefab prefab.");
|
||
}
|
||
#endif
|
||
}
|
||
public bool StartGame(int idInst, Vector3 vHostPos)
|
||
{
|
||
// TODO: Implement the rest of the StartGame logic based on the original C++ code, including:
|
||
// End current game state
|
||
EndGameState();
|
||
//
|
||
// memset(&m_WallowInfo, 0, sizeof(m_WallowInfo));
|
||
m_iGameState = (int)GameState.GS_GAME;
|
||
//
|
||
// if (!g_pGame.LoadInGameRes())
|
||
// {
|
||
// a_LogOutput(1, "CECGameRun::StartGame, Failed to call LoadInGameRes().");
|
||
// return false;
|
||
// }
|
||
//
|
||
// // Create message manager
|
||
// if (!(m_pMessageMan = new CECMessageMan(this)))
|
||
// {
|
||
// glb_ErrorOutput(ECERR_NOTENOUGHMEMORY, "CECGameRun::StartGame", __LINE__);
|
||
// return false;
|
||
// }
|
||
//
|
||
// Create default game world
|
||
//if (!JumpToInstance(idInst, vHostPos))
|
||
//{
|
||
// // a_LogOutput(1, "CECGameRun::StartGame, Failed to create game world.");
|
||
// return false;
|
||
//}
|
||
//
|
||
// // ÉèÖÿç·þ³É¹¦±êʶ£¬ÒÔÀûÓÚ CECGameUIMan ¸ù¾Ý¿ç·þ״̬×öÏàÓ¦³õʼ»¯
|
||
// if (CECCrossServer::Instance().IsWaitLogin()){
|
||
// CECCrossServer::Instance().OnLoginSuccess();
|
||
// }
|
||
// if (CECReconnect::Instance().IsReconnecting()){
|
||
// CECReconnect::Instance().OnReconnectSuccess();
|
||
// }
|
||
//
|
||
// // Create host player
|
||
// if (!CreateHostPlayer())
|
||
// {
|
||
// a_LogOutput(1, "CECGameRun::StartGame, Failed to create host player.");
|
||
// return false;
|
||
// }
|
||
//
|
||
// // Create team manager
|
||
// if (!(m_pTeamMan = new CECTeamMan))
|
||
// {
|
||
// glb_ErrorOutput(ECERR_NOTENOUGHMEMORY, "CECGameRun::StartGame", __LINE__);
|
||
// return false;
|
||
// }
|
||
//
|
||
// // Reset faction manager
|
||
// g_pGame.GetFactionMan().Release(false);
|
||
//
|
||
// Create shortcuts
|
||
if (!CreateShortcuts())
|
||
{
|
||
// a_LogOutput(1, "CECGameRun::StartGame, Failed to create shortcuts");
|
||
return false;
|
||
}
|
||
//
|
||
// // Change UI manager
|
||
// if (!m_pUIManager.ChangeCurUIManager(CECUIManager::UIMAN_INGAME))
|
||
// {
|
||
// a_LogOutput(1, "CECGameRun::StartGame, Failed to change UI manager.");
|
||
// return false;
|
||
// }
|
||
// m_pInputFilter.LoadHotKey();
|
||
//
|
||
// CECGameUIMan* pGameUIMan = m_pUIManager.GetInGameUIMan();
|
||
// if (pGameUIMan)
|
||
// pGameUIMan.ChangeWorldInstance(idInst);
|
||
//
|
||
// l_SaveCfgCnt.Reset();
|
||
//
|
||
// // Change cursor to default icon
|
||
// g_pGame.ChangeCursor(RES_CUR_NORMAL);
|
||
// // Discard current frame
|
||
// g_pGame.DiscardFrame();
|
||
//
|
||
// // Clear frame controller
|
||
// memset(&l_fc, 0, sizeof (l_fc));
|
||
//
|
||
// // ³õʼ»¯ÍøÂçÑÓ³Ù²éѯ
|
||
// l_bFirstQuery = true;
|
||
// m_iInGameDelay = 0;
|
||
// l_DelayQueryCounter.Reset();
|
||
//
|
||
// l_QueryServerTime.Reset();
|
||
//
|
||
// // clear the selling id
|
||
// m_SellingRoleID = 0;
|
||
//
|
||
// // ÏÂÔØÆ÷ÏìÓ¦½øÈëÓÎϷ״̬
|
||
// if( g_pGame.GetConfigs().IsMiniClient() )
|
||
// CECMCDownload::GetInstance().SendSwitchGame(true);
|
||
//
|
||
return true;
|
||
}
|
||
|
||
public bool JumpToInstance(int idInst, Vector3 vHostPos, int iParallelWorldID = 0, Action actDone = null)
|
||
{
|
||
CECInstance pInst = GetInstance(idInst);
|
||
string nameScene = UnityGameSession.Instance.GetWorldInstanceName(idInst);
|
||
if (pInst == null || string.IsNullOrEmpty(nameScene))
|
||
{
|
||
CECGameUIMan pGameUI = EC_Game.GetGameRun().GetUIManager().GetInGameUIMan();
|
||
if (pGameUI != null)
|
||
pGameUI.ShowErrorMsg(pGameUI.GetStringFromTable(10700), "");
|
||
|
||
//EC_Game.GetGameSession().SetBreakLinkFlag(CECGameSession::LBR_MAP_INVALID);
|
||
//a_LogOutput(1, "CECGameRun::JumpToInstance, wrong instance id: %d", idInst);
|
||
return false;
|
||
}
|
||
if(m_pWorld != null)
|
||
{
|
||
if (m_pWorld.GetInstanceID() == pInst.GetID() /*&& m_pWorld.IsValid()*/)
|
||
{
|
||
// TO DO: fix later
|
||
//int iLast = m_pWorld.GetCurParallelWorld();
|
||
//if (iLast == iParallelWorldID)
|
||
//{
|
||
// //m_pWorld.SetLoadCenter(vPos);
|
||
//}
|
||
//else
|
||
//{
|
||
// m_pWorld.OnParallelWorldChange(vPos, iParallelWorldID);
|
||
// CECUIHelper::UpdateParallelWorld();
|
||
// if (iLast != 0)
|
||
// {
|
||
// CECGameUIMan pGameUI = EC_Game.GetGameRun().GetUIManager().GetInGameUIMan();
|
||
// if (pGameUI != null)
|
||
// {
|
||
// ACString strMsg;
|
||
// strMsg.Format(pGameUI.GetStringFromTable(10703), pInst.GetName(), iParallelWorldID);
|
||
// CECUIHelper::AddHeartBeatHint(strMsg);
|
||
// }
|
||
// }
|
||
//}
|
||
// Same map/instance: still run Goto completion (SetPos, move stamp, etc.); was missing and left player stuck until next move/jump.
|
||
// 同地图/实例:仍需执行 Goto 完成逻辑(SetPos、移动同步等);此前未调用导致传送不生效直到再次移动或跳跃。
|
||
actDone?.Invoke();
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
// Release current world
|
||
ReleaseWorld();
|
||
}
|
||
}
|
||
SceneLoader.SceneLoadProcess = SceneLoadProcess.Loading;
|
||
SceneLoader.LoadingProgress = 0;
|
||
UnityGameSession.Instance.LoadScene(nameScene, LoadSceneMode.Single,
|
||
(progress) =>
|
||
{
|
||
LoadingSceneController.Instance.SetProgress(progress);
|
||
},
|
||
(value) =>
|
||
{
|
||
//isDoneWorldRender = value;
|
||
//isDoneNPCRender = true;
|
||
//isDoneWorldRender = true;
|
||
//actLoadChar?.Invoke();
|
||
//UnityGameSession.EnterWorldAsync(roleInfo, OnEnterWorldComplete);
|
||
m_pWorld.SetInstanceID(idInst);
|
||
actDone?.Invoke();
|
||
});
|
||
return true;
|
||
}
|
||
|
||
public static CECGameRun Instance
|
||
{
|
||
get
|
||
{
|
||
if (instance == null)
|
||
{
|
||
instance = new CECGameRun();
|
||
}
|
||
return instance;
|
||
}
|
||
}
|
||
|
||
public CECGameRun()
|
||
{
|
||
m_iGameState = (int)GameState.GS_NONE;
|
||
}
|
||
|
||
public CECHostPlayer GetHostPlayer()
|
||
{
|
||
return m_pHostPlayer;
|
||
}
|
||
public void InitCharacter(cmd_self_info_1 info)
|
||
{
|
||
if (_playerPrefab == null)
|
||
{
|
||
BMLogger.LogError("null _playerPrefab");
|
||
return;
|
||
}
|
||
|
||
// 同步世界/地图ID给任务系统(GetPos 返回的 worldId)
|
||
// English: Sync map ID to task system (worldId returned by GetPos).
|
||
// We don't receive mapId in cmd_self_info_1, so use selected RoleInfo.worldtag as current map id.
|
||
var roleInfo = UnityGameSession.Instance != null ? UnityGameSession.Instance.GetRoleInfo() : null;
|
||
if (roleInfo != null)
|
||
{
|
||
int idInst = roleInfo.worldtag;
|
||
if (idInst > 0)
|
||
{
|
||
// Ensure instance exists in table (minimal stub instance is fine for now)
|
||
if (!m_InstTab.ContainsKey(idInst))
|
||
m_InstTab.Add(idInst, new CECInstance());
|
||
|
||
// Update global world instance id used by task checks
|
||
CECGameRun.Instance?.GetWorld()?.SetInstanceID(idInst);
|
||
}
|
||
}
|
||
|
||
CECPlayer.InitStaticRes();
|
||
m_pHostPlayer = PrefabPoolManager.Instance.Spawn(_playerPrefab, Vector3.zero, Quaternion.identity, ObjectSpawner.Instance.transform).AddComponent<CECHostPlayer>();
|
||
m_pHostPlayer.InitCharacter(info);
|
||
|
||
if (m_pHostPlayer != null)
|
||
{
|
||
var t = Type.GetType("BrewMonster.UI.SelectedTargetHUDController, Assembly-CSharp");
|
||
if (t != null && m_pHostPlayer.GetComponent(t) == null)
|
||
m_pHostPlayer.gameObject.AddComponent(t);
|
||
}
|
||
}
|
||
public CECMonster GetMonster()
|
||
{
|
||
//return ObjectSpawner.Instance.InstantiateObject(_monsterPrefab, setThisAsParent: true)
|
||
// .GetComponent<CECMonster>();
|
||
return PrefabPoolManager.Instance.Spawn(_monsterPrefab, Vector3.zero, Quaternion.identity, ObjectSpawner.Instance.transform)
|
||
.GetComponent<CECMonster>();
|
||
}
|
||
public RoleInfo GetSelectedRoleInfo()
|
||
{
|
||
return l_SelRoleInfo;
|
||
}
|
||
public void SetSelectedRoleInfo(RoleInfo Info)
|
||
{
|
||
l_SelRoleInfo = Info;
|
||
}
|
||
public CECNPCServer GetNPCServer()
|
||
{
|
||
return ObjectSpawner.Instance.InstantiateObject(_npcServerPrefab, setThisAsParent: true).GetComponent<CECNPCServer>();
|
||
}
|
||
|
||
public async void ShowVfx(string assetAddress, Vector3 position, Transform parent, float timeLife)
|
||
{
|
||
var prefab = await AddressableManager.Instance.LoadPrefabAsync(assetAddress);
|
||
if (prefab == null)
|
||
{
|
||
BMLogger.LogError("Failed to load prefab: " + assetAddress);
|
||
return;
|
||
}
|
||
|
||
BMLogger.Log($"[GFX Spawn] ShowVfx - Asset: {assetAddress}, Prefab Name: {prefab.name}, Position: {position}, Parent: {(parent != null ? parent.name : "null")}, LifeTime: {timeLife}s");
|
||
|
||
if (parent == null)
|
||
{
|
||
var obj = ObjectSpawner.Instance.InstantiateObject(prefab, setThisAsParent: true);
|
||
obj.transform.position = position;
|
||
BMLogger.Log($"[GFX Spawn] ShowVfx - Instantiated object (no parent): {obj.name}");
|
||
DestroyTestVfx(obj, timeLife);
|
||
}
|
||
else
|
||
{
|
||
var obj = ObjectSpawner.Instance.InstantiateObject(prefab, parent, false);
|
||
obj.transform.position = position;
|
||
BMLogger.Log($"[GFX Spawn] ShowVfx - Instantiated object (with parent): {obj.name}");
|
||
DestroyTestVfx(obj, timeLife);
|
||
}
|
||
}
|
||
public void DestroyTestVfx(GameObject go, float delayTime)
|
||
{
|
||
ObjectSpawner.Instance.DestroyGameObject(go, delayTime);
|
||
}
|
||
public GameObject InitCharacter(info_player_1 info)
|
||
{
|
||
if (_playerPrefab == null)
|
||
{
|
||
Debug.LogError("null prefab");
|
||
return null;
|
||
}
|
||
GameObject character = PrefabPoolManager.Instance.Spawn(_playerPrefab, Vector3.zero, Quaternion.identity, ObjectSpawner.Instance.transform);
|
||
return character.gameObject;
|
||
}
|
||
|
||
//private void Update()
|
||
//{
|
||
// if (hostPlayer == null || hostPlayer.transform == null)
|
||
// return;
|
||
|
||
// bool rightClick = Input.GetMouseButton(1);
|
||
|
||
// if (rightClick)
|
||
// {
|
||
// // Bật khả năng xoay khi giữ chuột phải
|
||
// freeLookCam.m_XAxis.m_MaxSpeed = rotateSpeedX;
|
||
// freeLookCam.m_YAxis.m_MaxSpeed = rotateSpeedY;
|
||
|
||
// // Ghi giá trị chuột thủ công (nếu muốn override Input System cũ)
|
||
// float mouseX = Input.GetAxis("Mouse X");
|
||
// float mouseY = Input.GetAxis("Mouse Y");
|
||
|
||
// // Xoay camera theo hướng chuột
|
||
// freeLookCam.m_XAxis.Value += mouseX * Time.deltaTime * rotateSpeedX;
|
||
// freeLookCam.m_YAxis.Value -= mouseY * Time.deltaTime * (rotateSpeedY / 100f);
|
||
// }
|
||
// else
|
||
// {
|
||
// // Khi thả chuột thì khoá xoay
|
||
// freeLookCam.m_XAxis.m_MaxSpeed = 0;
|
||
// freeLookCam.m_YAxis.m_MaxSpeed = 0;
|
||
// }
|
||
//}
|
||
|
||
/// <summary>
|
||
/// Load necessary user configs (UI, shortcut, accelerate keys) from server
|
||
/// 从服务器加载必要的用户配置(UI、快捷键、加速键)
|
||
/// </summary>
|
||
/// <param name="pDataBuf">Config data buffer / 配置数据缓冲区</param>
|
||
/// <param name="iDataSize">Data size / 数据大小</param>
|
||
/// <returns>True if loaded successfully / 加载成功返回true</returns>
|
||
public bool LoadConfigsFromServer(byte[] pDataBuf, int iDataSize)
|
||
{
|
||
BMLogger.Log($"MH CECGameRun.LoadConfigsFromServer, iDataSize = {iDataSize}");
|
||
|
||
if (pDataBuf == null || iDataSize == 0)
|
||
{
|
||
BMLogger.LogError("CECGameRun::LoadConfigsFromServer, configs data is empty");
|
||
return false;
|
||
}
|
||
|
||
int offset = 0;
|
||
|
||
// Read version / 读取版本号
|
||
uint dwVer = System.BitConverter.ToUInt32(pDataBuf, offset);
|
||
offset += sizeof(uint);
|
||
|
||
if (dwVer > USERCFG_VERSION)
|
||
{
|
||
Debug.LogError($"CECGameRun::LoadConfigsFromServer, version {dwVer} > {USERCFG_VERSION}");
|
||
return false;
|
||
}
|
||
|
||
byte[] pUncompBuf = null;
|
||
uint dwRealLen = (uint)(iDataSize - sizeof(uint));
|
||
if (dwRealLen < 0)
|
||
{
|
||
dwRealLen = 0;
|
||
}
|
||
byte[] pData = pDataBuf;
|
||
|
||
if (dwVer >= 3)
|
||
{
|
||
// Uncompress config data / 解压配置数据
|
||
dwRealLen = 4096;
|
||
pUncompBuf = new byte[dwRealLen];
|
||
|
||
// Extract compressed data / 提取压缩数据
|
||
byte[] compressedData = new byte[iDataSize - sizeof(uint)];
|
||
System.Array.Copy(pDataBuf, offset, compressedData, 0, compressedData.Length);
|
||
|
||
// TODO: Implement AFilePackage::Uncompress equivalent
|
||
int iRes = AFilePackage.Uncompress(compressedData, compressedData.Length, pUncompBuf, ref dwRealLen);
|
||
|
||
if (iRes != 0)
|
||
{
|
||
// 解压失败,过程出错 / Decompression failed, process error
|
||
BMLogger.LogError($"CECGameRun::LoadConfigsFromServer, Failed to uncompress configs data ({iRes}:{iDataSize})");
|
||
return false;
|
||
}
|
||
|
||
pData = pUncompBuf;
|
||
}
|
||
|
||
try
|
||
{
|
||
// Create data reader / 创建数据读取器
|
||
CECDataReader dr = new CECDataReader(pData, (int)dwRealLen);
|
||
|
||
// Load host configs / 加载主机配置
|
||
CECHostPlayer pHost = GetHostPlayer();
|
||
if (pHost != null)
|
||
{
|
||
int iSize = dr.ReadInt();
|
||
byte[] hostConfigData = dr.ReadData(iSize);
|
||
if (!pHost.LoadConfigData(hostConfigData))
|
||
{
|
||
BMLogger.LogError("CECGameRun::LoadConfigsFromServer, Failed to load host configs");
|
||
return false;
|
||
}
|
||
}
|
||
//TODO: flow in update fix later
|
||
/* Task.Run(() =>
|
||
{
|
||
GameSession.Context.Post(_ =>
|
||
{
|
||
if (m_pUIManager == null)
|
||
{
|
||
m_pUIManager = CECUIManager.Instance;
|
||
}
|
||
m_pUIManager.GetCDlgQuickBar().UpdateShortcuts();
|
||
}, null);
|
||
});*/
|
||
// TODO: Uncomment when UI manager is available
|
||
// Load UI configs / 加载UI配置
|
||
|
||
CECGameUIMan pGameUI = m_pUIManager.GetInGameUIMan();
|
||
if (pGameUI != null)
|
||
{
|
||
int iSize = dr.ReadInt();
|
||
byte[] uiConfigData = dr.ReadData(iSize);
|
||
/*if (!pGameUI.SetUserLayout(uiConfigData, iSize))
|
||
{
|
||
BMLogger.LogError("CECGameRun::LoadConfigsFromServer, Failed to set user layout");
|
||
return false;
|
||
}*/
|
||
}
|
||
|
||
// Load user settings / 加载用户设置
|
||
if (dwVer >= 2)
|
||
{
|
||
// TODO: Uncomment when game configs are available
|
||
int iSize = dr.ReadInt();
|
||
byte[] settingsData = dr.ReadData(iSize);
|
||
if (!EC_Game.GetConfigs().LoadUserConfigData(settingsData, iSize))
|
||
{
|
||
BMLogger.LogError("CECGameRun::LoadConfigsFromServer, Failed to load user config data");
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
catch (System.Exception e)
|
||
{
|
||
BMLogger.LogError($"CECGameRun::LoadConfigsFromServer, data read error: {e.Message}");
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
public int GetCurStageIndex()
|
||
{
|
||
// CECGameRun.unique_data* data = GetUniqueData(0);
|
||
// if (data)
|
||
// {
|
||
// if(data.type ==1)
|
||
// {
|
||
// return data.GetValueAsInt();
|
||
// }
|
||
// }
|
||
return -1;
|
||
}
|
||
// Create shortcuts
|
||
public bool CreateShortcuts()
|
||
{
|
||
// // Normal command shortcut set
|
||
m_pNormalSCS = new CECShortcutSet();
|
||
m_pNormalSCS.Init(8);
|
||
|
||
CECSCCommand pSC = new CECSCCommand((int)CECSCCommand.CommandID.CMD_SITDOWN);
|
||
m_pNormalSCS.SetShortcut(0, pSC);
|
||
pSC = new CECSCCommand((int)CECSCCommand.CommandID.CMD_WALKRUN);
|
||
m_pNormalSCS.SetShortcut(1, pSC);
|
||
pSC = new CECSCCommand((int)CECSCCommand.CommandID.CMD_NORMALATTACK);
|
||
m_pNormalSCS.SetShortcut(2, pSC);
|
||
pSC = new CECSCCommand((int)CECSCCommand.CommandID.CMD_FINDTARGET);
|
||
m_pNormalSCS.SetShortcut(3, pSC);
|
||
pSC = new CECSCCommand((int)CECSCCommand.CommandID.CMD_ASSISTATTACK);
|
||
m_pNormalSCS.SetShortcut(3, pSC);
|
||
pSC = new CECSCCommand((int)CECSCCommand.CommandID.CMD_FLY);
|
||
m_pNormalSCS.SetShortcut(4, pSC);
|
||
pSC = new CECSCCommand((int)CECSCCommand.CommandID.CMD_PICKUP);
|
||
m_pNormalSCS.SetShortcut(5, pSC);
|
||
pSC = new CECSCCommand((int)CECSCCommand.CommandID.CMD_GATHER);
|
||
m_pNormalSCS.SetShortcut(6, pSC);
|
||
pSC = new CECSCCommand((int)CECSCCommand.CommandID.CMD_RUSHFLY);
|
||
m_pNormalSCS.SetShortcut(6, pSC);
|
||
pSC = new CECSCCommand((int)CECSCCommand.CommandID.CMD_BINDBUDDY);
|
||
m_pNormalSCS.SetShortcut(7, pSC);
|
||
|
||
// Team command shortcut set
|
||
m_pTeamSCS = new CECShortcutSet();
|
||
m_pTeamSCS.Init(2);
|
||
|
||
pSC = new CECSCCommand((int)CECSCCommand.CommandID.CMD_INVITETOTEAM);
|
||
m_pTeamSCS.SetShortcut(0, pSC);
|
||
pSC = new CECSCCommand((int)CECSCCommand.CommandID.CMD_LEAVETEAM);
|
||
m_pTeamSCS.SetShortcut(1, pSC);
|
||
pSC = new CECSCCommand((int)CECSCCommand.CommandID.CMD_KICKTEAMMEM);
|
||
m_pTeamSCS.SetShortcut(2, pSC);
|
||
pSC = new CECSCCommand((int)CECSCCommand.CommandID.CMD_FINDTEAM);
|
||
m_pTeamSCS.SetShortcut(2, pSC);
|
||
|
||
// Trade command shortcut set
|
||
m_pTradeSCS = new CECShortcutSet();
|
||
m_pTradeSCS.Init(2);
|
||
|
||
pSC = new CECSCCommand((int)CECSCCommand.CommandID.CMD_STARTTRADE);
|
||
m_pTradeSCS.SetShortcut(0, pSC);
|
||
pSC = new CECSCCommand((int)CECSCCommand.CommandID.CMD_SELLBOOTH);
|
||
m_pTradeSCS.SetShortcut(1, pSC);
|
||
|
||
// Pose command shortcut set
|
||
m_pPoseSCS = new CECShortcutSet();
|
||
m_pPoseSCS.Init((int)RoleExpression.NUM_ROLEEXP);
|
||
|
||
for (int i = 0; i < (int)RoleExpression.NUM_ROLEEXP; i++)
|
||
{
|
||
pSC = new CECSCCommand((int)CECSCCommand.CommandID.CMD_PLAYPOSE);
|
||
pSC.SetParam((uint)i);
|
||
m_pPoseSCS.SetShortcut(i, pSC);
|
||
}
|
||
|
||
// Faction command shortcut set
|
||
m_pFactionSCS = new CECShortcutSet();
|
||
m_pFactionSCS.Init(1);
|
||
|
||
pSC = new CECSCCommand((int)CECSCCommand.CommandID.CMD_INVITETOFACTION);
|
||
m_pFactionSCS.SetShortcut(0, pSC);
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
// Get UI manager
|
||
public CECUIManager GetUIManager()
|
||
{
|
||
if (m_pUIManager == null)
|
||
{
|
||
m_pUIManager = CECUIManager.Instance;
|
||
}
|
||
return m_pUIManager;
|
||
}
|
||
|
||
|
||
// Get instance by ID
|
||
public CECInstance GetInstance(int id)
|
||
{
|
||
if (m_InstTab.TryGetValue(id, out CECInstance value))
|
||
{
|
||
return value;
|
||
}
|
||
return null;
|
||
}
|
||
public string GetProfName(int i)
|
||
{
|
||
string szRet = null;
|
||
if (i >= 0 && i < (int)Profession.NUM_PROFESSION)
|
||
{
|
||
int[] s_ProfDesc = {
|
||
(int)FixedMsg.FIXMSG_PROF_WARRIOR,
|
||
(int)FixedMsg.FIXMSG_PROF_MAGE,
|
||
(int)FixedMsg.FIXMSG_PROF_MONK,
|
||
(int)FixedMsg.FIXMSG_PROF_HAG,
|
||
(int)FixedMsg.FIXMSG_PROF_ORC,
|
||
(int)FixedMsg.FIXMSG_PROF_GHOST,
|
||
(int)FixedMsg.FIXMSG_PROF_ARCHOR,
|
||
(int)FixedMsg.FIXMSG_PROF_ANGEL,
|
||
(int)FixedMsg.FIXMSG_PROF_JIANLING,
|
||
(int)FixedMsg.FIXMSG_PROF_MEILING,
|
||
(int)FixedMsg.FIXMSG_PROF_YEYING,
|
||
(int)FixedMsg.FIXMSG_PROF_YUEXIAN,
|
||
};
|
||
CECStringTab pStrTab = EC_Game.GetFixedMsgs();
|
||
szRet = pStrTab.GetWideString(s_ProfDesc[i]);
|
||
}
|
||
else
|
||
{
|
||
//BMLogger.LogError("CECGameRun::GetProfName, i: {0} is not exist", i);
|
||
return null;
|
||
}
|
||
return szRet;
|
||
}
|
||
|
||
public CECPet GetPet()
|
||
{
|
||
//return ObjectSpawner.Instance.InstantiateObject(_petServerPrefab, setThisAsParent: true)
|
||
// .GetComponent<CECPet>();
|
||
return PrefabPoolManager.Instance.Spawn(_petServerPrefab, Vector3.zero, Quaternion.identity, ObjectSpawner.Instance.transform)
|
||
.GetComponent<CECPet>();
|
||
}
|
||
|
||
public GameObject GetPetMount()
|
||
{
|
||
//return ObjectSpawner.Instance.InstantiateObject(_petMountServerPrefab, setThisAsParent: true);
|
||
return PrefabPoolManager.Instance.Spawn(_petMountServerPrefab, Vector3.zero, Quaternion.identity, ObjectSpawner.Instance.transform);
|
||
}
|
||
|
||
/// <summary>
|
||
/// Add a fixed message to chat system with optional formatting parameters
|
||
/// 添加固定消息到聊天系统,支持可选的格式化参数
|
||
/// </summary>
|
||
/// <param name="iMsg">Fixed message ID / 固定消息ID</param>
|
||
/// <param name="args">Optional formatting arguments / 可选的格式化参数</param>
|
||
public void AddFixedMessage(int iMsg, params object[] args)
|
||
{
|
||
CECStringTab pStrTab = EC_Game.GetFixedMsgs();
|
||
if (pStrTab == null)
|
||
{
|
||
Debug.LogWarning("[AddFixedMessage] Failed to get fixed message table");
|
||
return;
|
||
}
|
||
|
||
string szFixMsg = pStrTab.GetWideString(iMsg);
|
||
if (string.IsNullOrEmpty(szFixMsg))
|
||
{
|
||
Debug.LogWarning($"[AddFixedMessage] Fixed message {iMsg} not found");
|
||
return;
|
||
}
|
||
|
||
// fixed_msg.txt uses printf-style (%d, %s); not C# {0} placeholders
|
||
string szFormattedMsg;
|
||
try
|
||
{
|
||
if (args != null && args.Length > 0)
|
||
szFormattedMsg = AUIDialog.FormatPrintf(szFixMsg, args);
|
||
else
|
||
szFormattedMsg = szFixMsg;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Debug.LogError($"[AddFixedMessage] Format error for message {iMsg}: {ex.Message}");
|
||
szFormattedMsg = szFixMsg;
|
||
}
|
||
|
||
// Try to add to in-game UI chat
|
||
CECGameUIMan pGameUI = m_pUIManager?.GetInGameUIMan();
|
||
if (pGameUI != null)
|
||
{
|
||
pGameUI.AddChatMessage(szFormattedMsg, ChatChannel.GP_CHAT_SYSTEM);
|
||
}
|
||
else
|
||
{
|
||
// Fallback to debug output if UI is not available
|
||
Debug.Log($"[System] {szFormattedMsg}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Add a fixed message to specific chat channel with optional formatting
|
||
/// 添加固定消息到指定聊天频道,支持可选的格式化
|
||
/// </summary>
|
||
/// <param name="iMsg">Fixed message ID / 固定消息ID</param>
|
||
/// <param name="cChannel">Chat channel ID / 聊天频道ID</param>
|
||
/// <param name="args">Optional formatting arguments / 可选的格式化参数</param>
|
||
public void AddFixedChannelMsg(int iMsg, int cChannel, params object[] args)
|
||
{
|
||
CECStringTab pStrTab = EC_Game.GetFixedMsgs();
|
||
if (pStrTab == null)
|
||
{
|
||
Debug.LogWarning("[AddFixedChannelMsg] Failed to get fixed message table");
|
||
return;
|
||
}
|
||
|
||
string szFixMsg = pStrTab.GetWideString(iMsg);
|
||
if (string.IsNullOrEmpty(szFixMsg))
|
||
{
|
||
Debug.LogWarning($"[AddFixedChannelMsg] Fixed message {iMsg} not found");
|
||
return;
|
||
}
|
||
|
||
// fixed_msg.txt uses printf-style (%d, %s); not C# {0} placeholders
|
||
string szFormattedMsg;
|
||
try
|
||
{
|
||
if (args != null && args.Length > 0)
|
||
szFormattedMsg = AUIDialog.FormatPrintf(szFixMsg, args);
|
||
else
|
||
szFormattedMsg = szFixMsg;
|
||
}
|
||
catch (Exception ex)
|
||
{
|
||
Debug.LogError($"[AddFixedChannelMsg] Format error for message {iMsg}: {ex.Message}");
|
||
szFormattedMsg = szFixMsg;
|
||
}
|
||
|
||
// Try to add to in-game UI chat with specific channel
|
||
CECGameUIMan pGameUI = m_pUIManager?.GetInGameUIMan();
|
||
if (pGameUI != null)
|
||
{
|
||
//pGameUI.AddChatMessage(szFormattedMsg, cChannel);
|
||
}
|
||
else
|
||
{
|
||
// Fallback to debug output if UI is not available
|
||
Debug.Log($"[Channel {cChannel}] {szFormattedMsg}");
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Add a chat message with full parameters (matching C++ signature)
|
||
/// 添加聊天消息(完整参数版本,匹配C++签名)
|
||
/// </summary>
|
||
/// <param name="pszMsg">Message text / 消息文本</param>
|
||
/// <param name="cChannel">Chat channel / 聊天频道</param>
|
||
/// <param name="idPlayer">Player ID (default -1) / 玩家ID</param>
|
||
/// <param name="szName">Player name (optional) / 玩家名称</param>
|
||
/// <param name="byFlag">Message flag (default 0) / 消息标志</param>
|
||
/// <param name="cEmotion">Emotion ID (default 0) / 表情ID</param>
|
||
/// <param name="pItem">Related item (optional) / 相关物品</param>
|
||
/// <param name="pszMsgOrigion">Original message (optional) / 原始消息</param>
|
||
public void AddChatMessage(string pszMsg, int cChannel, int idPlayer = -1,
|
||
string szName = null, byte byFlag = 0, int cEmotion = 0,
|
||
EC_IvtrItem pItem = null, string pszMsgOrigion = null)
|
||
{
|
||
if (string.IsNullOrEmpty(pszMsg))
|
||
return;
|
||
|
||
CECGameUIMan pGameUI = m_pUIManager?.GetInGameUIMan();
|
||
if (pGameUI != null)
|
||
{
|
||
// Call UI manager's AddChatMessage with full parameters
|
||
pGameUI.AddChatMessage(pszMsg, (ChatChannel)cChannel, idPlayer, szName, byFlag, cEmotion, pItem, pszMsgOrigion);
|
||
}
|
||
else
|
||
{
|
||
// Fallback to debug output if UI is not available
|
||
BMLogger.LogError($"[Cuong] [Error] pGameUI == null");
|
||
|
||
// Note: In C++ original, pItem is deleted here if UI is not available
|
||
// In C#, we don't need explicit deletion due to garbage collection
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// Get remaining double experience time in seconds
|
||
/// 获取剩余双倍经验时间(秒)
|
||
/// </summary>
|
||
public int GetRemainDblExpTime()
|
||
{
|
||
int iRemainTime = m_iDExpEndTime - GetServerAbsTime();
|
||
if (iRemainTime < 0) iRemainTime = 0;
|
||
return iRemainTime;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Get server absolute time
|
||
/// 获取服务器绝对时间
|
||
/// </summary>
|
||
public int GetServerAbsTime()
|
||
{
|
||
// TODO: Implement server time synchronization
|
||
// This should return the synchronized server timestamp
|
||
return (int)(System.DateTime.UtcNow.Subtract(new System.DateTime(1970, 1, 1))).TotalSeconds;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Set double experience end time
|
||
/// 设置双倍经验结束时间
|
||
/// </summary>
|
||
public void SetDExpEndTime(int endTime)
|
||
{
|
||
m_iDExpEndTime = endTime;
|
||
}
|
||
public int GetGameState() { return m_iGameState; }
|
||
|
||
// Logout flag: -1 none, 0 exit app, 1 re-select role, 2 goto login (C++: SetLogoutFlag/GetLogoutFlag)
|
||
public void SetLogoutFlag(int iFlag) { m_iLogoutFlag = iFlag; }
|
||
public int GetLogoutFlag() { return m_iLogoutFlag; }
|
||
|
||
// Selling role ID for role trade (C++: SetSellingRoleID)
|
||
public void SetSellingRoleID(int roleid) { m_iSellingRoleID = roleid; }
|
||
public int GetSellingRoleID() { return m_iSellingRoleID; }
|
||
|
||
// Save necessary user configs (UI, shortcut, accelerate keys, etc.) to server
|
||
// ����ֵ: 0(����ʧ��), 1(���������ظ�����), 2(�������������Э��)
|
||
public uint SaveConfigsToServer()
|
||
{
|
||
|
||
// if (!m_pWorld || !m_pWorld.GetHostPlayer() || !m_pWorld.GetHostPlayer().HostIsReady() || !m_pUIManager.GetInGameUIMan())
|
||
// return 0;
|
||
CECHostPlayer pHost = GetHostPlayer();
|
||
CECGameUIMan pGameUI = m_pUIManager?.GetInGameUIMan() as CECGameUIMan;
|
||
if (m_pWorld == null || pHost == null || !pHost.HostIsReady() || pGameUI == null)
|
||
return 0;
|
||
|
||
// g_pGame.GetConfigs().SaveBlockedID();
|
||
EC_Game.GetConfigs().SaveBlockedID(); // TODO: Check if this is needed here
|
||
|
||
// int iTotalSize = 0;
|
||
// iTotalSize += sizeof (DWORD);
|
||
// iTotalSize += sizeof (int);
|
||
// int iHostSize = 0;
|
||
// CECHostPlayer* pHost = m_pWorld.GetHostPlayer();
|
||
// pHost.SaveConfigData(NULL, &iHostSize);
|
||
// iTotalSize += iHostSize;
|
||
// iTotalSize += sizeof (int);
|
||
int iTotalSize = sizeof(uint);
|
||
iTotalSize += sizeof(int);
|
||
int iHostSize = 0;
|
||
pHost.SaveConfigData(null, ref iHostSize);
|
||
iTotalSize += sizeof(int) + iHostSize;
|
||
|
||
// DWORD dwUISize = 0;
|
||
// CECGameUIMan* pGameUI = (CECGameUIMan*)m_pUIManager.GetInGameUIMan();
|
||
// pGameUI.GetUserLayout(NULL, dwUISize);
|
||
// iTotalSize += (int)dwUISize;
|
||
// iTotalSize += sizeof (int);
|
||
uint dwUISize = 0;
|
||
pGameUI.GetUserLayout(null,0, ref dwUISize); // TODO: Check if this is needed here
|
||
iTotalSize += sizeof(int) + (int)dwUISize;
|
||
|
||
// int iSettingSize = 0;
|
||
// g_pGame.GetConfigs().SaveUserConfigData(NULL, &iSettingSize);
|
||
// iTotalSize += iSettingSize;
|
||
int iSettingSize = 0;
|
||
EC_Game.GetConfigs().SaveUserConfigData(null, 0, out iSettingSize);
|
||
// iTotalSize += sizeof(int) + iSettingSize;
|
||
iTotalSize += iSettingSize;
|
||
|
||
// void* pDataBuf = a_malloctemp(iTotalSize);
|
||
// if (!pDataBuf) { glb_ErrorOutput(ECERR_NOTENOUGHMEMORY, "CECGameRun::SaveConfigsToServer", __LINE__); return 0; }
|
||
// BYTE* pData = (BYTE*)pDataBuf;
|
||
byte[] pDataBuf = new byte[iTotalSize];
|
||
int offset = 0;
|
||
|
||
// *((DWORD*)pData) = USERCFG_VERSION;
|
||
// pData += sizeof (DWORD);
|
||
Buffer.BlockCopy(BitConverter.GetBytes(USERCFG_VERSION), 0, pDataBuf, offset, sizeof(uint));
|
||
offset += sizeof(uint);
|
||
BMLogger.Log($"[SaveConfigsToServer] offset={offset} (after version)");
|
||
|
||
// *((int*)pData) = iHostSize;
|
||
// pData += sizeof (int);
|
||
// pHost.SaveConfigData(pData, &iHostSize);
|
||
// pData += iHostSize;
|
||
Buffer.BlockCopy(BitConverter.GetBytes(iHostSize), 0, pDataBuf, offset, sizeof(int));
|
||
offset += sizeof(int);
|
||
pHost.SaveConfigData(pDataBuf, ref iHostSize, offset); // TODO: converted but need to check
|
||
offset += iHostSize;
|
||
BMLogger.Log($"[SaveConfigsToServer] offset={offset} (after host config, iHostSize={iHostSize})");
|
||
|
||
// *((int*)pData) = (int)dwUISize;
|
||
// pData += sizeof (int);
|
||
// pGameUI.GetUserLayout(pData, dwUISize);
|
||
// pData += dwUISize;
|
||
Buffer.BlockCopy(BitConverter.GetBytes((int)dwUISize), 0, pDataBuf, offset, sizeof(int));
|
||
offset += sizeof(int);
|
||
pGameUI.GetUserLayout(pDataBuf, offset, ref dwUISize); // TODO: Check if this is needed here
|
||
offset += (int)dwUISize;
|
||
BMLogger.Log($"[SaveConfigsToServer] offset={offset} (after UI layout, dwUISize={dwUISize})");
|
||
|
||
// *((int*)pData) = iSettingSize;
|
||
// pData += sizeof (int);
|
||
// g_pGame.GetConfigs().SaveUserConfigData(pData, &iSettingSize);
|
||
// pData += iSettingSize;
|
||
Buffer.BlockCopy(BitConverter.GetBytes(iSettingSize), 0, pDataBuf, offset, sizeof(int));
|
||
offset += sizeof(int);
|
||
EC_Game.GetConfigs().SaveUserConfigData(pDataBuf, offset, out iSettingSize);
|
||
offset += iSettingSize;
|
||
BMLogger.Log($"[SaveConfigsToServer] offset={offset} (after user config, iSettingSize={iSettingSize}), iTotalSize={iTotalSize}");
|
||
|
||
// if (m_pCfgDataBuf) {
|
||
// if (m_iCfgDataSize == iTotalSize && !memcmp(m_pCfgDataBuf, pDataBuf, iTotalSize)) { a_freetemp(pDataBuf); return 1; }
|
||
// a_free(m_pCfgDataBuf); m_pCfgDataBuf = NULL; m_iCfgDataSize = 0;
|
||
// }
|
||
if (m_pCfgDataBuf != null && m_iCfgDataSize == iTotalSize)
|
||
{
|
||
bool same = true;
|
||
for (int i = 0; i < iTotalSize && same; i++)
|
||
same = (m_pCfgDataBuf[i] == pDataBuf[i]);
|
||
if (same)
|
||
return 1;
|
||
}
|
||
m_pCfgDataBuf = null;
|
||
m_iCfgDataSize = 0;
|
||
|
||
// if ((m_pCfgDataBuf = (BYTE*)a_malloc(iTotalSize))) { memcpy(m_pCfgDataBuf, pDataBuf, iTotalSize); m_iCfgDataSize = iTotalSize; }
|
||
m_pCfgDataBuf = new byte[iTotalSize];
|
||
Buffer.BlockCopy(pDataBuf, 0, m_pCfgDataBuf, 0, iTotalSize);
|
||
m_iCfgDataSize = iTotalSize;
|
||
|
||
// DWORD dwCompLen = iTotalSize * 2;
|
||
// void* pCompBuf = a_malloctemp(dwCompLen);
|
||
// if (!pCompBuf) { a_freetemp(pDataBuf); glb_ErrorOutput(ECERR_NOTENOUGHMEMORY, "CECGameRun::SaveConfigsToServer", __LINE__); return 0; }
|
||
// int iVerLen = sizeof (DWORD);
|
||
// memcpy(pCompBuf, pDataBuf, iVerLen);
|
||
// BYTE* pSrc = (BYTE*)pDataBuf + iVerLen;
|
||
// BYTE* pDst = (BYTE*)pCompBuf + iVerLen;
|
||
// dwCompLen -= iVerLen;
|
||
// int iRes = AFilePackage::Compress(pSrc, iTotalSize - iVerLen, pDst, &dwCompLen);
|
||
int iVerLen = sizeof(uint);
|
||
// int compLen = (iTotalSize - iVerLen) * 2;
|
||
int compLen = iTotalSize * 2;
|
||
byte[] pCompBuf = new byte[iVerLen + compLen];
|
||
compLen -= iVerLen;
|
||
Buffer.BlockCopy(pDataBuf, 0, pCompBuf, 0, iVerLen);
|
||
int iRes = AFilePackage.Compress(pDataBuf, iVerLen,iTotalSize - iVerLen, pCompBuf, iVerLen, ref compLen);
|
||
|
||
// if (0 == iRes) { g_pGame->GetGameSession()->SaveConfigData(pCompBuf, dwCompLen+iVerLen); iRes = 2; }
|
||
// else { a_LogOutput(1, "CECGameRun::SaveConfigsToServer, Failed to compress config data (%d:%d)", iRes, iTotalSize); iRes = 0; }
|
||
// a_freetemp(pDataBuf);
|
||
// a_freetemp(pCompBuf);
|
||
// return iRes;
|
||
if (iRes == 0)
|
||
{
|
||
var session = UnityGameSession.Instance?.GameSession;
|
||
if (session != null)
|
||
{
|
||
session.SaveConfigData(pCompBuf, iVerLen + compLen);
|
||
return 2;
|
||
}
|
||
}
|
||
else
|
||
BMLogger.LogWarning($"CECGameRun::SaveConfigsToServer, Failed to compress config data ({iRes}:{iTotalSize})");
|
||
return 0;
|
||
}
|
||
|
||
public void ReleasePendingActions()
|
||
{
|
||
m_pendingLogout.Clear();
|
||
}
|
||
|
||
public CECPendingActionArray GetPendingLogOut(){ return m_pendingLogout; }
|
||
|
||
// Game tick routine
|
||
public bool Tick(uint dwDeltaTime)
|
||
{
|
||
// if (GetWallowInfo().anti_wallow_active &&
|
||
// g_pGame.GetGameSession().IsConnected() &&
|
||
// GetGameState() == GS_GAME)
|
||
// {
|
||
// if (CECUIConfig::Instance().GetGameUI().nWallowHintType != CECUIConfig::GameUI::WHT_KOREA)
|
||
// {
|
||
// // ·À³ÁÃÔµ½3Сʱ£¬ÈôAU²»ÌßÈË£¨ÏûÏ¢¶ªÊ§£©£¬Ôò×Ô¶¯ÏÂÏß
|
||
// int stime = g_pGame.GetServerGMTTime();
|
||
// int nTime = stime - GetWallowInfo().play_time;
|
||
// if (nTime >= 3 * 3600)
|
||
// {
|
||
// // ÒѾ³¬¹ý3Сʱ
|
||
// g_pGame.GetGameSession().SetBreakLinkFlag(CECGameSession::LBR_ANTI_WALLOW);
|
||
// }
|
||
// }
|
||
// }
|
||
//
|
||
// DWORD dwTickTime = a_GetTime();
|
||
//
|
||
// CECGameSession* pSession = g_pGame.GetGameSession();
|
||
// pSession.ProcessNewProtocols();
|
||
// DWORD dwRealTime = g_pGame.GetRealTickTime();
|
||
|
||
if (m_iLogoutFlag >= 0)
|
||
{
|
||
Logout();
|
||
m_iLogoutFlag = -1;
|
||
}
|
||
|
||
// CECReconnect::Instance().Tick();
|
||
//
|
||
// if (m_pUIManager)
|
||
// m_bUIHasCursor = m_pUIManager.UIControlCursor();
|
||
// else
|
||
// m_bUIHasCursor = false;
|
||
//
|
||
// // Deal input first
|
||
// if (m_pInputCtrl)
|
||
// m_pInputCtrl.Tick();
|
||
//
|
||
// // Tick world
|
||
// if (!TickGameWorld(dwDeltaTime, g_pGame.GetViewport()))
|
||
// return false;
|
||
|
||
// Tick UI
|
||
// if (m_pUIManager)
|
||
// m_pUIManager.Tick();
|
||
|
||
// // Tick GFX caster
|
||
// g_pGame.GetGFXCaster().Tick(dwDeltaTime);
|
||
//
|
||
// // Tick GFX Manager
|
||
// g_pGame.GetA3DGFXExMan().Tick(dwDeltaTime);
|
||
//
|
||
// // A3DEngine::TickAnimation trigger animation of many objects.
|
||
// // For example: A3DSky objects, GFX objects etc.
|
||
// static DWORD dwAnimTime = 0;
|
||
// dwAnimTime += dwDeltaTime;
|
||
// while (dwAnimTime >= TIME_TICKANIMATION)
|
||
// {
|
||
// dwAnimTime -= TIME_TICKANIMATION;
|
||
// g_pGame.GetA3DEngine().TickAnimation();
|
||
// }
|
||
//
|
||
// // Update ear position so that all 3D sounds' positions are correct
|
||
// static DWORD dwEarTime = 0;
|
||
// if ((dwEarTime += dwDeltaTime) >= TIME_UPDATEEAR)
|
||
// {
|
||
// dwEarTime -= TIME_UPDATEEAR;
|
||
//
|
||
// CECHostPlayer* pHostPlayer = NULL;
|
||
// if (m_pWorld)
|
||
// pHostPlayer = m_pWorld.GetHostPlayer();
|
||
//
|
||
// A3DCamera * pCamera = g_pGame.GetViewport().GetA3DCamera();
|
||
//
|
||
// if (GetGameState() == CECGameRun::GS_GAME && pHostPlayer && pHostPlayer.HostIsReady())
|
||
// {
|
||
// AM3DSoundDevice * pAM3DSoundDevice = g_pGame.GetA3DEngine().GetAMSoundEngine().GetAM3DSoundDevice();
|
||
// A3DVECTOR3 vecDir = pCamera.GetDirH();
|
||
// A3DVECTOR3 vecUp = A3DVECTOR3(0.0f, 1.0f, 0.0f);
|
||
//
|
||
// // Now we should adjust the 3d sound device's pos and orientation;
|
||
// if (pAM3DSoundDevice)
|
||
// {
|
||
// pAM3DSoundDevice.SetPosition(pHostPlayer.GetPos() + A3DVECTOR3(0.0f, 0.8f, 0.0f));
|
||
// pAM3DSoundDevice.SetOrientation(vecDir, vecUp);
|
||
// pAM3DSoundDevice.UpdateChanges();
|
||
// }
|
||
// }
|
||
// else
|
||
// g_pGame.GetViewport().GetA3DCamera().UpdateEar();
|
||
// }
|
||
//
|
||
// // Tick Run-Time debug information
|
||
// g_pGame.GetRTDebug().Tick(dwDeltaTime);
|
||
//
|
||
// // Save UI configs when time reached
|
||
// if (m_iGameState == GS_GAME && l_SaveCfgCnt.IncCounter(dwRealTime))
|
||
// {
|
||
// l_SaveCfgCnt.Reset();
|
||
// SaveConfigsToServer();
|
||
// }
|
||
//
|
||
// l_StatCnt.IncCounter(dwDeltaTime);
|
||
//
|
||
// pSession.ClearOldProtocols();
|
||
//
|
||
// DWORD dwCurrentTick = a_GetTime();
|
||
// dwTickTime = (dwCurrentTick > dwTickTime) ? (dwCurrentTick - dwTickTime) : 0;
|
||
// l_Statistic.iTickTime = (int)dwTickTime;
|
||
//
|
||
// if (GetGameState() == CECGameRun::GS_GAME && l_fc.iAvgRdTime)
|
||
// {
|
||
// // Accumulate tick time
|
||
// l_fc.iTickCnt++;
|
||
// l_fc.iTickTime += (int)dwTickTime;
|
||
// }
|
||
//
|
||
// if (GetGameState() == GS_GAME && GetHostPlayer() && GetHostPlayer().HostIsReady())
|
||
// {
|
||
// if (l_bFirstQuery || l_DelayQueryCounter.IncCounter(dwDeltaTime))
|
||
// {
|
||
// // µÚÒ»´Î²éѯ£¬»òÕß²éѯ¼ÆÊýÆ÷µ½µã
|
||
//
|
||
// // ·¢ËÍÍøÂçÓµ¼·²éѯÐÒé
|
||
// l_iDelayTimeStamp = timeGetTime();
|
||
// g_pGame.GetGameSession().c2s_CmdQueryNetworkDelay(l_iDelayTimeStamp);
|
||
// l_DelayQueryCounter.Reset();
|
||
// l_bFirstQuery = false;
|
||
// }
|
||
//
|
||
// if (l_QueryServerTime.IncCounter(dwDeltaTime))
|
||
// {
|
||
// g_pGame.GetGameSession().c2s_CmdSendGetServerTime();
|
||
// l_QueryServerTime.Reset();
|
||
// }
|
||
// }
|
||
//
|
||
// m_pendingLogout.Update(dwDeltaTime);
|
||
//
|
||
// // ÓÅ»¯ÄÚ´æµÄÕ¼ÓÃ
|
||
// m_pMemSimplify.Tick(dwDeltaTime);
|
||
//
|
||
// // ¸üÐÂÏÂÔØ×´Ì¬
|
||
// CECMCDownload::GetInstance().Tick(dwDeltaTime);
|
||
//
|
||
// // ¸üÐÂ×Ô¶¯²ßÂÔ
|
||
// CECAutoPolicy::GetInstance().Tick(dwDeltaTime);
|
||
//
|
||
// if(m_pRandomMapProc)
|
||
// m_pRandomMapProc.Tick(dwDeltaTime);
|
||
//
|
||
// #ifdef _PROFILE_MEMORY
|
||
// g_TickMemoryHistory();
|
||
// #endif
|
||
|
||
TickHealthPlaytimeChatReminder(dwDeltaTime);
|
||
|
||
return true;
|
||
}
|
||
|
||
// Load instance information from file
|
||
bool LoadInstanceInfo(string szFile)
|
||
{
|
||
// AWScriptFile sf = new AWScriptFile();
|
||
//if (!sf.Open(szFile))
|
||
//{
|
||
// //a_LogOutput(1, "CECGameRun::LoadInstanceInfo, Failed to load %s", szFile);
|
||
// return false;
|
||
//}
|
||
// CECInstance pInst;
|
||
// while (sf.PeekNextToken(true))
|
||
// {
|
||
// pInst = new CECInstance();
|
||
// if (pInst == null || !pInst.Load(sf))
|
||
// {
|
||
// //a_LogOutput(1, "CECGameRun::LoadInstanceInfo, Failed to read %s near line:%d", szFile, sf.GetCurLine());
|
||
// return false;
|
||
// }
|
||
|
||
// if (!m_InstTab.ContainsKey(pInst.GetID()))
|
||
// {
|
||
// // ID collsion ?
|
||
// m_InstTab.Add(pInst.GetID(), pInst);
|
||
// }
|
||
// }
|
||
|
||
// sf.Close();
|
||
|
||
return true;
|
||
}
|
||
|
||
|
||
private Dictionary<string, int> m_Name2IDTab = new Dictionary<string, int>();
|
||
private Dictionary<int, string> m_ID2NameTab = new Dictionary<int, string>();
|
||
|
||
// Get player name
|
||
public string GetPlayerName(int cid, bool autoGen)
|
||
{
|
||
if (m_ID2NameTab.TryGetValue(cid, out var name))
|
||
return name;
|
||
|
||
if (autoGen)
|
||
return $"P-{cid}";
|
||
|
||
return null;
|
||
}
|
||
|
||
// Add player name to table
|
||
public void AddPlayerName(int cid, string szName, bool bOverwrite = false)
|
||
{
|
||
if (cid == 0)
|
||
{
|
||
Debug.LogError("CECGameRun::AddPlayerName, Invalid cid(=0)!");
|
||
return;
|
||
}
|
||
|
||
string strName = szName;
|
||
|
||
if (string.IsNullOrEmpty(strName))
|
||
{
|
||
Debug.LogError($"CECGameRun::AddPlayerName, Invalid name for cid={cid}!");
|
||
return;
|
||
}
|
||
|
||
// Name -> ID
|
||
var Pair2 = m_Name2IDTab.TryGetValue(strName, out var value2);
|
||
|
||
if (!Pair2)
|
||
m_Name2IDTab[strName] = cid;
|
||
else
|
||
m_Name2IDTab[strName] = cid;
|
||
|
||
// ID -> Name
|
||
var Pair = m_ID2NameTab.TryGetValue(cid, out var value);
|
||
|
||
if (Pair)
|
||
{
|
||
if (bOverwrite)
|
||
{
|
||
m_ID2NameTab[cid] = strName;
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
m_ID2NameTab[cid] = strName;
|
||
}
|
||
}
|
||
public enum GameState
|
||
|
||
{
|
||
GS_NONE = 0, // None
|
||
GS_LOGIN, // Login in state
|
||
GS_GAME, // In game
|
||
};
|