using System; using System.Collections.Generic; using System.Runtime.InteropServices; using BrewMonster.Scripts; using CSNetwork.GPDataType; using UnityEngine; using CombinedActMap = System.Collections.Generic.Dictionary; using CoGfxMap = System.Collections.Generic.Dictionary; using ConvexHullDataArray = System.Collections.Generic.List; using ECModelHookMap = System.Collections.Generic.Dictionary; using BrewMonster; public enum ECMScript { enumECMScriptStartAction = 0, enumECMScriptEndActioin, enumECMScriptInit, enumECMScriptRelease, enumECMScriptModelLoaded, enumECMScriptChangeEquip, enumECMScriptChangeEquipTableInit, enumECMScriptPhysBreak, enumECMScriptCount } public enum ECMScriptVar { enumECMVarModel = 0, enumECMVarActName, enumECMVarActChannel, enumECMVarEquipId, enumECMVarEquipFlag, enumECMVarFashionMode, enumECMVarPathId, enumECMVarId, enumECMVarEquipIndex, enumECMVarBreakOffsetX, enumECMVarBreakOffsetY, enumECMVarBreakOffsetZ, enumECMVarCasterId, enumECMVarCastTargetId, enumECMVarSelf, enumECMVarCount } public static class CECModelConstants { public const int ECM_SCRIPT_MAX_VAR_COUNT = 8; public const int OUTER_DATA_COUNT = 8; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct ECM_SCRIPT_VAR { [MarshalAs(UnmanagedType.I4)] public int var_count; [MarshalAs(UnmanagedType.ByValArray, SizeConst = CECModelConstants.ECM_SCRIPT_MAX_VAR_COUNT)] public int[] var_index; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct BoneScale { public int m_nIndex; public int m_nType; public A3DVECTOR3 m_vScale; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct BoneScaleEx { public int m_nIndex; public float m_fLenFactor; public float m_fThickFactor; public float m_fWholeFactor; } public class ActChannelInfo { public List bone_names = new List(); public List joint_indices = new List(); public ActChannelInfo Clone() { return new ActChannelInfo { bone_names = new List(bone_names), joint_indices = new List(joint_indices) }; } } public enum A3DBLEND { A3DBLEND_SRCALPHA, A3DBLEND_INVSRCALPHA } public struct A3DSHADER { public A3DBLEND SrcBlend; public A3DBLEND DestBlend; } public class CECModelStaticData { private string m_strFilePath = string.Empty; private string m_strSkinModelPath = string.Empty; private bool m_bAutoUpdate = true; private bool m_bActMapped; private readonly CombinedActMap m_ActionMap = new CombinedActMap(); private uint m_dwVersion; private string m_strHook = string.Empty; private string m_strCCName = string.Empty; private readonly List m_BoneScales = new List(); private readonly List m_BoneScaleExArr = new List(); private string m_strScaleBaseBone = string.Empty; private uint m_OrgColor = 0xFFFFFFFF; private uint m_EmissiveColor = 0; private float m_fDefPlaySpeed = 1.0f; private A3DSHADER m_BlendMode = new A3DSHADER { SrcBlend = A3DBLEND.A3DBLEND_SRCALPHA, DestBlend = A3DBLEND.A3DBLEND_INVSRCALPHA }; private readonly float[] m_OuterData = new float[CECModelConstants.OUTER_DATA_COUNT]; private bool m_bCanCastShadow = true; private bool m_bRenderSkinModel = true; private bool m_bRenderEdge = true; private readonly CoGfxMap m_CoGfxMap = new CoGfxMap(); private readonly ConvexHullDataArray m_ConvexHullDataArr = new ConvexHullDataArray(); private readonly A3DAABB m_CHAABB = new A3DAABB(); private readonly Dictionary m_ChannelInfoDict = new Dictionary(); private readonly Dictionary m_EventMasks = new Dictionary(); private readonly string[] m_Scripts = new string[(int)ECMScript.enumECMScriptCount]; private readonly bool[] m_ScriptEnable = new bool[(int)ECMScript.enumECMScriptCount]; private readonly CLuaMemTbl m_ScriptMemTbl = new CLuaMemTbl(); private bool m_bInitGlobalScript; private string m_strGlobalScriptName = string.Empty; public class ChildInfo { public string m_strName = string.Empty; public string m_strPath = string.Empty; public string m_strHHName = string.Empty; public string m_strCCName = string.Empty; } private readonly List m_ChildInfoArray = new List(); private readonly List m_AdditionalSkinLst = new List(); private string m_strPhysFileName = string.Empty; private object m_pPhysSyncData; private readonly ECModelHookMap m_ECModelHookMap = new ECModelHookMap(); private string m_strPixelShader = string.Empty; private string m_strShaderTex = string.Empty; private readonly List m_vecPSConsts = new List(); public CECModelStaticData() { ResetOuterData(); m_CHAABB.Clear(); } public bool LoadData(string szModelFile, bool bLoadAdditionalSkin) { throw new NotImplementedException("CECModelStaticData.LoadData requires the legacy AFile system to be ported."); } public bool Save(string szFile, CECModel pModel) { throw new NotImplementedException("CECModelStaticData.Save requires the legacy serialization pipeline to be ported."); } public bool SaveBoneScaleInfo(string szFile) { throw new NotImplementedException("CECModelStaticData.SaveBoneScaleInfo is not yet implemented."); } public void Release() { m_BoneScales.Clear(); m_BoneScaleExArr.Clear(); m_CoGfxMap.Clear(); m_ActionMap.Clear(); m_AdditionalSkinLst.Clear(); m_ChildInfoArray.Clear(); m_ConvexHullDataArr.Clear(); m_ChannelInfoDict.Clear(); m_EventMasks.Clear(); Array.Clear(m_Scripts, 0, m_Scripts.Length); Array.Clear(m_ScriptEnable, 0, m_ScriptEnable.Length); m_ECModelHookMap.Clear(); m_vecPSConsts.Clear(); m_bInitGlobalScript = false; m_strGlobalScriptName = string.Empty; m_pPhysSyncData = null; m_CHAABB.Clear(); ResetOuterData(); } public ConvexHullDataArray GetConvexHullData() => m_ConvexHullDataArr; public bool HasCHAABB() => m_ConvexHullDataArr.Count != 0; public A3DAABB GetCHAABB() => m_CHAABB; public bool UpdateScript(int index, string strScript, bool bCompileOnly) { if (index < 0 || index >= (int)ECMScript.enumECMScriptCount) return false; if (!bCompileOnly) m_Scripts[index] = strScript ?? string.Empty; m_ScriptEnable[index] = !string.IsNullOrEmpty(m_Scripts[index]); return m_ScriptEnable[index]; } public CoGfxMap GetCoGfxMap() => m_CoGfxMap; public CombinedActMap GetCombinedActMap() => m_ActionMap; public string GetPhysFileName() => m_strPhysFileName; public void SetPhysFileName(string szFile) => m_strPhysFileName = szFile ?? string.Empty; public object GetPhysSyncData() => m_pPhysSyncData; public void SetPhysSyncData(object p) => m_pPhysSyncData = p; public uint GetVersion() => m_dwVersion; public string GetPixelShaderPath() => m_strPixelShader; public void SetPixelShaderPath(string szPath) => m_strPixelShader = szPath ?? string.Empty; public string GetShaderTexture() => m_strShaderTex; public void SetShaderTexture(string szPath) => m_strShaderTex = szPath ?? string.Empty; public IList GetPSConstVec() => m_vecPSConsts; public void SetActionEventMask(int nChannel, uint dwMask) => m_EventMasks[nChannel] = dwMask; public uint GetActionEventMask(int nChannel) { return m_EventMasks.TryGetValue(nChannel, out uint mask) ? mask : uint.MaxValue; } public IReadOnlyDictionary GetActionEventMaskSnapshot() => m_EventMasks; public void OnScriptEndAction(CECModel pModel, int nChannel, string szActName) { if (!IsScriptEnabled(ECMScript.enumECMScriptEndActioin)) return; Debug.LogWarning($"CECModelStaticData.OnScriptEndAction invoked for {szActName}, scripting runtime not yet ported."); } public void Reset() { m_OrgColor = 0xFFFFFFFF; m_EmissiveColor = 0; m_fDefPlaySpeed = 1.0f; m_BlendMode = new A3DSHADER { SrcBlend = A3DBLEND.A3DBLEND_SRCALPHA, DestBlend = A3DBLEND.A3DBLEND_INVSRCALPHA }; ResetOuterData(); m_BoneScales.Clear(); m_BoneScaleExArr.Clear(); m_strScaleBaseBone = string.Empty; m_ChannelInfoDict.Clear(); m_strPhysFileName = string.Empty; } public void AddScriptMethod(int index, string szScript) { if (index < 0 || index >= (int)ECMScript.enumECMScriptCount) return; m_ScriptEnable[index] = !string.IsNullOrEmpty(szScript); } public void OnScriptPlayAction(CECModel pModel, int nChannel, string szActName) { if (!IsScriptEnabled(ECMScript.enumECMScriptStartAction)) return; Debug.LogWarning($"CECModelStaticData.OnScriptPlayAction triggered for {szActName}, scripting runtime not available."); } public void OnScriptChangeEquip(CECModel pModel, int nEquipId, int nEquipFlag, bool bFashionMode, int nPathId, int nEquipIndex) { if (!IsScriptEnabled(ECMScript.enumECMScriptChangeEquip)) return; Debug.LogWarning("CECModelStaticData.OnScriptChangeEquip called, scripting runtime not available."); } public void OnScriptPhysBreak(CECModel pModel, float fBreakOffsetX, float fBreakOffsetY, float fBreakOffsetZ) { if (!IsScriptEnabled(ECMScript.enumECMScriptPhysBreak)) return; Debug.LogWarning("CECModelStaticData.OnScriptPhysBreak called, scripting runtime not available."); } public void InitGlobalScript() { if (m_bInitGlobalScript) return; if (!IsScriptEnabled(ECMScript.enumECMScriptInit)) return; m_bInitGlobalScript = true; m_strGlobalScriptName = $"GlobalScriptFunc_{DateTime.UtcNow.Ticks}"; } public bool LoadAdditionalSkin(object pFile, uint dwVersion, bool bLoadAdditionalSkin) { Debug.LogWarning("CECModelStaticData.LoadAdditionalSkin stub invoked."); return true; } public IList GetAdditionalSkinList() => m_AdditionalSkinLst; public IList GetChildInfoArray() => m_ChildInfoArray; public float[] GetOuterData() => m_OuterData; public bool CanCastShadow => m_bCanCastShadow; public bool CanRenderSkinModel => m_bRenderSkinModel; public bool CanRenderEdge => m_bRenderEdge; private bool IsScriptEnabled(ECMScript scriptId) { int idx = (int)scriptId; if (idx < 0 || idx >= m_ScriptEnable.Length) return false; return m_ScriptEnable[idx]; } private void ResetOuterData() { for (int i = 0; i < m_OuterData.Length; i++) m_OuterData[i] = 1.0f; } } public class CLuaMemTbl { public void Init(string tableName) { } public bool AddMethod(string name, IList args, string script) => false; public void RemoveMethod(string name) { } public void Release() { } } public class CECModel { private const uint COMACT_FLAG_MODE_NONE = 0; protected CECModelStaticData m_pMapModel; public void ClearComActFlag(bool bSignalCurrent) { ClearComActFlag(0, bSignalCurrent); } public void ClearComActFlag(int nChannel, bool bSignalCurrent) { /* ChannelAct & ca = m_ChannelActs[nChannel]; ChannelActNode* pNode = ca.GetHighestRankNode(); if (pNode) { if (pNode->m_pActFlag && bSignalCurrent) *pNode->m_pActFlag = true; //ca.m_dwFlagMode = COMACT_FLAG_MODE_NONE; pNode->m_pActFlag = NULL; }*/ } public bool QueueAction(CECNPC.INFO iNFO, string szActName, ref bool pNewActFlag, int nTransTime = 200, uint dwUserData = 0, bool bForceStopPrevAct = false, bool bCheckTailDup = false, bool bNoFx = false, bool bResetSpeed = false /*joslian*/, bool bResetActFlag = false, uint dwNewFlagMode = COMACT_FLAG_MODE_NONE) { QueueAction(iNFO, 0, szActName, ref bResetActFlag, nTransTime, dwUserData, bForceStopPrevAct, bCheckTailDup, bNoFx, bResetSpeed/*joslian*/, pNewActFlag, dwNewFlagMode); return true; } public bool QueueAction(CECNPC.INFO iNFO, int nChannel, string szActName, ref bool pNewActFlag, int nTransTime, uint dwUserData/* 0 */, bool bForceStopPrevAct, bool bCheckTailDup, bool bNoFx, bool bResetSpeed /*joslian*/, bool bResetActFlag, uint dwNewFlagMode) { EventBus.PublishChannel(iNFO.nid, new QueueNPCActionEvent(szActName)); return true; } public void StopChannelAction(int nChannel, bool bStopAct, bool bStopFx = false) { //TODO: Implement StopChannelAction } public struct QueueNPCActionEvent { public string AnimationName; public QueueNPCActionEvent(string animationName) { AnimationName = animationName; } } public bool HasCHAABB() { return m_pMapModel.HasCHAABB(); } public void PlayGfx(string szPath, string szHook, float fScale, bool bFadeOut, A3DVECTOR3 vOffset, float fPitch, float fYaw, float fRot, bool bUseECMHook, uint dwFadeOutTime) { if (!bFadeOut) dwFadeOutTime = 0; string strKey = szPath; strKey += szHook; // PGFX_INFO pInfo; // // CoGfxMap::iterator it = m_CoGfxMap.find(strKey); // if (bUseECMHook) { // if (CECModelHook* pHook = GetECMHook(szHook)) // { // fScale *= pHook->GetScaleFactor(); // } // } // // if (it != m_CoGfxMap.end()) // { // pInfo = it->second; // A3DGFXEx* pGfx = pInfo->GetGfx(); // TransferEcmProperties(pGfx); // pGfx->SetScale(fScale * m_fGfxScaleFactor); // pInfo->SetFadeOutTime(dwFadeOutTime); // pInfo->SetModelAlpha(true); // pInfo->SetHookName(szHook); // pInfo->SetUseECMHook(bUseECMHook); // pInfo->SetScale(fScale); // pInfo->SetOffset(vOffset); // pInfo->SetPitch(fPitch); // pInfo->SetYaw(fYaw); // pInfo->SetRot(fRot); // pInfo->BuildTranMat(); // pGfx->SetSfxPriority(m_nSfxPriority); // pGfx->Start(true); // return; // } // // pInfo = new GFX_INFO(NULL); // pInfo->SetFilePath(szPath); // pInfo->SetHookName(szHook); // pInfo->SetUseECMHook(bUseECMHook); // pInfo->SetScale(fScale); // pInfo->Init(m_pA3DDevice); // pInfo->SetOffset(vOffset); // pInfo->SetPitch(fPitch); // pInfo->SetYaw(fYaw); // pInfo->SetRot(fRot); // pInfo->LoadGfx(); // // if (!pInfo->GetGfx()) // { // delete pInfo; // return; // } // // pInfo->BuildTranMat(); // pInfo->SetFadeOutTime(dwFadeOutTime); // pInfo->SetModelAlpha(true); // TransferEcmProperties(pInfo->GetGfx()); // pInfo->GetGfx()->SetScale(fScale * m_fGfxScaleFactor); // pInfo->GetGfx()->SetSfxPriority(m_nSfxPriority); // pInfo->GetGfx()->Start(true); // // m_CoGfxMap[strKey] = pInfo; } } // Action channel public enum ActionChannel { ACTCHA_WOUND = 1, };