Merge branch 'develop' of https://git.pthub.vn/Unity/perfect-world-unity into feature/update-ui

This commit is contained in:
VuNgocHaiC7
2026-04-06 15:37:47 +07:00
187 changed files with 81901 additions and 543 deletions
+7 -7
View File
@@ -1,9 +1,9 @@
// taskID,bezierID,speed,angle,dir,model file path
"32220,-1001,30,30.0,1,Models\NPCs\³èÎï\Æï³è\·ï»Ë\·ï»Ë.ecm"
"32221,-1003,30,30.0,1,Models\NPCs\³èÎï\Æï³è\·ï»Ë\·ï»Ë.ecm"
"32222,-1002,30,30.0,1,Models\NPCs\³èÎï\Æï³è\·ï»Ë\·ï»Ë.ecm"
"32223,-1004,30,30.0,1,Models\NPCs\³èÎï\Æï³è\·ï»Ë\·ï»Ë.ecm"
"32224,-1005,30,30.0,1,Models\NPCs\³èÎï\Æï³è\·ï»Ë\·ï»Ë.ecm"
"32428,-1006,30,30.0,1,Models\NPCs\³èÎï\Æï³è\·ï»Ë\·ï»Ë.ecm"
"32225,-1007,30,30.0,1,Models\NPCs\³èÎï\Æï³è\·ï»Ë\·ï»Ë.ecm"
"32220,-1001,30,30.0,1,Models/npcs/宠物/骑宠/凤凰/凤凰.ecm"
"32221,-1003,30,30.0,1,Models/npcs/宠物/骑宠/凤凰/凤凰.ecm"
"32222,-1002,30,30.0,1,Models/npcs/宠物/骑宠/凤凰/凤凰.ecm"
"32223,-1004,30,30.0,1,Models/npcs/宠物/骑宠/凤凰/凤凰.ecm"
"32224,-1005,30,30.0,1,Models/npcs/宠物/骑宠/凤凰/凤凰.ecm"
"32428,-1006,30,30.0,1,Models/npcs/宠物/骑宠/凤凰/凤凰.ecm"
"32225,-1007,30,30.0,1,Models/npcs/宠物/骑宠/凤凰/凤凰.ecm"
File diff suppressed because it is too large Load Diff
+56 -14
View File
@@ -215,7 +215,7 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 700879706879584381}
serializedVersion: 2
m_LocalRotation: {x: 0.0000000011722103, y: -0.26373407, z: -0.00000023176595, w: 0.9645954}
m_LocalRotation: {x: 0.0000000011722104, y: -0.2637341, z: -0.00000023176597, w: 0.96459544}
m_LocalPosition: {x: 0.16233289, y: -0.00000004810146, z: -0.000000061758335}
m_LocalScale: {x: 1, y: 1.0000001, z: 0.9999999}
m_ConstrainProportionsScale: 0
@@ -408,7 +408,7 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 870105474783592799}
serializedVersion: 2
m_LocalRotation: {x: -0.116904, y: 0.52980244, z: -0.18870111, w: 0.8185564}
m_LocalRotation: {x: -0.116904005, y: 0.5298025, z: -0.18870112, w: 0.8185565}
m_LocalPosition: {x: 0.012014532, y: -0.0000000867314, z: -0.000000065188935}
m_LocalScale: {x: 1, y: 0.9999999, z: 0.99999994}
m_ConstrainProportionsScale: 0
@@ -792,7 +792,7 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2090055399504802636}
serializedVersion: 2
m_LocalRotation: {x: -0.000000007450579, y: 0.05836967, z: 0.000000015279507, w: 0.998295}
m_LocalRotation: {x: -0.0000000074505793, y: 0.058369674, z: 0.00000001527951, w: 0.99829507}
m_LocalPosition: {x: 0.97464234, y: -0.0000001192093, z: -0.00000017881396}
m_LocalScale: {x: 1.0000001, y: 0.99999994, z: 0.9999999}
m_ConstrainProportionsScale: 0
@@ -857,7 +857,7 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2273991754805310631}
serializedVersion: 2
m_LocalRotation: {x: 0.000000015328007, y: 0.021831421, z: -0.000000014805245, w: 0.99976164}
m_LocalRotation: {x: 0.000000015328009, y: 0.021831423, z: -0.000000014805246, w: 0.9997617}
m_LocalPosition: {x: 0.7527077, y: 0.000000009196029, z: -0.00045834482}
m_LocalScale: {x: 0.9999999, y: 1, z: 1}
m_ConstrainProportionsScale: 0
@@ -1290,6 +1290,8 @@ GameObject:
m_Component:
- component: {fileID: 3453975982983096240}
- component: {fileID: 7816700123729441629}
- component: {fileID: 2347288213418982541}
- component: {fileID: 3641089161220139568}
m_Layer: 0
m_Name: "\u51E4\u51F0"
m_TagString: Untagged
@@ -1305,7 +1307,7 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3590142514949932151}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
@@ -1315,7 +1317,7 @@ Transform:
- {fileID: 6224603219712910697}
- {fileID: 1727233940975520613}
m_Father: {fileID: 1649783502964571937}
m_LocalEulerAnglesHint: {x: 0, y: 180, z: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!95 &7816700123729441629
Animator:
serializedVersion: 7
@@ -1338,6 +1340,46 @@ Animator:
m_AllowConstantClipSamplingOptimization: 1
m_KeepAnimatorStateOnDisable: 0
m_WriteDefaultValuesOnDisable: 0
--- !u!114 &2347288213418982541
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3590142514949932151}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d449242bb6214e81944862a05b7aed33, type: 3}
m_Name:
m_EditorClassIdentifier:
bones: []
bindPoses: []
rootBone: {fileID: 4586536927667645884}
--- !u!114 &3641089161220139568
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3590142514949932151}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: c75c0dcb6d50eb64abd727a90406ca2b, type: 3}
m_Name:
m_EditorClassIdentifier:
_Animator: {fileID: 7816700123729441629}
_ActionOnDisable: 0
_PlayAutomatically: 1
_Animations:
- {fileID: 7400000, guid: b612aa9768334a9438221e9ef67ab618, type: 2}
- {fileID: 7400000, guid: e7ff2fce14cfa304facf9adad5a885c1, type: 2}
- {fileID: 7400000, guid: 2335e6ff21363fe4682d43a44fb4e949, type: 2}
- {fileID: 7400000, guid: 4f487a471c7278b40bcd6a5cb13032b9, type: 2}
- {fileID: 7400000, guid: f54de864134717c47a4034684dc5d443, type: 2}
- {fileID: 7400000, guid: b612aa9768334a9438221e9ef67ab618, type: 2}
- {fileID: 7400000, guid: c80c98c187e5e4f4b8720cb0817760e4, type: 2}
- {fileID: 7400000, guid: e16a16712d922464e8a9d173dacffde4, type: 2}
- {fileID: 7400000, guid: f22348ccca70b4e408607ad52dc2d01e, type: 2}
--- !u!1 &3602394898410287554
GameObject:
m_ObjectHideFlags: 0
@@ -1393,7 +1435,7 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3786118911675041934}
serializedVersion: 2
m_LocalRotation: {x: 0.054106675, y: -0.048505306, z: 0.6238828, w: 0.7781325}
m_LocalRotation: {x: 0.054106668, y: -0.0485053, z: 0.6238827, w: 0.7781324}
m_LocalPosition: {x: 1.4803655, y: -0.038035985, z: -0.024959266}
m_LocalScale: {x: 1, y: 0.9999999, z: 0.9999998}
m_ConstrainProportionsScale: 0
@@ -1716,7 +1758,7 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4424724211710365003}
serializedVersion: 2
m_LocalRotation: {x: 0.00000008940696, y: -0.01583224, z: -0.00000006705522, w: 0.99987465}
m_LocalRotation: {x: 0.00000008940697, y: -0.015832242, z: -0.000000067055225, w: 0.9998747}
m_LocalPosition: {x: 1.4131434, y: -0.00000023841852, z: 0.00000008940699}
m_LocalScale: {x: 1, y: 1.0000001, z: 0.9999999}
m_ConstrainProportionsScale: 0
@@ -1877,7 +1919,7 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4713013740437862723}
serializedVersion: 2
m_LocalRotation: {x: 0.1315189, y: 0.9698584, z: 0.027563425, w: 0.20326757}
m_LocalRotation: {x: 0.13151892, y: 0.96985847, z: 0.027563427, w: 0.20326759}
m_LocalPosition: {x: 0.28217787, y: 0.14113632, z: -0.10175801}
m_LocalScale: {x: 0.9999998, y: 1, z: 0.99999994}
m_ConstrainProportionsScale: 0
@@ -2066,7 +2108,7 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5061385977300445428}
serializedVersion: 2
m_LocalRotation: {x: 0.000000054307304, y: -0.12958188, z: 0.00000052682435, w: 0.9915687}
m_LocalRotation: {x: 0.000000054307307, y: -0.1295819, z: 0.0000005268244, w: 0.99156874}
m_LocalPosition: {x: 0.21596491, y: -0.000000013746504, z: -0.00022520378}
m_LocalScale: {x: 0.9999999, y: 1.0000001, z: 0.99999994}
m_ConstrainProportionsScale: 0
@@ -2098,7 +2140,7 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5127379530201908994}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalRotation: {x: -0, y: -0, z: 0.000000014901161, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
@@ -2345,7 +2387,7 @@ GameObject:
m_Component:
- component: {fileID: 4767090072160652241}
m_Layer: 0
m_Name: HH_ride
m_Name: HH_Ride
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
@@ -2518,7 +2560,7 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6367996995571276794}
serializedVersion: 2
m_LocalRotation: {x: 0.00000007823107, y: 0.05836964, z: -0.00000001660373, w: 0.998295}
m_LocalRotation: {x: 0.000000078231075, y: 0.058369644, z: -0.000000016603732, w: 0.99829507}
m_LocalPosition: {x: 0.9746428, y: 0.00000035762793, z: -0.0000007152559}
m_LocalScale: {x: 0.99999976, y: 0.9999999, z: 0.99999976}
m_ConstrainProportionsScale: 0
@@ -3312,7 +3354,7 @@ Transform:
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8731122315004283578}
serializedVersion: 2
m_LocalRotation: {x: 0.54609156, y: 0.11095586, z: -0.8185872, w: 0.13923995}
m_LocalRotation: {x: 0.5460916, y: 0.110955864, z: -0.81858724, w: 0.13923997}
m_LocalPosition: {x: -0.17678149, y: -0.22698992, z: 0.037154097}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
@@ -9743,6 +9743,7 @@ MonoBehaviour:
currentTargetNPCID: 0
dialogResouce: {fileID: 11400000, guid: 540bc8e61556ba4479407a2d68e17580, type: 2}
canvasDlg: {fileID: 7894129013412138377}
_emotionLibrarySpriteMap: {fileID: 11400000, guid: f634ecf63ca3d004f82af9b17c966fc9, type: 2}
btnSecondClick: {fileID: 1330222957695115484}
m_pDlgQuickBar1: {fileID: 8338623026378970694}
ChangeSkillShortcutButton: {fileID: 335905991743982376}
+2 -2
View File
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:7245ad76b42e0f3f97f2cc7990d79ff171b5f78e64bad057b5acae21bed80395
size 321521
oid sha256:543e09f5571b2d48dd57646eee06f8efbc71e6aaa62d6e8a98a529dec44b7364
size 322591
@@ -37,7 +37,7 @@ MonoBehaviour:
prefix:
- channel: 1
iconName:
icon: {fileID: 0}
icon: {fileID: 21300000, guid: 4c42fa6e60df2184fa1a7d606bdbac8c, type: 3}
prefix: '!@'
- channel: 7
iconName:
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3011939e4e9c0ce4e83bc03a748fcf96
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,18 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &11400000
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: af2fa24fb63c4aa45bb99a711c857114, type: 3}
m_Name: EmotionLibrarySpriteMap
m_EditorClassIdentifier:
Library: {fileID: 11400000, guid: 3011939e4e9c0ce4e83bc03a748fcf96, type: 2}
TmpSpriteAsset: {fileID: 11400000, guid: c41005c129ba4d66911b75229fd70b45, type: 2}
PreferSpriteNameTag: 1
DefaultAnimFps: 10
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: f634ecf63ca3d004f82af9b17c966fc9
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 11400000
userData:
assetBundleName:
assetBundleVariant:
@@ -98,5 +98,12 @@ namespace BrewMonster
}
}
}
public void UpdateFollowObject(Transform followObject)
{
_cinemachineCamera.Follow = followObject;
_cinemachineCamera.ForceCameraPosition(followObject.position, Quaternion.identity);
orbital.HorizontalAxis.Value = 208;
orbital.VerticalAxis.Value = -268;
}
}
}
@@ -0,0 +1,49 @@
using CSNetwork;
namespace BrewMonster.Scripts.Chat
{
/// <summary>
/// Chat 表情与内联富文本 — Emotion set + TMP conversion for chat (ported from CECGameUIMan::AddChatMessage).
/// Keeps channel emotion filtering and Unmarshal/Convert-to-TMP in one place.
/// </summary>
public sealed class ChatEmotionDisplayPipeline
{
private IEmotionSpriteMap _spriteMap = new StubEmotionSpriteMap();
public ChatEmotionDisplayPipeline(IEmotionSpriteMap spriteMap = null)
{
if (spriteMap != null)
_spriteMap = spriteMap;
}
public void SetSpriteMap(IEmotionSpriteMap spriteMap)
{
_spriteMap = spriteMap ?? new StubEmotionSpriteMap();
}
/// <summary>C++: FilterEmotionSet — map inline emotion codes to the correct set for this channel.</summary>
public string ApplyChannelEmotionFilter(string pszMsg, int cEmotion)
{
return AUICommon.FilterEmotionSet(pszMsg, cEmotion);
}
/// <summary>
/// TMP: Unmarshal edit-box item codes and convert emotion / coord / inventory links to TMP rich text.
/// Call after <see cref="CECUIManager.FilterBadWords"/> when the message is from a player channel.
/// </summary>
public string ConvertInlineItemsToTmp(string pszMsgAfterBadWordFilter)
{
EditBoxItemsSet itemsSet = new EditBoxItemsSet();
string displayText = AUICommon.UnmarshalEditBoxText(pszMsgAfterBadWordFilter, itemsSet);
if (itemsSet.GetItemCount() <= 0)
return pszMsgAfterBadWordFilter;
string tmpText = displayText;
tmpText = AUICommon.ConvertEmotionsToTMP(tmpText, itemsSet, _spriteMap);
tmpText = AUICommon.ConvertCoordsToTMP(tmpText, itemsSet);
tmpText = AUICommon.ConvertIvtrItemsToTMP(tmpText, itemsSet);
tmpText = AUICommon.StripRemainingItemCodes(tmpText);
return tmpText;
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 017020ee87cf87d40abfd39726e185c0
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: b434da58bb8623f439f5cbf37342f155
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,32 @@
using System;
using UnityEngine;
namespace BrewMonster.Scripts.Chat.EmotionData
{
/// <summary>
/// Một dòng định nghĩa emotion trong Emotions{N}.txt (port từ AUITEXTAREA_EMOTION).
/// One emotion definition line from Emotions{N}.txt (ported from AUITEXTAREA_EMOTION).
/// </summary>
[Serializable]
public class EmotionEntryData
{
[Tooltip("Chỉ số ô bắt đầu trong lưới cell (nStartPos) — Starting cell index in the atlas grid.")]
public int StartPos;
[Tooltip("Số frame animation (nNumFrames), tối đa 20 như C++.")]
public int NumFrames;
[Tooltip("Tooltip / hint text từ file txt.")]
public string Hint = "";
/// <summary>
/// Thời điểm tick cho từng frame (nFrameTick[i]), độ dài = NumFrames.
/// </summary>
public int[] FrameTicks = Array.Empty<int>();
/// <summary>
/// Sprite đã cắt cho từng frame (gán bởi tool), độ dài = NumFrames khi đã convert.
/// </summary>
public Sprite[] FrameSprites = Array.Empty<Sprite>();
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: a0e42b4b83e3a6f40a2a7737f584fdc6
@@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace BrewMonster.Scripts.Chat.EmotionData
{
/// <summary>
/// Snapshot một bộ Emotions{N} (dùng embed trong EmotionLibrarySO hoặc copy sang EmotionSetDataSO).
/// One Emotions{N} snapshot (embedded in EmotionLibrarySO or copied to EmotionSetDataSO).
/// </summary>
[Serializable]
public class EmotionSetSnapshot
{
public int EmotionSetIndex;
public int CellWidth = 32;
public int CellHeight = 32;
public Texture2D SourceAtlas;
public string SourceTxtAssetPath = "";
public List<EmotionEntryData> Entries = new List<EmotionEntryData>();
}
/// <summary>
/// Một ScriptableObject chứa nhiều bộ emotion (vd. emotions0emotions7).
/// Single SO holding multiple emotion sets (e.g. all 8 atlases).
/// </summary>
[CreateAssetMenu(fileName = "EmotionLibrary", menuName = "Perfect World/Chat/Emotion Library (All Sets)", order = 1)]
public class EmotionLibrarySO : ScriptableObject
{
[Tooltip("Danh sách các bộ theo EmotionSetIndex (0,1,2,…).")]
public List<EmotionSetSnapshot> Sets = new List<EmotionSetSnapshot>();
public EmotionSetSnapshot GetSetOrNull(int emotionSetIndex)
{
if (Sets == null) return null;
foreach (var s in Sets)
{
if (s != null && s.EmotionSetIndex == emotionSetIndex)
return s;
}
return null;
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 3805edc4ea793a54eabafdd3e7e48581
@@ -0,0 +1,123 @@
using System;
using TMPro;
using UnityEngine;
namespace BrewMonster.Scripts.Chat.EmotionData
{
/// <summary>
/// Ánh xạ (emotionSet, emotionIndex) từ <see cref="EmotionLibrarySO"/> sang tag TMP.
/// Gán asset này vào <see cref="CECUIManager"/> (field emotion) — <see cref="BrewMonster.UI.CECGameUIMan"/> không phải MonoBehaviour nên không kéo SO trên Inspector được.
///
/// Cách dùng:
/// 1) Tạo <see cref="EmotionLibrarySO"/> bằng Emotion Atlas Converter.
/// 2) Tạo <see cref="TMP_SpriteAsset"/> từ cùng atlas (Window → TextMeshPro → Sprite Importer),
/// đảm bảo tên sub-sprite khớp (vd. cell_0000) với atlas Multiple từ tool.
/// 3) Gán TMP_SpriteAsset vào ô chat <see cref="TMPro.TextMeshProUGUI"/> (Sprite Asset / Additional).
/// 4) Kéo SO này vào field trên GameObject có <see cref="CECUIManager"/> (Awake gọi SetEmotionSpriteMap).
/// </summary>
[CreateAssetMenu(fileName = "EmotionLibrarySpriteMap", menuName = "Perfect World/Chat/Emotion Library Sprite Map", order = 2)]
public class EmotionLibrarySpriteMap : ScriptableObject, IEmotionSpriteMap
{
[Tooltip("Dữ liệu emotion đã convert (Entries + FrameSprites).")]
public EmotionLibrarySO Library;
[Tooltip("Sprite Asset dùng cho chat TMP — cùng tên sub-sprite với atlas (cell_XXXX). Bắt buộc cho emoji động (anim) hoặc khi không dùng name tag.")]
public TMP_SpriteAsset TmpSpriteAsset;
[Tooltip("Nếu true và chỉ 1 frame: thử <sprite name=\"...\"> (không cần tra index). Động (nhiều frame) vẫn cần TmpSpriteAsset để tra index.")]
public bool PreferSpriteNameTag = true;
[Tooltip("FPS mặc định cho <sprite anim> khi không suy ra được từ FrameTicks.")]
public int DefaultAnimFps = 10;
public bool TryGetSprite(int emotionSet, int emotionIndex, out EmotionSpriteInfo info)
{
info = default;
if (Library == null)
return false;
EmotionSetSnapshot set = Library.GetSetOrNull(emotionSet);
if (set == null || emotionIndex < 0 || emotionIndex >= set.Entries.Count)
return false;
EmotionEntryData entry = set.Entries[emotionIndex];
Sprite[] frames = entry.FrameSprites;
if (frames == null || frames.Length == 0)
return false;
if (frames.Length == 1)
{
Sprite s0 = frames[0];
if (s0 == null)
return false;
if (PreferSpriteNameTag && !string.IsNullOrEmpty(s0.name))
{
info = new EmotionSpriteInfo
{
UseSpriteName = true,
SpriteName = s0.name,
IsAnimated = false
};
return true;
}
int idx = FindSpriteIndexInTmpAsset(s0.name);
if (idx < 0)
return false;
info = new EmotionSpriteInfo { SpriteIndex = idx, IsAnimated = false };
return true;
}
if (TmpSpriteAsset == null)
return false;
int start = FindSpriteIndexInTmpAsset(frames[0]?.name);
int end = FindSpriteIndexInTmpAsset(frames[frames.Length - 1]?.name);
if (start < 0 || end < 0)
return false;
int fps = EstimateFps(entry.FrameTicks, frames.Length);
info = new EmotionSpriteInfo
{
SpriteIndex = start,
IsAnimated = true,
AnimEndFrame = end,
AnimFPS = fps > 0 ? fps : DefaultAnimFps
};
return true;
}
private int FindSpriteIndexInTmpAsset(string spriteName)
{
if (TmpSpriteAsset == null || string.IsNullOrEmpty(spriteName))
return -1;
if (TmpSpriteAsset.spriteInfoList != null)
{
for (int i = 0; i < TmpSpriteAsset.spriteInfoList.Count; i++)
{
var s = TmpSpriteAsset.spriteInfoList[i];
if (s != null && s.name == spriteName)
return i;
}
}
return -1;
}
private static int EstimateFps(int[] frameTicks, int numFrames)
{
if (frameTicks == null || numFrames < 2 || frameTicks.Length < numFrames)
return 0;
int last = frameTicks[numFrames - 1];
int first = frameTicks[0];
int span = last - first;
if (span <= 0)
return 0;
return Mathf.Max(1, Mathf.RoundToInt((numFrames - 1) * 60f / span));
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: af2fa24fb63c4aa45bb99a711c857114
@@ -0,0 +1,46 @@
using System.Collections.Generic;
using UnityEngine;
namespace BrewMonster.Scripts.Chat.EmotionData
{
/// <summary>
/// Dữ liệu một bộ emotion (tương ứng Emotions{N}.dds + Emotions{N}.txt).
/// Data for one emotion group (matches Emotions{N}.dds + Emotions{N}.txt).
/// </summary>
[CreateAssetMenu(fileName = "EmotionSetData", menuName = "Perfect World/Chat/Emotion Set Data", order = 0)]
public class EmotionSetDataSO : ScriptableObject
{
[Tooltip("N trong Emotions{N} (0..31 như AUIMANAGER_MAX_EMOTIONGROUPS).")]
public int EmotionSetIndex;
[Tooltip("Kích thước ô lưới giống C++ (mặc định 32x32).")]
public int CellWidth = 32;
[Tooltip("Kích thước ô lưới giống C++ (mặc định 32x32).")]
public int CellHeight = 32;
[Tooltip("Texture nguồn (atlas PNG/DDS import) dùng khi convert.")]
public Texture2D SourceAtlas;
[Tooltip("Đường dẫn asset của file txt nguồn (optional, để trace).")]
public string SourceTxtAssetPath;
public List<EmotionEntryData> Entries = new List<EmotionEntryData>();
/// <summary>
/// Số ô theo chiều ngang trong atlas (texture width / CellWidth).
/// </summary>
public int GridCellsX => SourceAtlas != null && CellWidth > 0
? SourceAtlas.width / CellWidth
: 0;
/// <summary>
/// Số ô theo chiều dọc.
/// </summary>
public int GridCellsY => SourceAtlas != null && CellHeight > 0
? SourceAtlas.height / CellHeight
: 0;
public int TotalCells => GridCellsX * GridCellsY;
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 2143882ad81a4ac4ea7e23512f481104
@@ -0,0 +1,147 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
namespace BrewMonster.Scripts.Chat.EmotionData
{
/// <summary>
/// Parser token giống thứ tự đọc trong AUIManager.cpp (Emotions{N}.txt).
/// Token order matches AUIManager.cpp when loading Emotions{N}.txt.
/// </summary>
public static class EmotionTxtParser
{
public const int MaxFrames = 20; // AUITEXTAREA_EMOTHION_MAXFRAME
public readonly struct ParseResult
{
public readonly List<EmotionEntryData> Entries;
public readonly string ErrorMessage;
public bool Success => string.IsNullOrEmpty(ErrorMessage);
public ParseResult(List<EmotionEntryData> entries, string error)
{
Entries = entries;
ErrorMessage = error ?? "";
}
}
/// <summary>
/// Đọc toàn bộ nội dung file txt; token tách bằng whitespace (giống GetNextToken cơ bản).
/// Reads full txt; tokens split by whitespace (basic GetNextToken behavior).
/// </summary>
public static ParseResult Parse(string text)
{
if (string.IsNullOrWhiteSpace(text))
return new ParseResult(new List<EmotionEntryData>(), "Empty text.");
var tokens = Tokenize(text);
var entries = new List<EmotionEntryData>();
int t = 0;
while (t < tokens.Count)
{
if (!TryParseInt(tokens[t], out int startPos))
return new ParseResult(null, $"Invalid nStartPos at token index {t}: '{tokens[t]}'");
t++;
if (t >= tokens.Count)
return new ParseResult(null, "Unexpected EOF after nStartPos.");
if (!TryParseInt(tokens[t], out int numFramesRaw))
return new ParseResult(null, $"Invalid nNumFrames at token index {t}.");
int numFrames = Math.Min(Math.Max(0, numFramesRaw), MaxFrames);
t++;
if (t >= tokens.Count)
return new ParseResult(null, "Unexpected EOF after nNumFrames (missing hint).");
string hint = tokens[t];
t++;
var frameTicks = new int[numFrames];
for (int i = 0; i < numFrames; i++)
{
if (t >= tokens.Count)
return new ParseResult(null,
$"Unexpected EOF: need {numFrames} frame tick values for entry starting at StartPos={startPos}.");
if (!TryParseInt(tokens[t], out frameTicks[i]))
return new ParseResult(null, $"Invalid nFrameTick[{i}] at token index {t}.");
t++;
}
entries.Add(new EmotionEntryData
{
StartPos = startPos,
NumFrames = numFrames,
Hint = hint,
FrameTicks = frameTicks
});
}
return new ParseResult(entries, null);
}
private static bool TryParseInt(string s, out int v)
{
return int.TryParse(s, NumberStyles.Integer, CultureInfo.InvariantCulture, out v);
}
/// <summary>
/// Tách token: khoảng trắng; hỗ trợ chuỗi trong dấu ngoặc kép cho hint nếu sau này cần.
/// </summary>
private static List<string> Tokenize(string text)
{
var list = new List<string>();
var sb = new StringBuilder();
bool inQuotes = false;
for (int i = 0; i < text.Length; i++)
{
char c = text[i];
if (inQuotes)
{
if (c == '"')
inQuotes = false;
else
sb.Append(c);
continue;
}
if (c == '"')
{
if (sb.Length > 0)
{
list.Add(sb.ToString());
sb.Clear();
}
inQuotes = true;
continue;
}
if (char.IsWhiteSpace(c))
{
if (sb.Length > 0)
{
list.Add(sb.ToString());
sb.Clear();
}
continue;
}
sb.Append(c);
}
if (sb.Length > 0)
list.Add(sb.ToString());
return list;
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 656924d32be0e3c469b409078941188e
@@ -0,0 +1,29 @@
/// <summary>
/// Stub实现 — 在没有真实TMP_SpriteAsset(emotion atlas)时使用的占位映射。
/// Stub implementation used when no real TMP_SpriteAsset (emotion atlas) is available yet.
///
/// 当准备好atlas后,创建一个新的IEmotionSpriteMap实现,替换掉这个stub。
/// When atlas is ready, create a real IEmotionSpriteMap implementation and swap it in
/// ChatEmotionDisplayPipeline / CECGameUIMan emotion pipeline.
/// </summary>
public class StubEmotionSpriteMap : IEmotionSpriteMap
{
private const int EMOTIONS_PER_SET = 50;
private const int FRAMES_PER_EMOTION = 4;
private const int DEFAULT_FPS = 10;
public bool TryGetSprite(int emotionSet, int emotionIndex, out EmotionSpriteInfo info)
{
int startFrame = (emotionSet * EMOTIONS_PER_SET + emotionIndex) * FRAMES_PER_EMOTION;
info = new EmotionSpriteInfo
{
SpriteIndex = startFrame,
IsAnimated = true,
AnimEndFrame = startFrame + FRAMES_PER_EMOTION - 1,
AnimFPS = DEFAULT_FPS
};
return true;
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 8b0342124b298f0428adfc94c9d6d972
@@ -1249,10 +1249,6 @@ public static class generate_item_temp
return 0;
}
public struct PetSkill {
public int skill;
public int level;
}
public static int generate_pet_egg<RAND_CLASS>(uint id, ID_SPACE idspace, out byte[] data, out uint size, RAND_CLASS cls)
{
DATA_TYPE datatype = DATA_TYPE.DT_INVALID;
@@ -1,5 +1,5 @@
using BrewMonster.Network;
using BrewMonster.Scripts.Managers;
using BrewMonster.Scripts;
using CSNetwork.C2SCommand;
using CSNetwork.Protocols;
using CSNetwork.S2CCommand;
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 63ad32ae8f64ef1449e51fe4460570a8
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,348 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using BrewMonster.Scripts.Chat.EmotionData;
using UnityEditor;
using UnityEngine;
namespace BrewMonster.Scripts.Editor
{
/// <summary>
/// Convert một bộ: ghi atlas (hoặc slice tại chỗ) + TextureImporter Sprite Multiple full lưới,
/// gán FrameSprites theo tên cell_XXXX khớp C++ (row-major, hàng trên = row 0).
/// </summary>
public static class EmotionAtlasConverterCore
{
public const string CellSpriteNamePrefix = "cell_";
public static string CellSpriteName(int cellIndex) => $"{CellSpriteNamePrefix}{cellIndex:D4}";
/// <param name="sliceInPlace">true = chỉnh importer trên asset atlas hiện tại (ghi đè import settings). false = copy PNG vào thư mục output rồi slice (an toàn hơn).</param>
public static bool ConvertOneSet(
Texture2D sourceAtlas,
TextAsset txtAsset,
int emotionSetIndex,
int cellW,
int cellH,
string outputRootFolder,
bool sliceInPlace,
out EmotionSetSnapshot snapshot,
out string error)
{
snapshot = null;
error = null;
if (sourceAtlas == null)
{
error = "Atlas null.";
return false;
}
if (txtAsset == null)
{
error = "TextAsset null.";
return false;
}
string sourceAtlasPath = AssetDatabase.GetAssetPath(sourceAtlas);
if (string.IsNullOrEmpty(sourceAtlasPath))
{
error = "Atlas không phải asset trong project.";
return false;
}
var parseResult = EmotionTxtParser.Parse(txtAsset.text);
if (!parseResult.Success)
{
error = parseResult.ErrorMessage;
return false;
}
if (cellW <= 0 || cellH <= 0)
{
error = "Cell size phải > 0.";
return false;
}
Texture2D readable = GetReadableTexture(sourceAtlas);
if (readable == null)
{
error = "Không đọc được pixel từ atlas.";
return false;
}
try
{
int texW = readable.width;
int texH = readable.height;
if (texW % cellW != 0 || texH % cellH != 0)
{
error = $"Texture ({texW}x{texH}) không chia hết cho cell ({cellW}x{cellH}).";
return false;
}
int nNumX = texW / cellW;
int nNumY = texH / cellH;
int totalCells = nNumX * nNumY;
foreach (var e in parseResult.Entries)
{
if (e.NumFrames > 0 && e.StartPos + e.NumFrames - 1 >= totalCells)
{
error = $"Set {emotionSetIndex}: StartPos={e.StartPos}, NumFrames={e.NumFrames} vượt lưới ({totalCells} ô).";
return false;
}
}
EnsureFolder(outputRootFolder);
string setFolder = $"{outputRootFolder}/Emotions{emotionSetIndex}";
if (!AssetDatabase.IsValidFolder(setFolder))
AssetDatabase.CreateFolder(outputRootFolder, $"Emotions{emotionSetIndex}");
string atlasAssetPath;
Texture2D atlasForSo;
if (sliceInPlace)
{
atlasAssetPath = sourceAtlasPath;
if (!ApplyMultipleSpriteSheet(atlasAssetPath, texW, texH, cellW, cellH, nNumX, nNumY, out error))
return false;
atlasForSo = AssetDatabase.LoadAssetAtPath<Texture2D>(atlasAssetPath);
if (atlasForSo == null)
{
error = "Không load lại Texture2D sau slice.";
return false;
}
}
else
{
string fileName = $"Emotions{emotionSetIndex}_atlas.png";
atlasAssetPath = $"{setFolder}/{fileName}";
byte[] png = readable.EncodeToPNG();
File.WriteAllBytes(atlasAssetPath, png);
AssetDatabase.Refresh();
if (!ApplyMultipleSpriteSheet(atlasAssetPath, texW, texH, cellW, cellH, nNumX, nNumY, out error))
return false;
atlasForSo = AssetDatabase.LoadAssetAtPath<Texture2D>(atlasAssetPath);
if (atlasForSo == null)
{
error = $"Không load texture tại {atlasAssetPath}";
return false;
}
}
var spriteByName = LoadSpritesByName(atlasAssetPath);
if (spriteByName.Count < totalCells)
{
error = $"Chỉ tìm thấy {spriteByName.Count}/{totalCells} sprite sau import.";
return false;
}
snapshot = new EmotionSetSnapshot
{
EmotionSetIndex = emotionSetIndex,
CellWidth = cellW,
CellHeight = cellH,
SourceAtlas = atlasForSo,
SourceTxtAssetPath = AssetDatabase.GetAssetPath(txtAsset),
Entries = new List<EmotionEntryData>()
};
foreach (var src in parseResult.Entries)
{
var copy = new EmotionEntryData
{
StartPos = src.StartPos,
NumFrames = src.NumFrames,
Hint = src.Hint,
FrameTicks = (int[])src.FrameTicks.Clone(),
FrameSprites = new Sprite[src.NumFrames]
};
for (int f = 0; f < src.NumFrames; f++)
{
int cellIndex = src.StartPos + f;
string key = CellSpriteName(cellIndex);
if (!spriteByName.TryGetValue(key, out var spr) || spr == null)
{
error = $"Thiếu sprite '{key}' trong atlas.";
return false;
}
copy.FrameSprites[f] = spr;
}
snapshot.Entries.Add(copy);
}
return true;
}
finally
{
if (readable != null && readable != sourceAtlas)
Object.DestroyImmediate(readable);
}
}
private static bool ApplyMultipleSpriteSheet(
string assetPath,
int texW,
int texH,
int cellW,
int cellH,
int nNumX,
int nNumY,
out string error)
{
error = null;
var importer = AssetImporter.GetAtPath(assetPath) as TextureImporter;
if (importer == null)
{
error = $"Không mở TextureImporter: {assetPath}";
return false;
}
importer.textureType = TextureImporterType.Sprite;
importer.spriteImportMode = SpriteImportMode.Multiple;
importer.spritePixelsPerUnit = 100;
importer.mipmapEnabled = false;
importer.alphaIsTransparency = true;
importer.maxTextureSize = Mathf.Max(importer.maxTextureSize, Mathf.Max(texW, texH));
importer.spritesheet = BuildSpriteMetaData(texW, texH, cellW, cellH, nNumX, nNumY);
importer.SetPlatformTextureSettings(new TextureImporterPlatformSettings
{
name = "Default",
overridden = false
});
importer.SaveAndReimport();
return true;
}
private static SpriteMetaData[] BuildSpriteMetaData(int texW, int texH, int cellW, int cellH, int nNumX, int nNumY)
{
var list = new List<SpriteMetaData>(nNumX * nNumY);
for (int row = 0; row < nNumY; row++)
{
for (int col = 0; col < nNumX; col++)
{
int cellIndex = row * nNumX + col;
float x = col * cellW;
float y = texH - (row + 1) * cellH;
list.Add(new SpriteMetaData
{
name = CellSpriteName(cellIndex),
rect = new Rect(x, y, cellW, cellH),
pivot = new Vector2(0.5f, 0.5f),
alignment = (int)SpriteAlignment.Center,
border = Vector4.zero
});
}
}
return list.ToArray();
}
private static Dictionary<string, Sprite> LoadSpritesByName(string atlasAssetPath)
{
var map = new Dictionary<string, Sprite>();
foreach (var o in AssetDatabase.LoadAllAssetsAtPath(atlasAssetPath))
{
if (o is Sprite sp && !string.IsNullOrEmpty(sp.name))
map[sp.name] = sp;
}
return map;
}
public static void EnsureFolder(string folder)
{
if (AssetDatabase.IsValidFolder(folder))
return;
string parent = "Assets";
foreach (var part in folder.Replace('\\', '/').Split('/'))
{
if (string.IsNullOrEmpty(part) || part == "Assets")
continue;
string newPath = parent + "/" + part;
if (!AssetDatabase.IsValidFolder(newPath))
AssetDatabase.CreateFolder(parent, part);
parent = newPath;
}
}
public static void ApplySnapshotToSetSO(EmotionSetDataSO so, EmotionSetSnapshot snap)
{
if (so == null || snap == null) return;
so.EmotionSetIndex = snap.EmotionSetIndex;
so.CellWidth = snap.CellWidth;
so.CellHeight = snap.CellHeight;
so.SourceAtlas = snap.SourceAtlas;
so.SourceTxtAssetPath = snap.SourceTxtAssetPath;
so.Entries.Clear();
foreach (var e in snap.Entries)
so.Entries.Add(e);
}
/// <summary>
/// Kiểm tra trùng EmotionSetIndex giữa các slot đang có đủ Atlas+Txt.
/// </summary>
public static bool TryValidateBatchIndices(IReadOnlyList<EmotionBatchSlot> slots, out string error)
{
error = null;
var used = new HashSet<int>();
foreach (var s in slots)
{
if (s?.Atlas == null && s?.Txt == null)
continue;
if (s.Atlas == null || s.Txt == null)
continue;
if (!used.Add(s.EmotionSetIndex))
{
error = $"Trùng Emotion set index: {s.EmotionSetIndex}";
return false;
}
}
return true;
}
private static Texture2D GetReadableTexture(Texture2D atlas)
{
try
{
var dup = new Texture2D(atlas.width, atlas.height, TextureFormat.RGBA32, false);
var prev = RenderTexture.active;
var rt = RenderTexture.GetTemporary(atlas.width, atlas.height, 0, RenderTextureFormat.ARGB32);
Graphics.Blit(atlas, rt);
RenderTexture.active = rt;
dup.ReadPixels(new Rect(0, 0, atlas.width, atlas.height), 0, 0);
dup.Apply(false, false);
RenderTexture.active = prev;
RenderTexture.ReleaseTemporary(rt);
return dup;
}
catch
{
return null;
}
}
}
/// <summary>
/// Một dòng batch: index bộ (N) + atlas + txt — có thể thêm/bớt trong cửa sổ tool.
/// </summary>
[System.Serializable]
public class EmotionBatchSlot
{
[Tooltip("N trong Emotions{N} (thư mục output & tên file atlas copy).")]
public int EmotionSetIndex;
public Texture2D Atlas;
public TextAsset Txt;
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 38dfc1555b7238a4c99647d8d8dcb7e4
@@ -0,0 +1,229 @@
using System.Collections.Generic;
using BrewMonster.Scripts.Chat.EmotionData;
using UnityEditor;
using UnityEngine;
namespace BrewMonster.Scripts.Editor
{
/// <summary>
/// Tool: atlas + txt → Sprite Mode Multiple (một PNG/bộ) + SO; batch linh hoạt số slot.
/// </summary>
public class EmotionAtlasConverterWindow : EditorWindow
{
private Texture2D _sourceAtlas;
private TextAsset _txtAsset;
private int _emotionSetIndex;
private int _cellW = 32;
private int _cellH = 32;
private string _outputFolder = "Assets/PerfectWorld/UI/Chat/GeneratedEmotions";
private bool _sliceInPlace;
private List<EmotionBatchSlot> _batchSlots = new List<EmotionBatchSlot>();
private Vector2 _batchScroll;
private string _libraryAssetPath = "Assets/PerfectWorld/UI/Chat/GeneratedEmotions/EmotionLibrary.asset";
[MenuItem("Tools/Perfect World/ChatSystem/Emotion Atlas Converter…")]
public static void Open()
{
GetWindow<EmotionAtlasConverterWindow>(true, "Emotion Atlas Converter", true);
}
private void OnEnable()
{
if (_batchSlots == null)
_batchSlots = new List<EmotionBatchSlot>();
if (_batchSlots.Count == 0)
{
for (int i = 0; i < 8; i++)
_batchSlots.Add(new EmotionBatchSlot { EmotionSetIndex = i });
}
}
private void OnGUI()
{
EditorGUILayout.LabelField("Chung / Shared", EditorStyles.boldLabel);
_cellW = EditorGUILayout.IntField("Cell width (W)", _cellW);
_cellH = EditorGUILayout.IntField("Cell height (H)", _cellH);
_outputFolder = EditorGUILayout.TextField("Output folder", _outputFolder);
_sliceInPlace = EditorGUILayout.ToggleLeft(
"Slice tại asset nguồn (ghi đè import Multiple lên atlas đang chọn) — Slice in-place on source asset",
_sliceInPlace);
if (_sliceInPlace)
{
EditorGUILayout.HelpBox(
"Cảnh báo: Unity sẽ đổi import của file atlas gốc thành Sprite Multiple full lưới.\n" +
"Warning: overwrites source texture import settings.",
MessageType.Warning);
}
else
{
EditorGUILayout.HelpBox(
"Mặc định: copy atlas vào Output/Emotions{N}/Emotions{N}_atlas.png rồi Multiple slice (giữ nguyên file nguồn).\n" +
"Default: copy atlas to output folder then slice (source unchanged).",
MessageType.None);
}
EditorGUILayout.Space(8f);
EditorGUILayout.LabelField("Một bộ / Single set", EditorStyles.boldLabel);
_sourceAtlas = (Texture2D)EditorGUILayout.ObjectField("Atlas", _sourceAtlas, typeof(Texture2D), false);
_txtAsset = (TextAsset)EditorGUILayout.ObjectField("EmotionsN.txt", _txtAsset, typeof(TextAsset), false);
_emotionSetIndex = EditorGUILayout.IntField("Emotion set index (N)", _emotionSetIndex);
EditorGUILayout.Space();
if (GUILayout.Button("Convert → EmotionSetData + Atlas (Multiple)"))
{
RunConvertSingle();
}
EditorGUILayout.Space(12f);
EditorGUILayout.LabelField("Batch → EmotionLibrary", EditorStyles.boldLabel);
EditorGUILayout.BeginHorizontal();
if (GUILayout.Button("+ Thêm slot", GUILayout.Width(100)))
_batchSlots.Add(new EmotionBatchSlot { EmotionSetIndex = NextSuggestedSetIndex() });
if (GUILayout.Button(" Xóa slot cuối", GUILayout.Width(120)) && _batchSlots.Count > 0)
_batchSlots.RemoveAt(_batchSlots.Count - 1);
EditorGUILayout.LabelField($"Số slot: {_batchSlots.Count}");
EditorGUILayout.EndHorizontal();
_batchScroll = EditorGUILayout.BeginScrollView(_batchScroll, GUILayout.MinHeight(160f));
for (int i = 0; i < _batchSlots.Count; i++)
{
var slot = _batchSlots[i];
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUILayout.BeginHorizontal();
EditorGUILayout.LabelField($"#{i}", GUILayout.Width(24));
slot.EmotionSetIndex = EditorGUILayout.IntField("Set N", slot.EmotionSetIndex, GUILayout.Width(120));
slot.Atlas = (Texture2D)EditorGUILayout.ObjectField(slot.Atlas, typeof(Texture2D), false);
slot.Txt = (TextAsset)EditorGUILayout.ObjectField(slot.Txt, typeof(TextAsset), false);
if (GUILayout.Button("×", GUILayout.Width(22)))
{
_batchSlots.RemoveAt(i);
i--;
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndVertical();
continue;
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndVertical();
}
EditorGUILayout.EndScrollView();
_libraryAssetPath = EditorGUILayout.TextField("Library .asset path", _libraryAssetPath);
EditorGUILayout.Space();
if (GUILayout.Button("Convert batch → EmotionLibrary.asset"))
{
RunConvertLibrary();
}
EditorGUILayout.Space(8f);
EditorGUILayout.HelpBox(
"Mỗi bộ: một texture **Sprite Multiple**, tên sub-sprite `cell_0000` … theo chỉ số ô (giống C++).\n" +
"Each set: one **Sprite Multiple** texture; sub-sprite names `cell_0000` … by cell index.",
MessageType.Info);
}
private int NextSuggestedSetIndex()
{
int max = -1;
foreach (var s in _batchSlots)
{
if (s.EmotionSetIndex > max)
max = s.EmotionSetIndex;
}
return max + 1;
}
private void RunConvertSingle()
{
if (!EmotionAtlasConverterCore.ConvertOneSet(
_sourceAtlas, _txtAsset, _emotionSetIndex, _cellW, _cellH, _outputFolder, _sliceInPlace,
out var snapshot, out string err))
{
EditorUtility.DisplayDialog("Error", err, "OK");
return;
}
var so = ScriptableObject.CreateInstance<EmotionSetDataSO>();
EmotionAtlasConverterCore.ApplySnapshotToSetSO(so, snapshot);
string setFolder = $"{_outputFolder}/Emotions{_emotionSetIndex}";
string soPath = $"{setFolder}/EmotionSetData_{_emotionSetIndex}.asset";
AssetDatabase.CreateAsset(so, soPath);
AssetDatabase.SaveAssets();
EditorUtility.DisplayDialog("Done", $"Đã tạo:\n{soPath}\nAtlas (Multiple) trong thư mục set (hoặc đã slice tại nguồn).", "OK");
EditorGUIUtility.PingObject(so);
}
private void RunConvertLibrary()
{
if (!EmotionAtlasConverterCore.TryValidateBatchIndices(_batchSlots, out string dupErr))
{
EditorUtility.DisplayDialog("Error", dupErr, "OK");
return;
}
var library = ScriptableObject.CreateInstance<EmotionLibrarySO>();
library.Sets.Clear();
int ok = 0;
int total = _batchSlots.Count;
for (int i = 0; i < total; i++)
{
var slot = _batchSlots[i];
if (slot.Atlas == null && slot.Txt == null)
continue;
if (slot.Atlas == null || slot.Txt == null)
{
EditorUtility.DisplayDialog("Error",
$"Slot #{i} (Set N={slot.EmotionSetIndex}): cần cả Atlas và TXT.",
"OK");
Object.DestroyImmediate(library);
return;
}
EditorUtility.DisplayProgressBar("Emotion Library", $"Set {slot.EmotionSetIndex}…", (float)i / Mathf.Max(1, total));
if (!EmotionAtlasConverterCore.ConvertOneSet(
slot.Atlas, slot.Txt, slot.EmotionSetIndex, _cellW, _cellH, _outputFolder, _sliceInPlace,
out var snapshot, out string err))
{
EditorUtility.ClearProgressBar();
EditorUtility.DisplayDialog("Error", $"Set {slot.EmotionSetIndex}: {err}", "OK");
Object.DestroyImmediate(library);
return;
}
library.Sets.Add(snapshot);
ok++;
}
EditorUtility.ClearProgressBar();
if (ok == 0)
{
EditorUtility.DisplayDialog("Error", "Không có cặp Atlas+TXT hợp lệ.", "OK");
Object.DestroyImmediate(library);
return;
}
string dir = System.IO.Path.GetDirectoryName(_libraryAssetPath)?.Replace('\\', '/') ?? _outputFolder;
if (!string.IsNullOrEmpty(dir))
EmotionAtlasConverterCore.EnsureFolder(dir);
AssetDatabase.CreateAsset(library, _libraryAssetPath);
AssetDatabase.SaveAssets();
EditorUtility.DisplayDialog("Done",
$"EmotionLibrary: {ok} bộ.\n{_libraryAssetPath}",
"OK");
EditorGUIUtility.PingObject(library);
}
}
}
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: bd89b10678fe79046af39970b5c83b4c
@@ -455,6 +455,10 @@ namespace BrewMonster.Scripts
{
pWorkNavigate.Finish();
}
else
{
pWorkNavigate.Cancel();
}
}
else
{
@@ -1,8 +1,9 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using System.Globalization;
using System.Threading.Tasks;
using UnityEngine;
using CSNetwork.GPDataType;
using BrewMonster.Scripts.Task;
@@ -151,6 +152,34 @@ namespace BrewMonster.Scripts
private const string DEFAULT_FORCE_NAVIGATE_CONFIG_ADDRESS = "Assets/Addressable/force_navigate.txt";
private bool m_bConfigLoaded = false;
// Decode raw file bytes: UTF-8 (optional BOM), else strict UTF-8; on invalid UTF-8 fall back to GBK (code page 936) for legacy PC exports.
// 解码原始文件字节:UTF-8(可选 BOM),否则严格 UTF-8;非法 UTF-8 时回退到 GBK(代码页 936)以兼容老 PC 导出。
private static string DecodeNavigateConfigText(byte[] bytes)
{
if (bytes == null || bytes.Length == 0)
{
return string.Empty;
}
int offset = 0;
if (bytes.Length >= 3 && bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF)
{
offset = 3;
}
int len = bytes.Length - offset;
var utf8Strict = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false, throwOnInvalidBytes: true);
try
{
return utf8Strict.GetString(bytes, offset, len);
}
catch (DecoderFallbackException)
{
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
return Encoding.GetEncoding(936).GetString(bytes, offset, len);
}
}
// Ensure default config is loaded (safe to call multiple times).
// 确保默认配置已加载(可重复调用)。
private void EnsureDefaultConfigLoaded()
@@ -184,13 +213,20 @@ namespace BrewMonster.Scripts
{
Addressables.InitializeAsync().WaitForCompletion();
var ta = Addressables.LoadAssetAsync<TextAsset>(address).WaitForCompletion();
if (ta == null || string.IsNullOrEmpty(ta.text))
if (ta == null || ta.bytes == null || ta.bytes.Length == 0)
{
Debug.LogWarning($"CECNavigateCtrl::LoadConfigAddressable, failed to load '{address}'");
return false;
}
return LoadConfigFromText(ta.text);
string text = DecodeNavigateConfigText(ta.bytes);
if (string.IsNullOrEmpty(text))
{
Debug.LogWarning($"CECNavigateCtrl::LoadConfigAddressable, decoded empty text '{address}'");
return false;
}
return LoadConfigFromText(text);
}
catch (Exception ex)
{
@@ -293,7 +329,8 @@ namespace BrewMonster.Scripts
return false;
}
string text = File.ReadAllText(filePath);
byte[] raw = File.ReadAllBytes(filePath);
string text = DecodeNavigateConfigText(raw);
return LoadConfigFromText(text);
}
catch (Exception)
@@ -318,7 +355,7 @@ namespace BrewMonster.Scripts
}
// Prepare navigation // 准备导航
public void OnPrepareNavigate(int task)
public async void OnPrepareNavigate(int task)
{
m_bForceNavigateState = true;
m_taskID = task;
@@ -329,27 +366,18 @@ namespace BrewMonster.Scripts
INFO naviInfo = new INFO();
if (GetNavigateInfo(task, ref naviInfo))
{
Debug.Log($"CECNavigateCtrl::OnPrepareNavigate, GetNavigateInfo: {task} success");
m_curNavigateInfo = naviInfo;
// Set navigate model file // 设置导航模型文件
CECHostNavigatePlayer player = m_pHost != null ? m_pHost.GetNavigatePlayer() : null;
if (player != null)
{
player.SetNavigateModelFile(m_curNavigateInfo.strModelPath);
player.Init();
}
CECHostNavigatePlayer player = m_pHost.GetNavigatePlayer();
player.SetNavigateModelFile(m_curNavigateInfo.strModelPath);
await player.Init();
}
else
{
// Give up task if no navigation info found // 如果找不到导航信息则放弃任务
if (m_pHost != null && m_pHost.GetTaskInterface() != null)
{
m_pHost.GetTaskInterface().GiveUpTask((uint)m_taskID);
}
m_pHost.GetTaskInterface().GiveUpTask((uint)m_taskID);
}
//TODO: Refine Logic.
//This is work around. It need to create a clone and make it do the animation.
m_pHost.OnNaviageEvent(task,(int)CECNavigateCtrl.NavigateEvent.EM_BEGIN);
}
// Begin navigation // 开始导航
@@ -403,6 +431,7 @@ namespace BrewMonster.Scripts
if (m_pHost != null && m_pHost.GetWorkMan() != null)
{
m_pHost.GetWorkMan().FinishRunningWork(CECHPWork.Host_work_ID.WORK_FORCENAVIGATEMOVE);
CameraController.Instance.UpdateFollowObject(m_pHost.PointCam);
}
// TODO: Implement UI helper
// CECUIHelper::GetGameUIMan()->SetShowAllPanlesFlag(true);
@@ -567,8 +596,9 @@ namespace BrewMonster.Scripts
CECHostNavigatePlayer pClone = m_pHost.GetNavigatePlayer();
if (pClone != null)
{
pClone.SetPos(vCurPos);
pClone.SetPos(new Vector3(vCurPos.x, vCurPos.y, vCurPos.z));
pClone.SetDirAndUp(new A3DVECTOR3(vDir.x, vDir.y, vDir.z), new A3DVECTOR3(vUp.x, vUp.y, vUp.z));
pClone.ResetHookPosition();
if(pNaviCtrl.GetCurrentNavigateInfo().bezierDir)
{
pClone.ChangeModelMoveDirAndUp(vDir, vUp);
@@ -1016,86 +1046,7 @@ namespace BrewMonster.Scripts
public bool GetLoopFlag() { return m_bLoop; }
}
// CECHostNavigatePlayer class - Basic implementation for navigation player // CECHostNavigatePlayer类 - 导航玩家的基本实现
public class CECHostNavigatePlayer
{
private CECNavigateCtrl m_pNavigateCtrl; // Force navigate // 强制导航
private CECHostPlayer m_pHost = null; // Reference to host player // 对宿主玩家的引用
public CECHostNavigatePlayer(CECHostPlayer pHost)
{
// Initialize navigate control // 初始化导航控制
m_pHost = pHost;
m_pNavigateCtrl = new CECNavigateCtrl(pHost);
}
public A3DVECTOR3 GetDir()
{
if (m_pHost != null)
{
// Get direction from host's transform // 从宿主的变换获取方向
Transform hostTransform = m_pHost.transform;
if (hostTransform != null)
{
Vector3 forward = hostTransform.forward;
return new A3DVECTOR3(forward.x, forward.y, forward.z);
}
}
return new A3DVECTOR3(0, 0, 1);
}
public void SetPos(A3DVECTOR3 vPos)
{
if (m_pHost != null)
{
// Actually move the host player // 实际移动宿主玩家
Vector3 newPos = new Vector3(vPos.x, vPos.y, vPos.z);
m_pHost.SetPos(newPos);
}
}
public void ChangeModelMoveDirAndUp(A3DVECTOR3 vDir, A3DVECTOR3 vUp)
{
if (m_pHost != null && m_pHost.transform != null)
{
// Update host's rotation based on direction // 根据方向更新宿主的旋转
Vector3 dir = new Vector3(vDir.x, vDir.y, vDir.z);
Vector3 up = new Vector3(vUp.x, vUp.y, vUp.z);
if (dir.magnitude > 0.01f)
{
Quaternion rotation = Quaternion.LookRotation(dir, up);
m_pHost.transform.rotation = rotation;
}
}
}
public void SetNavigateModelFile(string szFile) { } // Stub
public bool Init() { return true; } // Stub
public CECNavigateCtrl GetNavigateCtrl() { return m_pNavigateCtrl; }
// Handle navigation event // 处理导航事件
public void OnNavigateEvent(int task, int e)
{
if (m_pNavigateCtrl == null)
{
return;
}
if (e == (int)CECNavigateCtrl.NavigateEvent.EM_PREPARE)
{
m_pNavigateCtrl.OnPrepareNavigate(task);
}
else if (e == (int)CECNavigateCtrl.NavigateEvent.EM_BEGIN)
{
m_pNavigateCtrl.OnBeginNavigate();
}
else if (e == (int)CECNavigateCtrl.NavigateEvent.EM_END)
{
m_pNavigateCtrl.OnEndNavigate();
}
}
}
//////////////////////////////////////////////////////////////////////////
//
// CECBezierPoint class - Bezier curve point // 贝塞尔曲线点类
@@ -2,7 +2,7 @@ using System;
using System.Collections.Generic;
using UnityEngine;
namespace BrewMonster.Scripts.Managers
namespace BrewMonster.Scripts
{
/// <summary>
/// C# mirror of C++ CECInventory (EC_Inventory.h / EC_Inventory.cpp).
@@ -12,7 +12,7 @@ using BrewMonster.Scripts.Managers;
using BrewMonster.Scripts;
using CSNetwork.GPDataType;
using System.Runtime.InteropServices;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
/// <summary>
/// Arrow item class (cac loai mui ten)
@@ -62,7 +62,7 @@ using BrewMonster.Scripts;
// ///////////////////////////////////////////////////////////////////////////
#endregion
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
/// <summary>
/// Weapon item class (cac loai vu khi)
@@ -62,7 +62,7 @@ using BrewMonster.Scripts;
// ///////////////////////////////////////////////////////////////////////////
#endregion
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
/// <summary>
/// Armor item class (Mu + Ao + Quan + Giay) / Armor item class (Helmet + Armor + Pants + Boots)
@@ -1,6 +1,6 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrArmorrune : EC_IvtrItem
{
@@ -40,7 +40,7 @@ using BrewMonster.Scripts;
using System.Runtime.InteropServices;
using System;
using CSNetwork.GPDataType;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
/// <summary>
/// Auto HP item class (tu dong hoi mau). This is a part of CEC_IvtrEquipMatter(C++)
@@ -40,7 +40,7 @@ using BrewMonster.Scripts;
using System.Runtime.InteropServices;
using System;
using CSNetwork.GPDataType;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
/// <summary>
/// Auto MP item class (tu dong hoi mana). This is a part of CEC_IvtrEquipMatter(C++)
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrBible : EC_IvtrItem
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrCertificate : EC_IvtrItem
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrCongregate : EC_IvtrItem
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrDamagerune : EC_IvtrItem
{
@@ -37,7 +37,7 @@ using System.Collections.Generic;
using BrewMonster.Network;
using BrewMonster.Scripts.Managers;
using BrewMonster.Scripts;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
/// <summary>
/// Decoration item class (boi + nhan + ) / Decoration item class (various types of decorations)
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrDestroyingEssence : EC_IvtrItem
{
@@ -1,6 +1,6 @@
using BrewMonster;
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrDoubleExp : EC_IvtrItem
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrDyeTicket : EC_IvtrItem
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrDynSkillEquip : EC_IvtrEquip
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrElement : EC_IvtrItem
{
@@ -14,7 +14,7 @@ using System.Text.RegularExpressions;
using System.Reflection;
using BrewMonster.Scripts.Managers;
using BrewMonster.Scripts;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
/// <summary>
/// Equipment item class that handles all equipment-specific functionality
@@ -496,6 +496,7 @@ namespace PerfectWorld.Scripts.Managers
m_strDesc = oldDesc;
return result;
}
public ushort GetStoneMask() { return StoneMask; }
private static object TryFindElementByScanningArraysLocal(object edm, uint id)
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrFacePill : EC_IvtrItem
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrFaceTicket : EC_IvtrItem
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrFactionMaterial : EC_IvtrItem
{
@@ -12,7 +12,7 @@ using BrewMonster.Scripts.Managers;
using BrewMonster.Scripts;
using CSNetwork.GPDataType;
using System.Runtime.InteropServices;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrFashion : EC_IvtrEquip
{
@@ -115,6 +115,7 @@ namespace PerfectWorld.Scripts.Managers
{
return new Color(((color & (0x1f << 10)) >> 7), ((color & (0x1f << 5)) >> 2), ((color & 0x1f) << 3));
}
public ushort GetWordColor() { return m_wColor; }
public string GetSubTypeName()
{
// Try Unicode first (for Vietnamese/wide char names), then fallback to CP936
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrFirework : EC_IvtrItem
{
@@ -12,7 +12,7 @@ using BrewMonster.Scripts.Managers;
using BrewMonster.Scripts;
using CSNetwork.GPDataType;
using System.Runtime.InteropServices;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
/// <summary>
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrForceToken : EC_IvtrItem
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrGeneralCard : EC_IvtrItem
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrGeneralCardDice : EC_IvtrItem
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrGmGenerator : EC_IvtrItem
{
@@ -14,7 +14,7 @@ using CSNetwork.GPDataType;
using System.Runtime.InteropServices;
using BrewMonster.Scripts;
using BrewMonster.Scripts.Skills;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
/// <summary>
/// The goblin item class (cac loai tinh linh).(not completed, need generate class).
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrGoblinEquip : EC_IvtrEquip
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrGoblinExpPill : EC_IvtrItem
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrIncSkillAbility : EC_IvtrItem
{
@@ -7,10 +7,9 @@ using BrewMonster;
using ModelRenderer.Scripts.Common;
using ModelRenderer.Scripts.GameData;
using UnityEngine;
using PerfectWorld.Scripts.Managers;
using BrewMonster.Network;
namespace BrewMonster.Scripts.Managers
namespace BrewMonster.Scripts
{
// NOTE: The original lightweight EC_IvtrItem packet struct has been merged into the
// EC_IvtrItem class below (which mirrors C++ CECIvtrItem). Network-only fields such as
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrLookInfoItem : EC_IvtrItem
{
@@ -4,7 +4,7 @@ using BrewMonster.Scripts;
using ModelRenderer.Scripts.GameData;
using ModelRenderer.Scripts.Common;
using BrewMonster.Network;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrMaterial : EC_IvtrItem
{
@@ -5,7 +5,7 @@ using BrewMonster.Network;
using BrewMonster.Scripts.Managers;
using BrewMonster.Scripts;
using CSNetwork.GPDataType;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
/// <summary>
/// Medicine item class (cac loai thuoc).
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrMoneyConvertible : EC_IvtrItem
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrMonsterSpirit : EC_IvtrItem
{
@@ -12,7 +12,7 @@ using BrewMonster.Scripts.Managers;
using BrewMonster.Scripts;
using CSNetwork.GPDataType;
using System.Runtime.InteropServices;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public struct PETSKILL
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrPetFaceTicket : EC_IvtrItem
{
@@ -13,7 +13,7 @@ using BrewMonster.Scripts;
using CSNetwork.GPDataType;
using System.Runtime.InteropServices;
using BrewMonster.Scripts.Pet;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrPetFood : EC_IvtrItem
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrRecipe : EC_IvtrItem
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrRefineTicket : EC_IvtrItem
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrRevScroll : EC_IvtrItem
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrSharpener : EC_IvtrItem
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrShopToken : EC_IvtrItem
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrSkillMat : EC_IvtrItem
{
@@ -11,7 +11,7 @@ using PerfectWorld.Scripts.Managers;
using BrewMonster.Network;
using BrewMonster.Scripts.Managers;
using BrewMonster.Scripts;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
/// <summary>
/// Skill tome item class(sach ky nang). This is a part of CEC_IvtrScroll(C++)
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrSpeaker : EC_IvtrItem
{
@@ -2,7 +2,7 @@ using BrewMonster;
using BrewMonster.Scripts.Managers;
using ModelRenderer.Scripts.GameData;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrStone : EC_IvtrItem
{
@@ -1,6 +1,6 @@
using BrewMonster;
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrTargetItem : EC_IvtrItem
{
@@ -12,7 +12,7 @@ using BrewMonster.Scripts.Managers;
using BrewMonster.Scripts;
using CSNetwork.GPDataType;
using System.Runtime.InteropServices;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
/// <summary>
/// Task Dice Item (Tui qua random).
@@ -12,7 +12,7 @@ using BrewMonster.Scripts.Managers;
using BrewMonster.Scripts;
using CSNetwork.GPDataType;
using System.Runtime.InteropServices;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrTaskItem : EC_IvtrItem
{
@@ -12,7 +12,7 @@ using BrewMonster.Scripts.Managers;
using BrewMonster.Scripts;
using CSNetwork.GPDataType;
using System.Runtime.InteropServices;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
/// <summary>
/// Task Normal Matter Item.(non interactable quest item). it is a part of IvtrTaskItem(C++)
@@ -1,6 +1,6 @@
using BrewMonster;
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrTossMat : EC_IvtrItem
{
@@ -4,7 +4,7 @@ using BrewMonster.Network;
using BrewMonster.Scripts.Managers;
using BrewMonster.Scripts;
using CSNetwork.GPDataType;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
/// <summary>
/// Town scroll item class (hoi thanh phu). It is a part of EC_IvtrScroll(c++)
@@ -4,7 +4,7 @@ using BrewMonster.Network;
using BrewMonster.Scripts.Managers;
using BrewMonster.Scripts;
using CSNetwork.GPDataType;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
/// <summary>
/// Transmit scroll item(Da dich chuyen). It is a part of EC_IvtrConsume(c++)
@@ -4,7 +4,7 @@ using UnityEngine;
using ModelRenderer.Scripts.GameData;
using BrewMonster;
namespace BrewMonster.Scripts.Managers
namespace BrewMonster.Scripts
{
public enum IndexOfIteminEquipmentInventory : byte
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrUnionscroll : EC_IvtrItem
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrUniversalToken : EC_IvtrItem
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrUnknown : EC_IvtrItem
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrWarTankCallin : EC_IvtrItem
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrWeddingBookCard : EC_IvtrEquip
{
@@ -1,5 +1,5 @@
using BrewMonster.Scripts.Managers;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrWeddingInviteCard : EC_IvtrEquip
{
@@ -12,7 +12,7 @@ using BrewMonster.Scripts.Managers;
using BrewMonster.Scripts;
using CSNetwork.GPDataType;
using System.Runtime.InteropServices;
namespace PerfectWorld.Scripts.Managers
namespace BrewMonster.Scripts
{
public class EC_IvtrWing : EC_IvtrEquip

Some files were not shown because too many files have changed in this diff Show More