Merge branch 'develop' of https://git.pthub.vn/Unity/perfect-world-unity into feature/update-ui
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using BrewMonster;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
@@ -83,6 +84,7 @@ public class Joystick : MonoBehaviour, IPointerDownHandler, IDragHandler, IPoint
|
||||
if ((currentSnapped.x == -1 || currentSnapped.x == 1 || currentSnapped.y == -1 || currentSnapped.y == 1) &&
|
||||
currentSnapped != previousSnappedInput)
|
||||
{
|
||||
BMLogger.LogError($"Joystick snapped to: {currentSnapped}");
|
||||
EventBus.Publish(new JoystickPressEvent());
|
||||
}
|
||||
else if (currentSnapped == Vector2.zero && previousSnappedInput != Vector2.zero) {
|
||||
@@ -207,4 +209,4 @@ public class Joystick : MonoBehaviour, IPointerDownHandler, IDragHandler, IPoint
|
||||
|
||||
public enum AxisOptions { Both, Horizontal, Vertical }
|
||||
public struct JoystickPressEvent { }
|
||||
public struct JoystickRealeaseEvent { }
|
||||
public struct JoystickRealeaseEvent { }
|
||||
|
||||
@@ -38,7 +38,7 @@ RectTransform:
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 161.25, y: 0}
|
||||
m_SizeDelta: {x: 322.5, y: 300}
|
||||
m_SizeDelta: {x: 322.5, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 1}
|
||||
--- !u!222 &9154858122360570458
|
||||
CanvasRenderer:
|
||||
@@ -364,7 +364,6 @@ MonoBehaviour:
|
||||
m_EditorClassIdentifier:
|
||||
skillNameText: {fileID: 0}
|
||||
imageProgress: {fileID: 0}
|
||||
dialogType: 1
|
||||
m_TargetName:
|
||||
m_TargetPos: {x: 0, y: 0, z: 0}
|
||||
m_Targets: []
|
||||
|
||||
@@ -1017,7 +1017,7 @@ MonoBehaviour:
|
||||
m_PressedTrigger: Pressed
|
||||
m_SelectedTrigger: Selected
|
||||
m_DisabledTrigger: Disabled
|
||||
m_Interactable: 0
|
||||
m_Interactable: 1
|
||||
m_TargetGraphic: {fileID: 813625907549247604}
|
||||
m_OnClick:
|
||||
m_PersistentCalls:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6016467082edf7a46ab650b0c04c82cd
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -14,7 +14,7 @@ namespace BrewMonster.Scripts.ChatUI
|
||||
public string prefix;
|
||||
}
|
||||
|
||||
[CreateAssetMenu(fileName = "ChatSystemSO", menuName = "Scriptable Objects/ChatSystemSO")]
|
||||
[CreateAssetMenu(fileName = "ChatSystemSO", menuName = "Scriptable Objects/Chat/ChatSystemSO")]
|
||||
public class ChatSystemSO : ScriptableObject
|
||||
{
|
||||
[Header("Button States")]
|
||||
|
||||
@@ -0,0 +1,561 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace BrewMonster.Scripts.ChatUI
|
||||
{
|
||||
[System.Serializable]
|
||||
public struct ServerErrorMapping
|
||||
{
|
||||
public int id;
|
||||
public string message;
|
||||
}
|
||||
|
||||
[CreateAssetMenu(fileName = "ServerErrorSO", menuName = "Scriptable Objects/Chat/ServerErrorSO")]
|
||||
public class ServerErrorSO : ScriptableObject
|
||||
{
|
||||
public List<ServerErrorMapping> errors = new List<ServerErrorMapping>();
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
errors = new List<ServerErrorMapping>
|
||||
{
|
||||
new ServerErrorMapping { id = 0, message = "Thành công không mắc lỗi" },
|
||||
new ServerErrorMapping { id = 1, message = "Sai mục tiêu" },
|
||||
new ServerErrorMapping { id = 2, message = "Khoảng cách đến mục tiêu quá xa" },
|
||||
new ServerErrorMapping { id = 3, message = "Sai: lệnh không chính xác" },
|
||||
new ServerErrorMapping { id = 4, message = "Trong trạng thái tử vong không thể nhận mệnh lệnh này" },
|
||||
new ServerErrorMapping { id = 5, message = "Đồ đặc biệt không nằm trong túi đồ" },
|
||||
new ServerErrorMapping { id = 6, message = "Không thể nhặt vật phẩm/Ngân lượng" },
|
||||
new ServerErrorMapping { id = 7, message = "Túi đồ đã đầy" },
|
||||
new ServerErrorMapping { id = 8, message = "Món đồ này không thể trang bị" },
|
||||
new ServerErrorMapping { id = 9, message = "Hiện tại không thể tấn công" },
|
||||
new ServerErrorMapping { id = 10, message = "Không thể đưa ra lời mời" },
|
||||
new ServerErrorMapping { id = 11, message = "Không thể gia nhập đội ngũ" },
|
||||
new ServerErrorMapping { id = 12, message = "Vui lòng mời lại sau 30 giây nữa" },
|
||||
new ServerErrorMapping { id = 13, message = "Đề nghị gia nhập đội ngũ đã quá hạn" },
|
||||
new ServerErrorMapping { id = 14, message = "Không thể phục vụ" },
|
||||
new ServerErrorMapping { id = 15, message = "Không thể thực hiện yêu cầu này!" },
|
||||
new ServerErrorMapping { id = 16, message = "Không đủ Ngân lượng" },
|
||||
new ServerErrorMapping { id = 17, message = "Hiện tại chưa thể thoát ra!" },
|
||||
new ServerErrorMapping { id = 18, message = "Không thể sử dụng món đồ" },
|
||||
new ServerErrorMapping { id = 19, message = "Không thể tiến hành nhiệm vụ" },
|
||||
new ServerErrorMapping { id = 20, message = "Không thể sử dụng kỹ năng" },
|
||||
new ServerErrorMapping { id = 21, message = "Không thể khảm đồ" },
|
||||
new ServerErrorMapping { id = 22, message = "Không thể học kỹ năng này" },
|
||||
new ServerErrorMapping { id = 23, message = "Không thể trị liệu khi đang ở trạng thái chiến đấu " },
|
||||
new ServerErrorMapping { id = 24, message = "Không thể bổ sung thời gian phi hành" },
|
||||
new ServerErrorMapping { id = 25, message = "Không đủ nguyên liệu" },
|
||||
new ServerErrorMapping { id = 26, message = "Không thể chế tạo" },
|
||||
new ServerErrorMapping { id = 27, message = "Không thể chia tách" },
|
||||
new ServerErrorMapping { id = 28, message = "Hiện tại không thể ngồi xuống" },
|
||||
new ServerErrorMapping { id = 29, message = "Hiện tại không thể đổi trang bị" },
|
||||
new ServerErrorMapping { id = 30, message = "Đồ đang được sử dụng" },
|
||||
new ServerErrorMapping { id = 31, message = "Công cụ khai thác khoáng bị lỗi" },
|
||||
new ServerErrorMapping { id = 32, message = "Không thể khai thông mục tiêu" },
|
||||
new ServerErrorMapping { id = 33, message = "Các thao tác khác đang được tiến hành" },
|
||||
new ServerErrorMapping { id = 34, message = "Trong mật khẩu có chứa những ký tự không hợp lệ" },
|
||||
new ServerErrorMapping { id = 35, message = "Nhập sai mật khẩu rồi, thử lại xem nào" },
|
||||
new ServerErrorMapping { id = 36, message = "Chưa mở khóa thì làm sao mà vào kho được chứ?" },
|
||||
new ServerErrorMapping { id = 37, message = "Ngân lượng trong kho còn quá ít" },
|
||||
new ServerErrorMapping { id = 38, message = "Đề nghị gia nhập đội ngũ đã bị từ chối" },
|
||||
new ServerErrorMapping { id = 39, message = "Động tác ủng hộ bị từ chối" },
|
||||
new ServerErrorMapping { id = 40, message = "Kho trang bị đã khóa, không thể tiến hành thao tác này" },
|
||||
new ServerErrorMapping { id = 41, message = "Không thể mở cửa hàng cá nhân" },
|
||||
new ServerErrorMapping { id = 42, message = "Đồ bị lỗi" },
|
||||
new ServerErrorMapping { id = 43, message = "Đang ở trạng thái tránh né" },
|
||||
new ServerErrorMapping { id = 44, message = "Không thể vứt đồ" },
|
||||
new ServerErrorMapping { id = 45, message = "Quyền không hợp pháp" },
|
||||
new ServerErrorMapping { id = 46, message = "Trong giang hồ không tồn tại nhân vật này" },
|
||||
new ServerErrorMapping { id = 47, message = "Không thể bỏ trạng thái PVP" },
|
||||
new ServerErrorMapping { id = 48, message = "Không thể xóa bỏ kỹ năng chỉ định" },
|
||||
new ServerErrorMapping { id = 49, message = "Không thể tiến hành mệnh lệnh này trong trạng thái hôn mê" },
|
||||
new ServerErrorMapping { id = 50, message = "Không thể tiến hành thao tác này trong trạng thái phong ấn" },
|
||||
new ServerErrorMapping { id = 51, message = "Chưa đủ cấp độ để tiến hành thao tác này" },
|
||||
new ServerErrorMapping { id = 52, message = "Không thể vào phụ bản" },
|
||||
new ServerErrorMapping { id = 53, message = "Kỹ năng đang trong thời gian chờ" },
|
||||
new ServerErrorMapping { id = 54, message = "Đồ đang trong thời gian chờ" },
|
||||
new ServerErrorMapping { id = 55, message = "Hiện tại không thể bay được" },
|
||||
new ServerErrorMapping { id = 56, message = "Vào lạ phụ bản phải chờ tối thiểu 5 phút" },
|
||||
new ServerErrorMapping { id = 57, message = "Túi đồ đang bị khóa" },
|
||||
new ServerErrorMapping { id = 58, message = "Số người chơi trong phụ bản đã đạt giới hạn" },
|
||||
new ServerErrorMapping { id = 59, message = "Số phụ bản đã đạt giới hạn" },
|
||||
new ServerErrorMapping { id = 60, message = "Vùng đất của bang đang bị đóng cửa" },
|
||||
new ServerErrorMapping { id = 61, message = "Đất của bang chỉ mở cửa cho bang chúng" },
|
||||
new ServerErrorMapping { id = 62, message = "Không thể di chuyển đến phụ bản cùng loại" },
|
||||
new ServerErrorMapping { id = 63, message = "Thời gian nghỉ ngơi không đủ" },
|
||||
new ServerErrorMapping { id = 64, message = "Không thể lặp lại thao tác quyết đấu " },
|
||||
new ServerErrorMapping { id = 65, message = "Không thể thiết lập trạng thái quyết đấu, thử lại xem sao?" },
|
||||
new ServerErrorMapping { id = 66, message = "Không thể thực hiện thao tác này trong trạng thái chiến đấu" },
|
||||
new ServerErrorMapping { id = 67, message = "Không phù hợp điều kiện" },
|
||||
new ServerErrorMapping { id = 68, message = "Không thể thực hiện thao tác tương hỗ" },
|
||||
new ServerErrorMapping { id = 69, message = "Không thể thực hiện thao tác tương hỗ" },
|
||||
new ServerErrorMapping { id = 70, message = "Hiện tại không thể thực hiện thao tác này" },
|
||||
new ServerErrorMapping { id = 71, message = "Thú nuôi đang được gọi ra" },
|
||||
new ServerErrorMapping { id = 72, message = "Thú không ở trong Túi Thú nuôi" },
|
||||
new ServerErrorMapping { id = 73, message = "Thú nuôi chưa được thả ra" },
|
||||
new ServerErrorMapping { id = 74, message = "Thú nuôi của bạn không ăn món này" },
|
||||
new ServerErrorMapping { id = 75, message = "Chiến trường đang mở, mời các hạ quay lại sau!" },
|
||||
new ServerErrorMapping { id = 76, message = "Không thể ấp trứng thú nuôi" },
|
||||
new ServerErrorMapping { id = 77, message = "Thú nuôi không thể trở về trứng" },
|
||||
new ServerErrorMapping { id = 78, message = "Bang phái của bạn hiện không thể tham gia chiến trường" },
|
||||
new ServerErrorMapping { id = 79, message = "Không thể tra cứu thông tin về đối thủ người chơi" },
|
||||
new ServerErrorMapping { id = 80, message = "NPC này đang bận" },
|
||||
new ServerErrorMapping { id = 81, message = "Không thể cưỡi ngựa ở đây" },
|
||||
new ServerErrorMapping { id = 82, message = "Không thể tẩy điểm" },
|
||||
new ServerErrorMapping { id = 83, message = "Trận đánh trên chiến trường đã kết thúc, không thể vào được" },
|
||||
new ServerErrorMapping { id = 84, message = "Không thể quyết đấu ở đây" },
|
||||
new ServerErrorMapping { id = 85, message = "Không thể gọi Thú nuôi ra ở đây" },
|
||||
new ServerErrorMapping { id = 86, message = "Không thể điều khiển nhiều xe công thành cùng lúc" },
|
||||
new ServerErrorMapping { id = 87, message = "Lệnh triệu hồi thất bại: hãy hồi sinh thú nuôi trước khi triệu hồi" },
|
||||
new ServerErrorMapping { id = 88, message = "Không thể hồi sinh thú nuôi, thú nuôi vẫn chưa chết" },
|
||||
new ServerErrorMapping { id = 89, message = "Không thể tiến hành thao tác tương hỗ ở địa điểm này" },
|
||||
new ServerErrorMapping { id = 90, message = "Lớp nhân vật không phù hợp" },
|
||||
new ServerErrorMapping { id = 91, message = "Lá bùa cần dùng đang phát huy tác dụng, không thể sử dụng lại" },
|
||||
new ServerErrorMapping { id = 92, message = "Thao tác thất bại: không thể tinh luyện" },
|
||||
new ServerErrorMapping { id = 93, message = "Kỹ năng thú nuôi đang trong thời gian chờ" },
|
||||
new ServerErrorMapping { id = 94, message = "Trong túi càn khôn không có món đồ này" },
|
||||
new ServerErrorMapping { id = 95, message = "Lỗi: Đồ của bạn đang hỏng dần" },
|
||||
new ServerErrorMapping { id = 96, message = "Loại trang bị này không thể tháo ra" },
|
||||
new ServerErrorMapping { id = 97, message = "Không thể sử dụng đồ" },
|
||||
new ServerErrorMapping { id = 98, message = "Không thể nhuộm màu" },
|
||||
new ServerErrorMapping { id = 99, message = "Không thể nhuộm loại trang phục này" },
|
||||
new ServerErrorMapping { id = 100, message = "Không đủ thuốc nhuộm" },
|
||||
new ServerErrorMapping { id = 101, message = "Không thể tiến hành di chuyển Càn Khôn" },
|
||||
new ServerErrorMapping { id = 102, message = "Thao tác thất bại: cấp độ tinh luyện của trang bị ban đầu quá thấp" },
|
||||
new ServerErrorMapping { id = 103, message = "Thao tác thất bại: Không thể tinh luyện trang bị mục tiêu!" },
|
||||
new ServerErrorMapping { id = 104, message = "Thao tác thất bại: trang bị mục tiêu cũng phải cùng loại trang bị Thiên Nhân Hợp Nhất!" },
|
||||
new ServerErrorMapping { id = 105, message = "Thao tác thất bại: không đủ Càn Khôn Thạch!" },
|
||||
new ServerErrorMapping { id = 106, message = "Thất bại: Không thể tạo lỗ" },
|
||||
new ServerErrorMapping { id = 107, message = "Tạo lỗ thành công!" },
|
||||
new ServerErrorMapping { id = 108, message = "Khóa an toàn, không thể tiến hành thao tác!" },
|
||||
new ServerErrorMapping { id = 109, message = "Tăng tỉ lệ thất bại thuộc tính Tiểu Tinh Linh" },
|
||||
new ServerErrorMapping { id = 110, message = "Tăng tỉ lệ thất bại điểm thiên phú Tiểu Tinh Linh" },
|
||||
new ServerErrorMapping { id = 111, message = "Thất bại thêm điểm kinh nghiệm" },
|
||||
new ServerErrorMapping { id = 112, message = "Không thể trang bị vật phẩm này cho Tiểu Tinh Linh" },
|
||||
new ServerErrorMapping { id = 113, message = "Chỉnh sửa trạng thái an toàn cho Tiểu Tinh linh thất bại" },
|
||||
new ServerErrorMapping { id = 114, message = "Không sử dụng được kỹ năng Tiểu Tinh Linh" },
|
||||
new ServerErrorMapping { id = 115, message = "Thao tác tẩy thuộc tính thất bại" },
|
||||
new ServerErrorMapping { id = 116, message = "Thao tác tẩy thiên phú thất bại" },
|
||||
new ServerErrorMapping { id = 117, message = "Kỹ năng học tập của Tiểu Tinh Linh thất bại" },
|
||||
new ServerErrorMapping { id = 118, message = "Kỹ năng di vong thất bại" },
|
||||
new ServerErrorMapping { id = 119, message = "Tinh luyện Tiểu Tinh Linh thất bại" },
|
||||
new ServerErrorMapping { id = 120, message = "Di chuyển cấp tinh luyện Tiểu Tinh Linh thất bại" },
|
||||
new ServerErrorMapping { id = 121, message = "Hủy điểm thất bại" },
|
||||
new ServerErrorMapping { id = 122, message = "Không thể hủy trang bị Tiểu Tinh Linh" },
|
||||
new ServerErrorMapping { id = 123, message = "Tiểu Tinh Linh không thể hủy và giao dịch" },
|
||||
new ServerErrorMapping { id = 124, message = "Tiểu Tinh Linh không thể hủy Kinh nghiệm về 0" },
|
||||
new ServerErrorMapping { id = 125, message = "Trang bị không thể hủy Tiểu Tinh Linh" },
|
||||
new ServerErrorMapping { id = 126, message = "Tiểu Tinh Linh Không đủ năng lượng" },
|
||||
new ServerErrorMapping { id = 127, message = "Tiểu Tinh Linh Không đủ Thể lực" },
|
||||
new ServerErrorMapping { id = 128, message = "Kỹ năng không thể phóng thích Tiểu Tinh Linh" },
|
||||
new ServerErrorMapping { id = 129, message = "Tiểu Tinh Linh không thể kích hoạt" },
|
||||
new ServerErrorMapping { id = 130, message = "Tiểu Tinh Linh không thể phòng ngự khi chiến đấu" },
|
||||
new ServerErrorMapping { id = 131, message = "Không thể phóng thích kỹ năng Tiểu Tinh Linh" },
|
||||
new ServerErrorMapping { id = 132, message = "Thao tác của Tiểu Tinh Linh bị đông cứng" },
|
||||
new ServerErrorMapping { id = 133, message = "Bên bán không thể nhặt Ngân lượng hoặc Ngân phiếu, giao dịch thất bại." },
|
||||
new ServerErrorMapping { id = 134, message = "Bên bán không có đủ Ngân lượng và Ngân phiếu, giao dịch thất bại." },
|
||||
new ServerErrorMapping { id = 135, message = "Không thể nhặt Ngân lượng và Ngân phiếu, giao dịch thất bại." },
|
||||
new ServerErrorMapping { id = 136, message = "Không thể trang bị thời trang trong túi đồ" },
|
||||
new ServerErrorMapping { id = 137, message = "Mật mã an toàn chưa được xác nhận" },
|
||||
new ServerErrorMapping { id = 138, message = "Đang ẩn thân, không thể thực hiện" },
|
||||
new ServerErrorMapping { id = 139, message = "Tại đây không thể mở/đóng Tụ Linh" },
|
||||
new ServerErrorMapping { id = 140, message = "Không tiến hành Hôn lễ" },
|
||||
new ServerErrorMapping { id = 141, message = "Không thể Đính hôn" },
|
||||
new ServerErrorMapping { id = 142, message = "Không thể hủy Đính hôn" },
|
||||
new ServerErrorMapping { id = 143, message = "Không thể tiến hành thao tác" },
|
||||
new ServerErrorMapping { id = 144, message = "Không thể thao tác Cơ sở Bang phái" },
|
||||
new ServerErrorMapping { id = 145, message = "Thao tác Cơ sở Bang phái thất bại" },
|
||||
new ServerErrorMapping { id = 146, message = "Không đủ điểm Cống hiến Bang phái" },
|
||||
new ServerErrorMapping { id = 147, message = "Cơ sở Bang phái từ chối thêm người" },
|
||||
new ServerErrorMapping { id = 148, message = "Vợ/chồng bạn không có mặt" },
|
||||
new ServerErrorMapping { id = 149, message = "Nhuộm màu thú cưỡi thất bại" },
|
||||
new ServerErrorMapping { id = 150, message = "Vị trí hiện tại không thể dùng Tập Kết Lệnh" },
|
||||
new ServerErrorMapping { id = 151, message = "LINK - ERR_TOBECONTINUE" },
|
||||
new ServerErrorMapping { id = 152, message = "LINK - Trong giang hồ không tồn tại người chơi này " },
|
||||
new ServerErrorMapping { id = 153, message = "LINK - Tài khoản hoặc mật khẩu không chính xác" },
|
||||
new ServerErrorMapping { id = 154, message = "LINK - Quá giờ" },
|
||||
new ServerErrorMapping { id = 155, message = "LINK - Sai tham số" },
|
||||
new ServerErrorMapping { id = 156, message = "LINK- Dữ liệu về bằng hữu không đồng bộ khi sao lưu " },
|
||||
new ServerErrorMapping { id = 157, message = "Không thể dùng tên này" },
|
||||
new ServerErrorMapping { id = 158, message = "Giá bán không phù hợp" },
|
||||
new ServerErrorMapping { id = 159, message = "Không thể tiến hóa thú cưng" },
|
||||
new ServerErrorMapping { id = 160, message = "Loại thú cưng không đúng" },
|
||||
new ServerErrorMapping { id = 161, message = "Vật phẩm này hiện đang bị cấm mua bán" },
|
||||
new ServerErrorMapping { id = 162, message = "Vật phẩm này hiện cấm bán" },
|
||||
new ServerErrorMapping { id = 163, message = "Không thể liên server trong trạng thái hiện tại." },
|
||||
new ServerErrorMapping { id = 164, message = "Không đạt điều kiện tu chân." },
|
||||
new ServerErrorMapping { id = 165, message = "Độ dài tên mới của nhân vật không phù hợp." },
|
||||
new ServerErrorMapping { id = 166, message = "Không có trang bị hoặc lỗ trang bị thích hợp." },
|
||||
new ServerErrorMapping { id = 167, message = "Nguyên liệu và phương thuốc không phù hợp" },
|
||||
new ServerErrorMapping { id = 168, message = "Hồn thạch cũ không phù hợp" },
|
||||
new ServerErrorMapping { id = 169, message = "Hồn thạch mới không phù hợp" },
|
||||
new ServerErrorMapping { id = 170, message = "Chuyển đổi Hồn thạch bị lỗi" },
|
||||
new ServerErrorMapping { id = 171, message = "Chưa mở chức năng nhận đồ tặng." },
|
||||
new ServerErrorMapping { id = 172, message = "Chưa đạt điều kiện tấn công linh mạch." },
|
||||
new ServerErrorMapping { id = 173, message = "Không thể tiến hành bồi dưỡng hoặc hủy bỏ tính cách." },
|
||||
new ServerErrorMapping { id = 174, message = "Không thể chuyển đổi tuyến nhánh" },
|
||||
new ServerErrorMapping { id = 175, message = "Tuyến nhánh không tồn tại" },
|
||||
new ServerErrorMapping { id = 176, message = "Tuyến nhánh quá đông" },
|
||||
new ServerErrorMapping { id = 177, message = "Không đạt điều kiện chuyển sinh" },
|
||||
new ServerErrorMapping { id = 178, message = "Không thể viết lại Truyền Thế Chi Thư" },
|
||||
new ServerErrorMapping { id = 179, message = "Không thể đánh thức Thư Ma" },
|
||||
new ServerErrorMapping { id = 180, message = "Không phải chủ sở hữu, không thể tiến hành thu thập" },
|
||||
new ServerErrorMapping { id = 181, message = "Không thể hồi sinh Chiến Linh" },
|
||||
new ServerErrorMapping { id = 182, message = "Không thể tăng kinh nghiệm cho Chiến Linh" },
|
||||
new ServerErrorMapping { id = 183, message = "Không thể trang bị vật phẩm trong túi đồ" },
|
||||
new ServerErrorMapping { id = 184, message = "Đã đạt mức hấp thu Nguyên Hồn" },
|
||||
new ServerErrorMapping { id = 185, message = "Nguyên Hồn đã đạt mức tối đa, không thể sử dụng" },
|
||||
new ServerErrorMapping { id = 186, message = "Không thể sử dụng Nguyên hồn, cần nâng Lịch sử lên cấp tối đa để phá vỡ." },
|
||||
new ServerErrorMapping { id = 187, message = "Thu thập đang bị đóng băng" },
|
||||
new ServerErrorMapping { id = 188, message = "Vật phẩm này không thể cường hóa." },
|
||||
new ServerErrorMapping { id = 189, message = "LINK - Số người đăng nhập vào máy chủ đã đạt giới hạn" },
|
||||
new ServerErrorMapping { id = 190, message = "Di chuyển thi pháp xung đột" },
|
||||
new ServerErrorMapping { id = 191, message = "Di chuyển thi pháp xung đột" },
|
||||
new ServerErrorMapping { id = 192, message = "Di chuyển thi pháp xung đột" },
|
||||
new ServerErrorMapping { id = 193, message = "LINK - ERR_NOTFOUND" },
|
||||
new ServerErrorMapping { id = 194, message = "Hiện không thể thay đổi Giới tính chỉ định." },
|
||||
new ServerErrorMapping { id = 195, message = "Không thể thay đổi thành Giới tính chỉ định" },
|
||||
new ServerErrorMapping { id = 196, message = "Lớp nhân vật hiện tại không thể thay đổi Giới tính." },
|
||||
new ServerErrorMapping { id = 197, message = "Không thể thay đổi giới tính khi có vợ/chồng." },
|
||||
new ServerErrorMapping { id = 198, message = "Hãy cở bỏ toàn bộ thời trang trước khi thay đổi giới tính." },
|
||||
new ServerErrorMapping { id = 199, message = "Hãy hủy bỏ toàn bộ hệ thống tình duyên trước khi thay đổi giới tính." },
|
||||
new ServerErrorMapping { id = 200, message = "Các hạ đang mang nhiệm vụ liên quan giới tính, hãy hoàn thành trước khi thay đổi giới tính." },
|
||||
new ServerErrorMapping { id = 201, message = "Thao tác thất bại: không thể đục lỗ." },
|
||||
new ServerErrorMapping { id = 202, message = "Tham số thao tác phi pháp" },
|
||||
new ServerErrorMapping { id = 203, message = "Không thể nuốt vật phẩm này." },
|
||||
new ServerErrorMapping { id = 204, message = "Đã đạt cấp độ tối đa của Đơn Nhân Phụ Bản." },
|
||||
new ServerErrorMapping { id = 205, message = "Không thể tiến nhập Đơn Nhân Phụ Bản." },
|
||||
new ServerErrorMapping { id = 206, message = "Đơn Nhân Phụ Bản không thể phát thưởng." },
|
||||
new ServerErrorMapping { id = 207, message = "Không thể đổi điểm tích lũy." },
|
||||
new ServerErrorMapping { id = 208, message = "Điểm tích lũy không đủ." },
|
||||
new ServerErrorMapping { id = 209, message = "Thao tác thay đổi điểm tích lũy hiện đang bị đóng băng." },
|
||||
new ServerErrorMapping { id = 210, message = "Thao tác đang bị đóng băng" },
|
||||
new ServerErrorMapping { id = 211, message = "Không có trong chiến trường liên server." },
|
||||
new ServerErrorMapping { id = 212, message = "Không có thông tin bang phái liên server." },
|
||||
new ServerErrorMapping { id = 213, message = "Điểm di chuyển hiện tại không thuộc về bổn bang." },
|
||||
new ServerErrorMapping { id = 214, message = "Báo danh cấp C không đủ 3 khu vực." },
|
||||
new ServerErrorMapping { id = 215, message = "Báo danh cấp A hoặc cấp B, không có lãnh địa cấp thấp nhất." },
|
||||
new ServerErrorMapping { id = 216, message = "Không thể đào khoáng." },
|
||||
new ServerErrorMapping { id = 217, message = "Thành viên bổn bang đang thu thập." },
|
||||
new ServerErrorMapping { id = 218, message = "Tài nguyên đã thuộc về bổn bang." },
|
||||
new ServerErrorMapping { id = 219, message = "Tháp tài nguyên đã bị tổn hại." },
|
||||
new ServerErrorMapping { id = 220, message = "Cấp độ Cảnh giới không đủ." },
|
||||
new ServerErrorMapping { id = 221, message = "Hạn chế số người hoạt động liên server." },
|
||||
new ServerErrorMapping { id = 222, message = "Gói trạng thái Đơn Nhân Phụ Bản đã đạt mức tối đa." },
|
||||
new ServerErrorMapping { id = 223, message = "Mỗi nhân vật chỉ được vào 1 chiến trường." },
|
||||
new ServerErrorMapping { id = 224, message = "Nhân vật vào chiến trường quá đông." },
|
||||
new ServerErrorMapping { id = 225, message = "Chiến trường chưa mở." },
|
||||
new ServerErrorMapping { id = 226, message = "Chưa đủ cấp độ VIP cần thiết." },
|
||||
new ServerErrorMapping { id = 227, message = "Bản đồ này không hỗ trợ định vị di chuyển." },
|
||||
new ServerErrorMapping { id = 228, message = "Không có điểm di chuyển này." },
|
||||
new ServerErrorMapping { id = 229, message = "Không đủ năng lượng định vị di chuyển." },
|
||||
new ServerErrorMapping { id = 230, message = "Đã đạt số lần hạn chế." },
|
||||
new ServerErrorMapping { id = 231, message = "Đã đủ số lượng định vị điểm di chuyển." },
|
||||
new ServerErrorMapping { id = 232, message = "Năng lượng định vị di chuyển đã đạt mức tối đa." },
|
||||
new ServerErrorMapping { id = 237, message = "Không thể vào gia viên" },
|
||||
new ServerErrorMapping { id = 238, message = "Thao tác này chỉ thực hiện trong Gia Viên." },
|
||||
new ServerErrorMapping { id = 239, message = "Thanh Khiết không đủ" },
|
||||
new ServerErrorMapping { id = 240, message = "Các hạ vẫn chưa có vật phẩm Gia Viên này." },
|
||||
new ServerErrorMapping { id = 241, message = "Có tin tức Đại Công không thể đổi trang bị có Phồn Vinh thấp." },
|
||||
new ServerErrorMapping { id = 242, message = "Thiếu Bản Vẽ Gia Viên chỉ định." },
|
||||
new ServerErrorMapping { id = 243, message = "Không đủ Gia Viên Tinh Lực" },
|
||||
new ServerErrorMapping { id = 244, message = "Loại Gia Viên Công Phường không đúng." },
|
||||
new ServerErrorMapping { id = 245, message = "Cấp Chuyên Tinh quá thấp." },
|
||||
new ServerErrorMapping { id = 246, message = "Không đủ vật phẩm cần dùng chế tạo Gia Viên." },
|
||||
new ServerErrorMapping { id = 247, message = "Không đủ nguyên liệu cần dùng." },
|
||||
new ServerErrorMapping { id = 248, message = "Cấp Gia Viên quá thấp." },
|
||||
new ServerErrorMapping { id = 249, message = "Cấp Kì Hóa Tập quá thấp." },
|
||||
new ServerErrorMapping { id = 250, message = "Không ở Gia Viên của bản thân thì không thể thao tác." },
|
||||
new ServerErrorMapping { id = 251, message = "Loại dịch vụ không đúng." },
|
||||
new ServerErrorMapping { id = 252, message = "Đã đạt cấp Công Phường tối đa." },
|
||||
new ServerErrorMapping { id = 253, message = "Cấp 1=>2 bắt buộc chọn Chuyên Tinh." },
|
||||
new ServerErrorMapping { id = 254, message = "Loại nguyên liệu không đúng." },
|
||||
new ServerErrorMapping { id = 255, message = "Loại nguyên liệu là Giáng Ngọc." },
|
||||
new ServerErrorMapping { id = 256, message = "Loại nguyên liệu không phải Giáng Ngọc." },
|
||||
new ServerErrorMapping { id = 257, message = "Loại xưởng nguyên liệu không đúng." },
|
||||
new ServerErrorMapping { id = 258, message = "Cấp độ Chỉ Huyền không phù hợp." },
|
||||
new ServerErrorMapping { id = 259, message = "Không đủ Giáng Ngọc" },
|
||||
new ServerErrorMapping { id = 260, message = "Vượt mức tối đa" },
|
||||
new ServerErrorMapping { id = 261, message = "Xưởng nguyên liệu quá bận" },
|
||||
new ServerErrorMapping { id = 262, message = "Đang chế tạo, không thể thăng cấp thao tác." },
|
||||
new ServerErrorMapping { id = 263, message = "Không đủ điều kiện thăng cấp xưởng nguyên liệu." },
|
||||
new ServerErrorMapping { id = 264, message = "Cấp Gia Viên không đúng." },
|
||||
new ServerErrorMapping { id = 265, message = "Lượng tồn nguyên liệu vượt mức tối đa." },
|
||||
new ServerErrorMapping { id = 266, message = "Giáng Ngọc tồn quá nhiều" },
|
||||
new ServerErrorMapping { id = 267, message = "Thiếu vật phẩm cần dùng chế tạo Giáng Ngọc." },
|
||||
new ServerErrorMapping { id = 268, message = "Không đủ vật phẩm cần dùng chế tạo Giáng Ngọc." },
|
||||
new ServerErrorMapping { id = 269, message = "Không đủ Giáng Ngọc dùng trong chế tạo nguyên liệu." },
|
||||
new ServerErrorMapping { id = 270, message = "Thông tin xưởng nguyên liệu không đúng." },
|
||||
new ServerErrorMapping { id = 272, message = "Bản mẫu không tồn tại hoặc số liệu không đúng." },
|
||||
new ServerErrorMapping { id = 273, message = "Không đủ EXP Gia Viên, không thể thăng cấp." },
|
||||
new ServerErrorMapping { id = 274, message = "Lịch sử nhân vật không đủ, không thể thăng cấp GV." },
|
||||
new ServerErrorMapping { id = 275, message = "Số lần chuyển sinh nhân vật không phù hợp, không thể nâng cấp GV." },
|
||||
new ServerErrorMapping { id = 276, message = "Cấp độ cảnh giới nhân vật không phù hợp, không thể nâng cấp GV." },
|
||||
new ServerErrorMapping { id = 277, message = "Đường dẫn giải tỏa thổ địa không đúng." },
|
||||
new ServerErrorMapping { id = 278, message = "Khu đất này đã bị giải tỏa." },
|
||||
new ServerErrorMapping { id = 279, message = "Thông tin khu đất Gia Viên không đúng." },
|
||||
new ServerErrorMapping { id = 280, message = "Bạn đã xác định bảo mật điện thoại, xin đăng nhập sau khi mở khóa điện 10-5885-8566." },
|
||||
new ServerErrorMapping { id = 281, message = "Phải kích hoạt mới vào được máy chủ này, tài khoản này chưa kích hoạt." },
|
||||
new ServerErrorMapping { id = 282, message = "Tài khoản chưa được kích hoạt không thể đăng nhập vào game." },
|
||||
new ServerErrorMapping { id = 283, message = "Để ưu hóa cụm máy chủ, vì tài khoản này không đăng nhập đã lâu nên đã bị khóa, hãy liên hệ với bộ phận chăm sóc khách hàng." },
|
||||
new ServerErrorMapping { id = 284, message = "Tần suất đăng nhập quá dày, chờ trong giây lát rồi đăng nhập lại..." },
|
||||
new ServerErrorMapping { id = 285, message = "Số lần nhận lại nhiệm vụ Gia Viên đã vượt mức tối đa." },
|
||||
new ServerErrorMapping { id = 286, message = "Số lần nhận nhiệm vụ Gia Viên đã vượt mức tối đa." },
|
||||
new ServerErrorMapping { id = 287, message = "Thanh Khiết không thỏa mãn sẽ không thể biến đổi tài sản." },
|
||||
new ServerErrorMapping { id = 288, message = "Không đủ quyền hạn, không thể vào Gia Viên." },
|
||||
new ServerErrorMapping { id = 290, message = "Kho chứa xưởng nguyên liệu không đủ." },
|
||||
new ServerErrorMapping { id = 291, message = "Hiện không ở trong khu vực an toàn, không thể vào Gia Viên." },
|
||||
new ServerErrorMapping { id = 292, message = "Thanh Khiết đã đủ." },
|
||||
new ServerErrorMapping { id = 293, message = "Thiếu đạo cụ để thiết lập lại Chuyên Tinh." },
|
||||
new ServerErrorMapping { id = 294, message = "Cấp độ quá thấp, không thể vào Gia Viên." },
|
||||
new ServerErrorMapping { id = 295, message = "Cấp tu chân quá thấp, không thể vào Gia Viên." },
|
||||
new ServerErrorMapping { id = 296, message = "Danh vọng quá thấp, không thể vào Gia Viên." },
|
||||
new ServerErrorMapping { id = 297, message = "Tiền trong túi đã đầy tràn." },
|
||||
new ServerErrorMapping { id = 298, message = "Không tìm thấy Gia Viên." },
|
||||
new ServerErrorMapping { id = 299, message = "Không tìm thấy vật phẩm Công Phường sau khi thăng cấp hoặc thiết lập lại Chuyên Tinh." },
|
||||
new ServerErrorMapping { id = 300, message = "Thiếu vật phẩm, không thể điểm tán." },
|
||||
new ServerErrorMapping { id = 301, message = "Không thể điểm tán cho Gia Viên của bản thân." },
|
||||
new ServerErrorMapping { id = 302, message = "ID của người điểm tán Gia Viên không đúng." },
|
||||
new ServerErrorMapping { id = 303, message = "Gia Viên đã tồn tại, xây dựng thất bại." },
|
||||
new ServerErrorMapping { id = 304, message = "Không thể xây dựng Gia Viên." },
|
||||
new ServerErrorMapping { id = 305, message = "Không tìm thấy vật phẩm cần đổi tên." },
|
||||
new ServerErrorMapping { id = 306, message = "Tên Gia Viên có chứa kí tự không hợp lệ." },
|
||||
new ServerErrorMapping { id = 307, message = "Quyền thiết lập Gia Viên không đổi." },
|
||||
new ServerErrorMapping { id = 308, message = "Không đủ Giáng Ngọc để nhận lại nhiệm vụ Gia Viên." },
|
||||
new ServerErrorMapping { id = 309, message = "Phụ bản Gia Viên đạt mức tối đa, hãy thử lại sau ít phút..." },
|
||||
new ServerErrorMapping { id = 310, message = "Trị số KNB không đúng." },
|
||||
new ServerErrorMapping { id = 311, message = "Số tiền không đúng." },
|
||||
new ServerErrorMapping { id = 312, message = "Cướp phong bao cần 2 ô trống trong túi đồ." },
|
||||
new ServerErrorMapping { id = 313, message = "Số tiền nhỏ hơn số đã phát." },
|
||||
new ServerErrorMapping { id = 314, message = "Thiếu giấy phong bao." },
|
||||
new ServerErrorMapping { id = 315, message = "Nhận phong bao cần 1 ô trống trong túi đồ." },
|
||||
new ServerErrorMapping { id = 316, message = "Số phong bao không đúng." },
|
||||
new ServerErrorMapping { id = 10150, message = "LINK - Thành công" },
|
||||
new ServerErrorMapping { id = 10151, message = "LINK - ERR_TOBECONTINUE" },
|
||||
new ServerErrorMapping { id = 10152, message = "LINK - Người dùng không tồn tại" },
|
||||
new ServerErrorMapping { id = 10153, message = "LINK -- Tên tài khoản hoặc mật mã sai" },
|
||||
new ServerErrorMapping { id = 10154, message = "LINK - Quá thời gian" },
|
||||
new ServerErrorMapping { id = 10155, message = "LINK - Tham số sai" },
|
||||
new ServerErrorMapping { id = 10156, message = "LINK - Không thể đồng bộ thông tin hảo hữu khi lưu giữ ở kho số liệu" },
|
||||
new ServerErrorMapping { id = 10157, message = "LINK - Máy chủ không hỗ trợ yêu cầu này" },
|
||||
new ServerErrorMapping { id = 10158, message = "LINK - Mạng lưới thông tin giữa các máy chủ lỗi" },
|
||||
new ServerErrorMapping { id = 10159, message = "LINK - Đăng nhập lại, tài khoản hiện tại đã đăng nhập, ở trạng thái khóa" },
|
||||
new ServerErrorMapping { id = 10160, message = "LINK - Đăng nhập lại, tài khoản hiện tại đã đăng nhập" },
|
||||
new ServerErrorMapping { id = 10161, message = "LINK - Giá trị nonce vô hiệu" },
|
||||
new ServerErrorMapping { id = 10163, message = "LINK - Máy chủ nhận thông tin nhân vật thất bại" },
|
||||
new ServerErrorMapping { id = 10164, message = "LINK - Đăng nhập máy chủ thất bại" },
|
||||
new ServerErrorMapping { id = 10165, message = "LINK - Số lượng người trong máy chủ đã đạt giới hạn" },
|
||||
new ServerErrorMapping { id = 10166, message = "LINK - Nhân vật này đã vào trò chơi" },
|
||||
new ServerErrorMapping { id = 10168, message = "LINK-Số người xếp hàng đã đạt mức tối đa." },
|
||||
new ServerErrorMapping { id = 10171, message = "LINK - Chuyển tiếp thất bại" },
|
||||
new ServerErrorMapping { id = 10172, message = "LINK - Chuyển tiếp quá thời gian" },
|
||||
new ServerErrorMapping { id = 10173, message = "LINK - Số dư tài khoản không đủ" },
|
||||
new ServerErrorMapping { id = 10174, message = "LINK - Tài khoản đã bị khóa, đăng nhập thất bại" },
|
||||
new ServerErrorMapping { id = 10175, message = "LINK - Không thể dùng tên này" },
|
||||
new ServerErrorMapping { id = 10176, message = "LINK - IP đã bị khóa, không thể đăng nhập trò chơi" },
|
||||
new ServerErrorMapping { id = 10177, message = "LINK - Bạn đã dùng thẻ bảo mật để đăng nhập thất bại ba lần liên tiếp, để đảm bảo an toàn cho tài khoản của bạn, hệ thống đã khóa tạm thời tài khoản. Bạn có thể đăng nhập lại sau." },
|
||||
new ServerErrorMapping { id = 10178, message = "LINK - Xác nhận bảo mật thất bại" },
|
||||
new ServerErrorMapping { id = 10181, message = "LINK - Đăng nhập trò chơi thất bại" },
|
||||
new ServerErrorMapping { id = 10182, message = "LINK - Bị văng khỏi mạng" },
|
||||
new ServerErrorMapping { id = 10183, message = "LINK - Tạo nhân vật thất bại" },
|
||||
new ServerErrorMapping { id = 10184, message = "LINK - Xóa nhân vật thất bại" },
|
||||
new ServerErrorMapping { id = 10185, message = "LINK - Nhận danh sách nhân vật thất bại" },
|
||||
new ServerErrorMapping { id = 10186, message = "LINK - Bỏ xóa nhân vật thất bại" },
|
||||
new ServerErrorMapping { id = 10187, message = "LINK - Máy chủ đang bảo trì, đăng nhập thất bại" },
|
||||
new ServerErrorMapping { id = 10188, message = "LINK - Nhân vật đã bị khóa, đăng nhập thất bại" },
|
||||
new ServerErrorMapping { id = 10189, message = "LINK - Số người trong máy chủ đã đầy" },
|
||||
new ServerErrorMapping { id = 10190, message = "LINK - Máy chủ chủ động ngắt kết nối" },
|
||||
new ServerErrorMapping { id = 10191, message = "LINK - ERR_FAILED" },
|
||||
new ServerErrorMapping { id = 10192, message = "LINK - ERR_EXCEPTION" },
|
||||
new ServerErrorMapping { id = 10193, message = "LINK - ERR_NOTFOUND" },
|
||||
new ServerErrorMapping { id = 10194, message = "LINK - ERR_INVALIDHANDLE" },
|
||||
new ServerErrorMapping { id = 10195, message = "LINK - Tên nhân vật bị trùng lặp" },
|
||||
new ServerErrorMapping { id = 10196, message = "LINK - Số lượng nhân vật đã đủ" },
|
||||
new ServerErrorMapping { id = 10201, message = "LINK - Đề nghị thêm làm hảo hữu" },
|
||||
new ServerErrorMapping { id = 10202, message = "LINK - Từ chối thêm làm hảo hữu" },
|
||||
new ServerErrorMapping { id = 10203, message = "LINK - Đồng ý thêm làm hảo hữu" },
|
||||
new ServerErrorMapping { id = 10204, message = "LINK - Đồng ý và hy vọng thêm đối phương làm hảo hữu" },
|
||||
new ServerErrorMapping { id = 10206, message = "LINK - Số phụ bản đã đạt mức tối đa, không thể mở phụ bản mới, tạm thời không thể đăng nhập" },
|
||||
new ServerErrorMapping { id = 10210, message = "LINK - Số liệu không tồn tại" },
|
||||
new ServerErrorMapping { id = 10213, message = "Trước khi rời khỏi giang hồ hãy thoái vị bang chủ" },
|
||||
new ServerErrorMapping { id = 10215, message = "Xin hãy xóa bỏ quan hệ hôn nhân với bạn đời của mình, sau đó mới có thể xóa nhân vật này." },
|
||||
new ServerErrorMapping { id = 10218, message = "LINK - Đối phương đã rời mạng" },
|
||||
new ServerErrorMapping { id = 10219, message = "LINK - Đối phương từ chối giao dịch" },
|
||||
new ServerErrorMapping { id = 10220, message = "LINK - Đối phương đang bận" },
|
||||
new ServerErrorMapping { id = 10221, message = "LINK - Đọc và ghi kho số liệu thất bại" },
|
||||
new ServerErrorMapping { id = 10222, message = "LINK - Vào giao dịch thất bại, đối phương đã có đối tượng giao dịch" },
|
||||
new ServerErrorMapping { id = 10223, message = "LINK - Người giao dịch vô hiệu" },
|
||||
new ServerErrorMapping { id = 10224, message = "LINK - Thêm vật phẩm giao dịch thất bại" },
|
||||
new ServerErrorMapping { id = 10225, message = "LINK - Giảm vật phẩm giao dịch thất bại" },
|
||||
new ServerErrorMapping { id = 10226, message = "LINK - Trao đổi hoàn thành một nữa, hãy đợi đối phương hoàn thành" },
|
||||
new ServerErrorMapping { id = 10227, message = "LINK - Trao đổi hoàn thành" },
|
||||
new ServerErrorMapping { id = 10228, message = "LINK - Trao đổi thất bại" },
|
||||
new ServerErrorMapping { id = 10229, message = "LINK - Xác nhận thất bại" },
|
||||
new ServerErrorMapping { id = 10230, message = "LINK - Giao dịch hoàn thành" },
|
||||
new ServerErrorMapping { id = 10231, message = "LINK - Giao dịch hoàn thành một nửa, hãy đợi đối phương xác nhận" },
|
||||
new ServerErrorMapping { id = 10232, message = "LINK - Hủy giao dịch thất bại" },
|
||||
new ServerErrorMapping { id = 10233, message = "LINK - Di chuyển vật phẩm thất bại" },
|
||||
new ServerErrorMapping { id = 10234, message = "LINK - Không gian ô vật phẩm của một bên nào đó không đủ" },
|
||||
new ServerErrorMapping { id = 10235, message = "LINK - Thiết lập tài sản của người giao dịch bị lỗi" },
|
||||
new ServerErrorMapping { id = 10236, message = "LINK - Vào giao dịch 1-1 thành công" },
|
||||
new ServerErrorMapping { id = 10237, message = "LINK - Vào giao dịch hai người thành công" },
|
||||
new ServerErrorMapping { id = 10238, message = "LINK - Quyền giao dịch của đối phương đã bị cấm" },
|
||||
new ServerErrorMapping { id = 10266, message = "Không đáp ứng điều kiện thao tác" },
|
||||
new ServerErrorMapping { id = 10280, message = "Bạn đã khóa bảo mật điện thoại, xin hãy gọi 010-5885-8566 tiến hành mở khóa rồi mới đăng nhập" },
|
||||
new ServerErrorMapping { id = 10281, message = "Tài khoản chưa kích hoạt không thể đăng nhập" },
|
||||
new ServerErrorMapping { id = 10282, message = "Tài khoản mạng Tung Hoành Trung Quốc chưa kích hoạt không thể đăng nhập" },
|
||||
new ServerErrorMapping { id = 10283, message = "Nhằm ưu hóa chất lượng đường truyền máy chủ, tài khoản lâu ngày không đăng nhập đã bị khóa, xin hãy liên hệ với Chăm sóc khách hàng." },
|
||||
new ServerErrorMapping { id = 10284, message = "Tần suất đăng nhập quá dày, chờ trong giây lát rồi đăng nhập lại..." },
|
||||
new ServerErrorMapping { id = 10285, message = "Tài khoản này đăng nhập lặp lại quá nhiều lần trong thời gian ngắn, để đảm bảo an toàn cho tài khỏan xin hãy đợi 10 phút đăng nhập lại." },
|
||||
new ServerErrorMapping { id = 10286, message = "Tài khoản của bạn đã bị khóa, vui lòng đăng nhập lại sau" },
|
||||
new ServerErrorMapping { id = 10287, message = "Bạn đã nhập sai mật mã Lệnh bài liên tục 3 lần. Để đảm bảo an toàn cho tài khoản, hệ thống tạm thời khóa tài khoản. Hãy thử đăng nhập lại sau 10 phút." },
|
||||
new ServerErrorMapping { id = 10288, message = "Vé quá hạn khi chuyển đổi, đăng nhập thất bại." },
|
||||
new ServerErrorMapping { id = 10289, message = "Kiểm duyệt thông tin ID thất bại khi chuyển đổi, không thể đăng nhập" },
|
||||
new ServerErrorMapping { id = 10290, message = "Kiểm duyệt thông tin ID server thất bại khi chuyển đổi, đăng nhập thất bại" },
|
||||
new ServerErrorMapping { id = 10291, message = "Tài khoản của bạn đăng ký nhanh, thông tin không hoàn thiện, có lỗ hổng an toàn nghiêm trọng. Hãy nhanh chóng hoàn thiện thông tin tài khoản trước khi đăng nhập lại." },
|
||||
new ServerErrorMapping { id = 10321, message = "Không thể tấn công kinh mạch" },
|
||||
new ServerErrorMapping { id = 10365, message = "Hòm thư của đối phương đã bị đóng băng" },
|
||||
new ServerErrorMapping { id = 10367, message = "Hòm thư của đối phương đã đầy" },
|
||||
new ServerErrorMapping { id = 10381, message = "Không thể đăng nhập, xin hãy đăng nhập trên trang Netmarble và xác nhận thông tin chi tiết" },
|
||||
new ServerErrorMapping { id = 10382, message = "Độ tuổi không đủ để có thể chơi trò chơi" },
|
||||
new ServerErrorMapping { id = 10383, message = "Không thể đăng nhập, xin hãy đợi trong giây lát rồi đăng nhập lại" },
|
||||
new ServerErrorMapping { id = 10384, message = "Người chơi không thử bên trong" },
|
||||
new ServerErrorMapping { id = 10385, message = "Đăng nhập thất bại, xin hãy xác nhận tài khoản/mật mã rồi đăng nhập lại" },
|
||||
new ServerErrorMapping { id = 10386, message = "Nhập sai tài khoản, mật mã quá 10 lần, xin hãy đăng nhập lại trên trang Netmarble" },
|
||||
new ServerErrorMapping { id = 10387, message = "Đăng nhập lại sau khi xác nhận tài khoản/mật mã" },
|
||||
new ServerErrorMapping { id = 10388, message = "Khách hàng dưới 18 tuổi phải tìm hiểu máy chủ." },
|
||||
new ServerErrorMapping { id = 10431, message = "Người chơi chưa thoát mạng" },
|
||||
new ServerErrorMapping { id = 10432, message = "Tin tức online của người chơi chưa được tải." },
|
||||
new ServerErrorMapping { id = 10433, message = "Người chơi đang lấy Hồng Lợi Trị" },
|
||||
new ServerErrorMapping { id = 10434, message = "Đăng nhập không có Hồng Lợi Trị để lấy." },
|
||||
new ServerErrorMapping { id = 10435, message = "Hỏi kho số liệu sai" },
|
||||
new ServerErrorMapping { id = 10436, message = "Mã mở rộng không đúng" },
|
||||
new ServerErrorMapping { id = 10437, message = "Người mở rộng không ở máy chủ này." },
|
||||
new ServerErrorMapping { id = 10438, message = "Dưới 40 cấp người chơi không thể mở rộng rời mạng" },
|
||||
new ServerErrorMapping { id = 10439, message = "Người mở rộng không có ở khu này" },
|
||||
new ServerErrorMapping { id = 10440, message = "Đăng nhập đã gắn kết, không thể gắn kết lại" },
|
||||
new ServerErrorMapping { id = 10441, message = "Người chơi điểm Danh Vọng nhỏ hơn 20 không thể mở rộng rời mạng" },
|
||||
new ServerErrorMapping { id = 10451, message = "Người chơi đã rời mạng" },
|
||||
new ServerErrorMapping { id = 10452, message = "Kho số liệu đã đầy" },
|
||||
new ServerErrorMapping { id = 10453, message = "Hỏi kho số liệu sai" },
|
||||
new ServerErrorMapping { id = 10454, message = "Điểm không đủ" },
|
||||
new ServerErrorMapping { id = 10455, message = "Không phải thời gian event không thể đổi điểm tích lũy" },
|
||||
new ServerErrorMapping { id = 10456, message = "Phương thức trở lại vô hiệu" },
|
||||
new ServerErrorMapping { id = 10457, message = "Số lần đổi quá nhiều" },
|
||||
new ServerErrorMapping { id = 10461, message = "Chưa mở giao dịch" },
|
||||
new ServerErrorMapping { id = 10462, message = "Không thể nhận mã số giao dịch" },
|
||||
new ServerErrorMapping { id = 10463, message = "Không thể ký gửi" },
|
||||
new ServerErrorMapping { id = 10464, message = "Không thể hủy ký gửi" },
|
||||
new ServerErrorMapping { id = 10465, message = "Số tiền bảo đảm giao dịch không đủ" },
|
||||
new ServerErrorMapping { id = 10466, message = "Thời gian giao dịch không hợp lệ" },
|
||||
new ServerErrorMapping { id = 10467, message = "Vật phẩm tương ứng số giao dịch không tồn tại" },
|
||||
new ServerErrorMapping { id = 10468, message = "Khi đồng bộ thao tác không thể nhận đề nghị giao dịch" },
|
||||
new ServerErrorMapping { id = 10469, message = "Nhân vật không khớp với mã số giao dịch" },
|
||||
new ServerErrorMapping { id = 10470, message = "Thời gian giao dịch không phù hợp" },
|
||||
new ServerErrorMapping { id = 10471, message = "Vật phẩm giao dịch đã bị bán" },
|
||||
new ServerErrorMapping { id = 10472, message = "Người mua không tồn tại" },
|
||||
new ServerErrorMapping { id = 10473, message = "Mã số giao dịch không phù hợp với ID tài khoản" },
|
||||
new ServerErrorMapping { id = 10474, message = "Giá bán vô hiệu" },
|
||||
new ServerErrorMapping { id = 10475, message = "Số lượng vật phẩm ký gửi đã đạt mức tối đa" },
|
||||
new ServerErrorMapping { id = 10476, message = "Hòm thư đã đầy, không thể nhận vật phẩm ký gửi" },
|
||||
new ServerErrorMapping { id = 10477, message = "Trạng thái hiện tại của người mua không phù hợp" },
|
||||
new ServerErrorMapping { id = 10478, message = "Người mua không tồn tại 2" },
|
||||
new ServerErrorMapping { id = 10479, message = "Người bán không tồn tại" },
|
||||
new ServerErrorMapping { id = 10480, message = "Người mua không phù hợp với điều kiện mua" },
|
||||
new ServerErrorMapping { id = 10481, message = "Nhân vật này đang có vật phẩm ký gửi, sau khi xóa mới có thể ký gửi nhân vật này" },
|
||||
new ServerErrorMapping { id = 10482, message = "Tài khoản này có nhân vật khác đang ký gửi, không thể tiếp tục ký gửi nhân vật" },
|
||||
new ServerErrorMapping { id = 10491, message = "Không tồn tại vật phẩm cạnh tranh" },
|
||||
new ServerErrorMapping { id = 10492, message = "Đang đồng bộ thao tác, không thể nhận yêu cầu cạnh tranh" },
|
||||
new ServerErrorMapping { id = 10493, message = "Hiện tại không thể cạnh tranh" },
|
||||
new ServerErrorMapping { id = 10494, message = "Giá cạnh tranh quá thấp" },
|
||||
new ServerErrorMapping { id = 10495, message = "Cạnh tranh thất bại, có nguời ra giá cao hơn" },
|
||||
new ServerErrorMapping { id = 10496, message = "Tài khoản tham gia cạnh tranh không tồn tại" },
|
||||
new ServerErrorMapping { id = 10497, message = "Đang đồng bộ thao tác, không thể nhận yêu cầu cạnh tranh" },
|
||||
new ServerErrorMapping { id = 10498, message = "Tiền đấu giá không đủ" },
|
||||
new ServerErrorMapping { id = 10499, message = "Lỗi tràn Tiền đấu giá (gửi vào hoặc lấy ra)" },
|
||||
new ServerErrorMapping { id = 10500, message = "Không thể chuyển tồn Nguyên Bảo" },
|
||||
new ServerErrorMapping { id = 10511, message = "Chưa mở Cơ sở Bang phái" },
|
||||
new ServerErrorMapping { id = 10512, message = "Cơ sở bang phái đã tồn tại" },
|
||||
new ServerErrorMapping { id = 10513, message = "Cơ sở bang phái không tồn tại" },
|
||||
new ServerErrorMapping { id = 10514, message = "Cơ sở Bang phái đang tiêu hủy" },
|
||||
new ServerErrorMapping { id = 10515, message = "Không thể tuyên chiến với cơ sở bang phái đối phương" },
|
||||
new ServerErrorMapping { id = 10516, message = "Tuyên chiến trùng lặp, đã từng tuyên chiến với Cơ sở Bang phái này" },
|
||||
new ServerErrorMapping { id = 10517, message = "Đang đồng bộ số liệu Cơ sở Bang phái" },
|
||||
new ServerErrorMapping { id = 10531, message = "Cấp độ Bang phái không phù hợp" },
|
||||
new ServerErrorMapping { id = 10532, message = "Đang tái thi triển thao tác" },
|
||||
new ServerErrorMapping { id = 10533, message = "Đang trong trạng thái ngoại giao, không thể thao tác" },
|
||||
new ServerErrorMapping { id = 10534, message = "Đối phương chưa gửi đề nghị này" },
|
||||
new ServerErrorMapping { id = 10561, message = "Số thẻ hoặc mật mã không đúng" },
|
||||
new ServerErrorMapping { id = 10562, message = "Thẻ nói chuyện đã quá hạn" },
|
||||
new ServerErrorMapping { id = 10563, message = "Số lần nạp tiền vào cùng một thẻ trong thời gian quy định vướt quá giới hạn" },
|
||||
new ServerErrorMapping { id = 10564, message = "Đang xử lý nạp thẻ, xin đợi trong giây lát rồi thử lại" },
|
||||
new ServerErrorMapping { id = 10571, message = "Trong vòng 10 ngày không thể gửi nhiều email cho cùng một người chơi" },
|
||||
new ServerErrorMapping { id = 10572, message = "Được gửi tối đa 5 email mỗi ngày" },
|
||||
new ServerErrorMapping { id = 10573, message = "Không tìm thấy hảo hữu" },
|
||||
new ServerErrorMapping { id = 10574, message = "Thời gian hảo hữu rời đi không phù hợp" },
|
||||
new ServerErrorMapping { id = 10575, message = "Cấp độ của hảo hữu quá thấp" },
|
||||
new ServerErrorMapping { id = 10576, message = "Chưa mở hoạt động triệu hồi" },
|
||||
new ServerErrorMapping { id = 10582, message = "Mã điện tử lệnh bài di động sai hoặc quá hạn, hãy kiểm tra trước khi thử nhập lại." },
|
||||
new ServerErrorMapping { id = 10583, message = "Nhân vật đã đổi tên" },
|
||||
new ServerErrorMapping { id = 10589, message = "Không đủ điều kiện tạo nhân vật tại máy chủ này" },
|
||||
new ServerErrorMapping { id = 10590, message = "Số lượng nhân vật tạo mới đã đạt giới hạn" },
|
||||
new ServerErrorMapping { id = 10601, message = "Mã kiểm tra liên server đã hết hạn" },
|
||||
new ServerErrorMapping { id = 10602, message = "Mã kiểm tra liên server không phù hợp" },
|
||||
new ServerErrorMapping { id = 10603, message = "Số liệu người chơi liên server có lỗi" },
|
||||
new ServerErrorMapping { id = 10604, message = "Máy chủ liên server đang được bảo trì" },
|
||||
new ServerErrorMapping { id = 10605, message = "Số liệu người chơi liên server bất thường" },
|
||||
new ServerErrorMapping { id = 10611, message = "Dịch vụ đổi tên không thể sử dụng" },
|
||||
new ServerErrorMapping { id = 10612, message = "Tên mới của nhân vật đã bị chiếm dụng" },
|
||||
new ServerErrorMapping { id = 10613, message = "Tên mới của nhân vật chứa kí tự không phù hợp" },
|
||||
new ServerErrorMapping { id = 10621, message = "Người ứng tuyển Quốc Vương không đáp ứng điều kiện đấu giá" },
|
||||
new ServerErrorMapping { id = 10622, message = "Đã dùng hết số lần ứng tuyển Quốc Vương" },
|
||||
new ServerErrorMapping { id = 10623, message = "Đã tham gia đấu giá" },
|
||||
new ServerErrorMapping { id = 10624, message = "Hiện tại không thể bỏ phiếu" },
|
||||
new ServerErrorMapping { id = 10625, message = "Người ứng tuyến không phù hợp" },
|
||||
new ServerErrorMapping { id = 10631, message = "Dịch vụ tặng quà không thể sử dụng" },
|
||||
new ServerErrorMapping { id = 10632, message = "Phát thưởng lại dựa trên thư nhận được" },
|
||||
new ServerErrorMapping { id = 10633, message = "Hòm thư của đối tượng nhận thưởng đã đầy" },
|
||||
new ServerErrorMapping { id = 10634, message = "Hòm thư của đối tượng thu nhận đã đầy" },
|
||||
new ServerErrorMapping { id = 10635, message = "Đã thu nhận hơn 3 lần đối với đối tượng thu nhận" },
|
||||
new ServerErrorMapping { id = 10640, message = "Chiến Xa Chiến Trường chưa mở" },
|
||||
new ServerErrorMapping { id = 10641, message = "Đã mời Chiến Xa Chiến Trường" },
|
||||
new ServerErrorMapping { id = 10642, message = "Không thể đổi bản đồ, hãy báo danh lại" },
|
||||
new ServerErrorMapping { id = 10643, message = "Không thể đổi bản đồ, hãy báo danh lại" },
|
||||
new ServerErrorMapping { id = 10651, message = "Số liệu cửa hàng chưa được tải từ kho dữ liệu" },
|
||||
new ServerErrorMapping { id = 10652, message = "Cửa hàng không tồn tại" },
|
||||
new ServerErrorMapping { id = 10653, message = "Cửa hàng đã tồn tại" },
|
||||
new ServerErrorMapping { id = 10654, message = "Cột thu mua của cửa hàng đã đầy" },
|
||||
new ServerErrorMapping { id = 10655, message = "Cột bán ra của cửa hàng đã đầy" },
|
||||
new ServerErrorMapping { id = 10657, message = "Kho của cửa hàng đã đầy" },
|
||||
new ServerErrorMapping { id = 10658, message = "Số tiền của cửa hàng đã đầy" },
|
||||
new ServerErrorMapping { id = 10659, message = "Số tiền của cửa hàng không đủ" },
|
||||
new ServerErrorMapping { id = 10660, message = "Cửa hàng đã quá hạn" },
|
||||
new ServerErrorMapping { id = 10661, message = "Cửa hàng bận rộn" },
|
||||
new ServerErrorMapping { id = 10662, message = "Cửa hàng không phát hiện vật phẩm" },
|
||||
new ServerErrorMapping { id = 10663, message = "Vật phẩm trong của hàng không phù hợp" },
|
||||
new ServerErrorMapping { id = 10751, message = "Số người đăng nhập liên server quá nhiều." },
|
||||
new ServerErrorMapping { id = 10752, message = "Khu vực không tồn tại." },
|
||||
new ServerErrorMapping { id = 10780, message = "Người chơi không ở server trung tâm." },
|
||||
new ServerErrorMapping { id = 10781, message = "Người chơi ở server trung tâm." },
|
||||
new ServerErrorMapping { id = 10782, message = "Không tìm thấy thông tin người chơi." },
|
||||
new ServerErrorMapping { id = 10783, message = "Không tìm thấy thông tin bang phái." },
|
||||
new ServerErrorMapping { id = 10784, message = "Số lãnh địa của bổn bang không đủ." },
|
||||
new ServerErrorMapping { id = 10785, message = "Số lãnh địa liên server không đủ." },
|
||||
new ServerErrorMapping { id = 10786, message = "Hoạt động chưa mở." },
|
||||
new ServerErrorMapping { id = 10787, message = "Loại báo danh không đúng." },
|
||||
new ServerErrorMapping { id = 10788, message = "Báo danh trùng lặp." },
|
||||
new ServerErrorMapping { id = 10789, message = "Điều kiện bang phái không phù hợp yêu cầu Quốc chiến liên server." },
|
||||
new ServerErrorMapping { id = 10790, message = "Phí báo danh không đủ." },
|
||||
};
|
||||
}
|
||||
|
||||
public string GetErrorString(int id)
|
||||
{
|
||||
foreach (var err in errors)
|
||||
{
|
||||
if (err.id == id) return err.message;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9066c623ade43ef4387b249530200c5f
|
||||
@@ -1,4 +1,5 @@
|
||||
using BrewMonster.Scripts.Task.UI;
|
||||
using BrewMonster.Scripts.UI;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
@@ -8,7 +9,7 @@ namespace BrewMonster.Scripts.ChatUI
|
||||
public class ChatMessageView : MonoBehaviour
|
||||
{
|
||||
public Image iconImage;
|
||||
public TextMeshProUGUI messageText;
|
||||
public EC_UIUtility.TextOutlet messageText;
|
||||
|
||||
public void Bind(Sprite iconSprite, string message)
|
||||
{
|
||||
@@ -20,7 +21,7 @@ namespace BrewMonster.Scripts.ChatUI
|
||||
iconImage.sprite = iconSprite;
|
||||
iconImage.enabled = iconSprite != null;
|
||||
|
||||
messageText.text = message;
|
||||
messageText.Set(message);
|
||||
GetComponent<IRefreshLayout>().RefreshLayout();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,13 +32,16 @@ namespace BrewMonster.Scripts.ChatUI
|
||||
|
||||
private List<ChatMessageData> _messages = new();
|
||||
private List<ChatMessageView> _visibleViews = new();
|
||||
private List<ChatMessageData> _filteredMessagesCache = new();
|
||||
|
||||
private ObjectPool<ChatMessageView> _pool;
|
||||
|
||||
private bool _userAtBottom = true;
|
||||
private ChatChannel _currentFilterChannel = ChatChannel.GP_CHAT_LOCAL;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
ClearChat();
|
||||
_iconCache = new Dictionary<byte, Sprite>();
|
||||
if (chatSystemSO != null && chatSystemSO.channelIcons != null)
|
||||
{
|
||||
@@ -48,7 +51,9 @@ namespace BrewMonster.Scripts.ChatUI
|
||||
}
|
||||
}
|
||||
|
||||
EventBus.Subscribe<OnEventClearChat>(OnChatMessageClear);
|
||||
EventBus.Subscribe<GameSession.ChatMessageEvent>(OnChatMessageReceived);
|
||||
EventBus.Subscribe<ChatChannelFilterChangedEvent>(OnChannelFilterChanged);
|
||||
_pool = new ObjectPool<ChatMessageView>(
|
||||
CreateItem,
|
||||
OnGetItem,
|
||||
@@ -64,19 +69,56 @@ namespace BrewMonster.Scripts.ChatUI
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
EventBus.Unsubscribe<OnEventClearChat>(OnChatMessageClear);
|
||||
EventBus.Unsubscribe<GameSession.ChatMessageEvent>(OnChatMessageReceived);
|
||||
EventBus.Unsubscribe<ChatChannelFilterChangedEvent>(OnChannelFilterChanged);
|
||||
|
||||
if (_pool != null)
|
||||
{
|
||||
_pool.Clear();
|
||||
_pool.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnChannelFilterChanged(ChatChannelFilterChangedEvent e)
|
||||
{
|
||||
if (this == null) return;
|
||||
_currentFilterChannel = e.channel;
|
||||
if (chatPanelUIGO != null && chatPanelUIGO.activeSelf)
|
||||
{
|
||||
RefreshVisible();
|
||||
}
|
||||
}
|
||||
|
||||
private bool ShouldShowMessage(ChatMessageData data)
|
||||
{
|
||||
if (_currentFilterChannel == ChatChannel.GP_CHAT_LOCAL) return true;
|
||||
if (data.channel == (byte)ChatChannel.GP_CHAT_MISC) return true;
|
||||
return data.channel == (byte)_currentFilterChannel;
|
||||
}
|
||||
|
||||
private void OnChatMessageReceived(GameSession.ChatMessageEvent x)
|
||||
{
|
||||
ChatThreadDispatcher.Instance.Post(() =>
|
||||
{
|
||||
if (this == null) return;
|
||||
AddMessage(x.context, x.channel);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void OnChatMessageClear(OnEventClearChat obj)
|
||||
{
|
||||
ChatThreadDispatcher.Instance.Post(() =>
|
||||
{
|
||||
if (this == null) return;
|
||||
ClearChat();
|
||||
});
|
||||
}
|
||||
|
||||
ChatMessageView CreateItem()
|
||||
{
|
||||
if (messagePrefab == null || content == null) return null;
|
||||
var item = Instantiate(messagePrefab);
|
||||
item.transform.SetParent(content, false);
|
||||
return item;
|
||||
@@ -84,17 +126,20 @@ namespace BrewMonster.Scripts.ChatUI
|
||||
|
||||
void OnGetItem(ChatMessageView item)
|
||||
{
|
||||
item.gameObject.SetActive(true);
|
||||
if (item != null)
|
||||
item.gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
void OnReleaseItem(ChatMessageView item)
|
||||
{
|
||||
item.gameObject.SetActive(false);
|
||||
if (item != null)
|
||||
item.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
void OnDestroyItem(ChatMessageView item)
|
||||
{
|
||||
Destroy(item.gameObject);
|
||||
if (item != null)
|
||||
Destroy(item.gameObject);
|
||||
}
|
||||
|
||||
void OnScrollChanged(Vector2 pos)
|
||||
@@ -114,6 +159,8 @@ namespace BrewMonster.Scripts.ChatUI
|
||||
|
||||
public void AddMessage(string msg, byte channel)
|
||||
{
|
||||
if (this == null || chatPanelUIGO == null) return;
|
||||
|
||||
var data = new ChatMessageData { message = msg, channel = channel };
|
||||
_messages.Add(data);
|
||||
|
||||
@@ -123,15 +170,22 @@ namespace BrewMonster.Scripts.ChatUI
|
||||
if (!chatPanelUIGO.activeSelf)
|
||||
return;
|
||||
|
||||
AddMessageView(data);
|
||||
if (ShouldShowMessage(data))
|
||||
{
|
||||
AddMessageView(data);
|
||||
|
||||
if (_userAtBottom)
|
||||
ScrollToBottom();
|
||||
if (_userAtBottom)
|
||||
ScrollToBottom();
|
||||
}
|
||||
}
|
||||
|
||||
void AddMessageView(ChatMessageData data)
|
||||
{
|
||||
if (this == null) return;
|
||||
var view = _pool.Get();
|
||||
if (view == null) view = CreateItem();
|
||||
if (view == null) return;
|
||||
|
||||
view.transform.SetParent(content, false);
|
||||
view.transform.SetAsLastSibling();
|
||||
|
||||
@@ -144,7 +198,10 @@ namespace BrewMonster.Scripts.ChatUI
|
||||
{
|
||||
var old = _visibleViews[0];
|
||||
_visibleViews.RemoveAt(0);
|
||||
_pool.Release(old);
|
||||
if (old != null)
|
||||
{
|
||||
_pool.Release(old);
|
||||
}
|
||||
}
|
||||
|
||||
Canvas.ForceUpdateCanvases();
|
||||
@@ -153,19 +210,34 @@ namespace BrewMonster.Scripts.ChatUI
|
||||
void RefreshVisible()
|
||||
{
|
||||
foreach (var view in _visibleViews)
|
||||
_pool.Release(view);
|
||||
{
|
||||
if (view != null)
|
||||
_pool.Release(view);
|
||||
}
|
||||
|
||||
_visibleViews.Clear();
|
||||
|
||||
int start = Mathf.Max(0, _messages.Count - maxVisibleMessages);
|
||||
_filteredMessagesCache.Clear();
|
||||
foreach (var msg in _messages)
|
||||
{
|
||||
if (ShouldShowMessage(msg))
|
||||
{
|
||||
_filteredMessagesCache.Add(msg);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = start; i < _messages.Count; i++)
|
||||
int start = Mathf.Max(0, _filteredMessagesCache.Count - maxVisibleMessages);
|
||||
|
||||
for (int i = start; i < _filteredMessagesCache.Count; i++)
|
||||
{
|
||||
var view = _pool.Get();
|
||||
if (view == null) view = CreateItem();
|
||||
if (view == null) continue;
|
||||
|
||||
view.transform.SetParent(content, false);
|
||||
view.transform.SetAsLastSibling();
|
||||
|
||||
var data = _messages[i];
|
||||
var data = _filteredMessagesCache[i];
|
||||
Sprite icon = _iconCache.ContainsKey(data.channel) ? _iconCache[data.channel] : null;
|
||||
view.Bind(icon, data.message);
|
||||
|
||||
@@ -186,7 +258,10 @@ namespace BrewMonster.Scripts.ChatUI
|
||||
public void ClearChat()
|
||||
{
|
||||
foreach (var view in _visibleViews)
|
||||
_pool.Release(view);
|
||||
{
|
||||
if (view != null)
|
||||
_pool.Release(view);
|
||||
}
|
||||
|
||||
_visibleViews.Clear();
|
||||
_messages.Clear();
|
||||
@@ -201,4 +276,6 @@ namespace BrewMonster.Scripts.ChatUI
|
||||
RefreshVisible();
|
||||
}
|
||||
}
|
||||
|
||||
public struct OnEventClearChat{}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
#if UNITY_EDITOR
|
||||
using UnityEngine;
|
||||
using CSNetwork;
|
||||
|
||||
namespace BrewMonster.Scripts.ChatUI
|
||||
{
|
||||
public class ServerErrorChatHandler : MonoBehaviour
|
||||
{
|
||||
public ServerErrorSO errorDatabase;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
EventBus.Subscribe<GameSession.ServerErrorEvent>(OnServerError);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
EventBus.Unsubscribe<GameSession.ServerErrorEvent>(OnServerError);
|
||||
}
|
||||
|
||||
private void OnServerError(GameSession.ServerErrorEvent e)
|
||||
{
|
||||
string errorMsg = null;
|
||||
if (errorDatabase != null)
|
||||
{
|
||||
errorMsg = errorDatabase.GetErrorString(e.ErrorCode);
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(errorMsg))
|
||||
{
|
||||
errorMsg = $"Lỗi không xác định";
|
||||
}
|
||||
|
||||
string coloredMsg = $"<color=red>[System Error {e.ErrorCode}] {errorMsg}</color>";
|
||||
|
||||
EventBus.Publish(new GameSession.ChatMessageEvent(
|
||||
coloredMsg,
|
||||
(byte)CSNetwork.GPDataType.ChatChannel.GP_CHAT_SYSTEM
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,2 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 94695abb88b0bff4b8b00ccc937f6d0f
|
||||
@@ -1339,33 +1339,10 @@ public class CECAttackEvent
|
||||
}
|
||||
public bool UpdateTargetFlag()
|
||||
{
|
||||
// update all targets' bAboutToDie flag
|
||||
|
||||
int nNumTargets = m_targets.Count;
|
||||
for (int i = 0; i < nNumTargets; i++)
|
||||
{
|
||||
TARGET_DATA data = m_targets[i];
|
||||
/*
|
||||
if( data.dwModifier & MOD_DEADLYSTRIKE )
|
||||
{
|
||||
int idTarget = data.idTarget;
|
||||
if (ISNPCID(idTarget))
|
||||
{
|
||||
CECNPC* pNPC = g_pGame->GetGameRun()->GetWorld()->GetNPCMan()->GetNPC(idTarget);
|
||||
if (!pNPC)
|
||||
return true;
|
||||
|
||||
pNPC->SetAboutToDie(true);
|
||||
}
|
||||
else if (ISPLAYERID(idTarget))
|
||||
{
|
||||
CECPlayer* pPlayer = g_pGame->GetGameRun()->GetWorld()->GetPlayerMan()->GetPlayer(idTarget);
|
||||
if (!pPlayer)
|
||||
return true;
|
||||
|
||||
pPlayer->SetAboutToDie(true);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@@ -294,24 +294,25 @@ namespace BrewMonster
|
||||
protected override void HitTarget(Vector3 vTarget)
|
||||
{
|
||||
base.HitTarget(vTarget);
|
||||
|
||||
DestroyFlyGfx();
|
||||
// Only destroy fly GFX if NOT tracing target
|
||||
// If tracing target, fly GFX will be cleaned up when buff expires
|
||||
// 只有在不跟踪目标时才销毁飞行特效
|
||||
// 如果跟踪目标,飞行特效将在buff过期时清理
|
||||
if (!m_bTraceTarget)
|
||||
{
|
||||
DestroyFlyGfx();
|
||||
}
|
||||
else
|
||||
{
|
||||
// If fly GFX exists and m_bTraceTarget is true, add to tracking list
|
||||
// 如果飞行特效存在且m_bTraceTarget为true,添加到跟踪列表
|
||||
if (m_flyGfxInstance != null)
|
||||
{
|
||||
SkillGfxMan.InstanceSub?.AddTraceTargetGfx(m_flyGfxInstance, 0); // Skill ID not available, use 0
|
||||
}
|
||||
}
|
||||
|
||||
// if (!m_bTraceTarget)
|
||||
// {
|
||||
// DestroyFlyGfx();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// // If fly GFX exists and m_bTraceTarget is true, add to tracking list
|
||||
// // 如果飞行特效存在且m_bTraceTarget为true,添加到跟踪列表
|
||||
// if (m_flyGfxInstance != null)
|
||||
// {
|
||||
// SkillGfxMan.InstanceSub?.AddTraceTargetGfx(m_flyGfxInstance, 0); // Skill ID not available, use 0
|
||||
// }
|
||||
// }
|
||||
|
||||
SpawnHitGfx(vTarget);
|
||||
|
||||
|
||||
@@ -316,6 +316,14 @@ namespace BrewMonster.Scripts
|
||||
// LOG_DEBUG_INFO(AString().Format("CECHPWork::%s add to priority queue %d", pWork->GetWorkName(), iPriority));
|
||||
//}
|
||||
}
|
||||
|
||||
if (bStarted &&
|
||||
pWork.GetWorkID() == CECHPWork.Host_work_ID.WORK_FORCENAVIGATEMOVE &&
|
||||
ValidatePriority(iPriority))
|
||||
{
|
||||
// (debug log removed)
|
||||
}
|
||||
|
||||
return bStarted;
|
||||
}
|
||||
bool CanRunSimultaneouslyWithCurrentWork(int iPriority, CECHPWork pWork)
|
||||
@@ -440,6 +448,14 @@ namespace BrewMonster.Scripts
|
||||
}
|
||||
}
|
||||
}
|
||||
if(pWork.GetWorkID() == Host_work_ID.WORK_FORCENAVIGATEMOVE)
|
||||
{
|
||||
CECHPWorkNavigate pWorkNavigate = pWork as CECHPWorkNavigate;
|
||||
if(pWorkNavigate != null)
|
||||
{
|
||||
pWorkNavigate.Finish();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pWork.Cancel();
|
||||
@@ -802,10 +818,10 @@ namespace BrewMonster.Scripts
|
||||
}
|
||||
|
||||
public void FinishRunningWork(int idWork)
|
||||
{
|
||||
{
|
||||
if (!IsWorkRunning(idWork))
|
||||
{
|
||||
return;
|
||||
return;
|
||||
}
|
||||
WorkList workList = m_WorkStack[m_iCurPriority];
|
||||
if (workList != null)
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace BrewMonster.Scripts
|
||||
}
|
||||
|
||||
fYaw -= 180.0f;
|
||||
UnityEngine.Debug.Assert(fYaw >= -180.0f && fYaw <= 180.0f);
|
||||
//UnityEngine.Debug.Assert(fYaw >= -180.0f && fYaw <= 180.0f);
|
||||
}
|
||||
|
||||
// Get pitch from vector // 从向量获取俯仰角
|
||||
@@ -257,9 +257,7 @@ namespace BrewMonster.Scripts
|
||||
navi.strModelPath = parts[5];
|
||||
|
||||
m_configInfo.Add(navi);
|
||||
}
|
||||
|
||||
Debug.Log($"[CECNavigateCtrl] Loaded force navigate config entries={m_configInfo.Count}");
|
||||
}
|
||||
return m_configInfo.Count > 0;
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -332,7 +330,6 @@ namespace BrewMonster.Scripts
|
||||
if (GetNavigateInfo(task, ref naviInfo))
|
||||
{
|
||||
m_curNavigateInfo = naviInfo;
|
||||
|
||||
// Set navigate model file // 设置导航模型文件
|
||||
CECHostNavigatePlayer player = m_pHost != null ? m_pHost.GetNavigatePlayer() : null;
|
||||
if (player != null)
|
||||
@@ -349,6 +346,10 @@ namespace BrewMonster.Scripts
|
||||
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 // 开始导航
|
||||
@@ -537,16 +538,17 @@ namespace BrewMonster.Scripts
|
||||
|
||||
if (!m_bMove || pBezierWalker == null) return true;
|
||||
|
||||
// C++: DWORD dwRealTime = g_pGame->GetRealTickTime(); // ms delta
|
||||
// 原版:DWORD dwRealTime = g_pGame->GetRealTickTime(); // 帧间毫秒差
|
||||
int dwRealTime = (int)EC_Game.GetRealTickTime();
|
||||
// Do not use EC_Game.GetRealTickTime() here: it is (unscaledDeltaTime - 0.018s)*1000 for mining tuning
|
||||
// and goes negative on typical frames (<18ms), corrupting m_iTimeCnt and Bezier param f.
|
||||
// 此处勿用 EC_Game.GetRealTickTime():其为挖矿偏移后的毫秒增量,帧快于 ~18ms 时为负,会破坏时间轴与 f。
|
||||
int dwRealTime = Mathf.Max(1, Mathf.RoundToInt(Time.unscaledDeltaTime * 1000f));
|
||||
|
||||
// TODO: Implement IsWalking
|
||||
// if (pBezierWalker->IsWalking()) {
|
||||
if (pBezierWalker.IsWalking())
|
||||
{
|
||||
pBezierWalker.Tick(dwRealTime);
|
||||
|
||||
|
||||
// Get updated position from bezier walker // 从贝塞尔行走器获取更新的位置
|
||||
A3DVECTOR3 vCurPos = pBezierWalker.GetPos();
|
||||
|
||||
@@ -585,7 +587,7 @@ namespace BrewMonster.Scripts
|
||||
}
|
||||
else
|
||||
{
|
||||
UnityEngine.Debug.Assert(false);
|
||||
//UnityEngine.Debug.Assert(false);
|
||||
}
|
||||
|
||||
// Set finish flag // 设置完成标志
|
||||
@@ -622,6 +624,7 @@ namespace BrewMonster.Scripts
|
||||
private bool m_bWalking; // true, is walking // true,正在行走
|
||||
private bool m_bPause; // Pause flag // 暂停标志
|
||||
private bool m_bForwardStop; // Stop flag // 停止标志
|
||||
private bool m_dbgWarnedZeroSeg; // One-shot empty-spline warning // 空路径单次警告
|
||||
public CECBezierWalker()
|
||||
{
|
||||
m_pBezier = null;
|
||||
@@ -650,6 +653,7 @@ namespace BrewMonster.Scripts
|
||||
m_bForwardStop = false;
|
||||
m_bWalking = false;
|
||||
m_bPause = false;
|
||||
m_dbgWarnedZeroSeg = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -711,7 +715,7 @@ namespace BrewMonster.Scripts
|
||||
{
|
||||
if (fSpeed <= 0.0f)
|
||||
{
|
||||
UnityEngine.Debug.Assert(false);
|
||||
//UnityEngine.Debug.Assert(false);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -762,15 +766,25 @@ namespace BrewMonster.Scripts
|
||||
int iNumSeg = m_pBezier.GetSegmentNum();
|
||||
if (iNumSeg == 0)
|
||||
{
|
||||
if (!m_dbgWarnedZeroSeg)
|
||||
{
|
||||
m_dbgWarnedZeroSeg = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
float fInvSpeed = 1000.0f / m_fSpeed;
|
||||
|
||||
if (iDeltaTime < 0)
|
||||
{
|
||||
iDeltaTime = Mathf.Max(1, Mathf.RoundToInt(Time.unscaledDeltaTime * 1000f));
|
||||
}
|
||||
|
||||
if (m_iTotalTime > 0)
|
||||
{
|
||||
iDeltaTime = iDeltaTime % m_iTotalTime;
|
||||
}
|
||||
|
||||
m_iTimeCnt += iDeltaTime;
|
||||
|
||||
if (m_bForward)
|
||||
@@ -864,7 +878,7 @@ namespace BrewMonster.Scripts
|
||||
{
|
||||
if (m_pBezier == null)
|
||||
{
|
||||
UnityEngine.Debug.Assert(false);
|
||||
//UnityEngine.Debug.Assert(false);
|
||||
return new A3DVECTOR3(0, 0, 0);
|
||||
}
|
||||
|
||||
@@ -877,6 +891,7 @@ namespace BrewMonster.Scripts
|
||||
if (m_iCurSegTime > 0)
|
||||
{
|
||||
f = (float)(m_iTimeCnt - m_iPassSegTime) / m_iCurSegTime;
|
||||
f = Mathf.Clamp01(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -915,7 +930,7 @@ namespace BrewMonster.Scripts
|
||||
{
|
||||
if (m_pBezier == null)
|
||||
{
|
||||
UnityEngine.Debug.Assert(false);
|
||||
//UnityEngine.Debug.Assert(false);
|
||||
return new A3DVECTOR3(0, 0, 1);
|
||||
}
|
||||
|
||||
@@ -928,6 +943,7 @@ namespace BrewMonster.Scripts
|
||||
if (m_iCurSegTime > 0)
|
||||
{
|
||||
f = (float)(m_iTimeCnt - m_iPassSegTime) / m_iCurSegTime;
|
||||
f = Mathf.Clamp01(f);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -961,6 +977,36 @@ namespace BrewMonster.Scripts
|
||||
return new A3DVECTOR3(0, 0, 1);
|
||||
}
|
||||
|
||||
// Debug: timeline mirrors GetPos/GetDir parameter f (expect 0…1 while walking). // 调试:与 GetPos 一致的段内参数 f(行走时期望 0…1)。
|
||||
public void GetTimelineDebug(out int numSeg, out int curSeg, out int timeCnt, out int passSegTime, out int curSegTime, out float paramF, out bool walking, out bool forwardStop, out bool loop)
|
||||
{
|
||||
numSeg = m_pBezier != null ? m_pBezier.GetSegmentNum() : 0;
|
||||
curSeg = m_iCurSeg;
|
||||
timeCnt = m_iTimeCnt;
|
||||
passSegTime = m_iPassSegTime;
|
||||
curSegTime = m_iCurSegTime;
|
||||
walking = m_bWalking;
|
||||
forwardStop = m_bForwardStop;
|
||||
loop = m_bLoop;
|
||||
paramF = 0f;
|
||||
if (m_pBezier == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_bWalking || m_bPause)
|
||||
{
|
||||
if (m_iCurSegTime > 0)
|
||||
{
|
||||
paramF = Mathf.Clamp01((float)(m_iTimeCnt - m_iPassSegTime) / m_iCurSegTime);
|
||||
}
|
||||
}
|
||||
else if (m_bForwardStop)
|
||||
{
|
||||
paramF = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsWalking() { return m_bWalking; }
|
||||
public bool IsPause() { return m_bPause; }
|
||||
public bool GetForwardFlag() { return m_bForward; }
|
||||
@@ -1466,6 +1512,7 @@ namespace BrewMonster.Scripts
|
||||
}
|
||||
|
||||
s_loaded = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
catch
|
||||
|
||||
@@ -65,11 +65,13 @@ namespace BrewMonster.Scripts
|
||||
|
||||
// Tick routine
|
||||
public override bool Tick(float dwDeltaTime)
|
||||
{
|
||||
{
|
||||
base.Tick(dwDeltaTime * 1000);
|
||||
|
||||
BMLogger.LogError($" m_OverTimeCnt m_dwCounter:{m_OverTimeCnt.m_dwCounter}, m_dwPeriod:{m_OverTimeCnt.m_dwPeriod} ");
|
||||
if (m_OverTimeCnt.IncCounter(dwDeltaTime * 1000))
|
||||
m_bFinished = true;
|
||||
{
|
||||
BMLogger.LogError($" m_OverTimeCnt finished ");
|
||||
m_bFinished = true; }
|
||||
|
||||
if (m_idTarget != 0)
|
||||
{
|
||||
@@ -126,7 +128,7 @@ namespace BrewMonster.Scripts
|
||||
m_pSkill = pSkill;
|
||||
}
|
||||
|
||||
public bool Match(CECHPWork pWork, int priority, bool isDelayWork)
|
||||
public override bool Match(CECHPWork pWork, int priority, bool isDelayWork)
|
||||
{
|
||||
bool bMatching = false;
|
||||
if (pWork != null && pWork.GetWorkID() == CECHPWork.Host_work_ID.WORK_SPELLOBJECT)
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using BrewMonster;
|
||||
using UnityEngine;
|
||||
|
||||
public class CECCounter
|
||||
{
|
||||
// Thuộc tính
|
||||
protected float m_dwCounter; // Counter
|
||||
protected float m_dwPeriod; // Count period
|
||||
public float m_dwCounter; // Counter
|
||||
public float m_dwPeriod; // Count period
|
||||
|
||||
// Constructor
|
||||
public CECCounter()
|
||||
|
||||
@@ -820,6 +820,12 @@ namespace CSNetwork
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public struct ServerErrorEvent
|
||||
{
|
||||
public int ErrorCode;
|
||||
public ServerErrorEvent(int code) { ErrorCode = code; }
|
||||
}
|
||||
|
||||
private static string GetEquipSlotName(byte slotIndex)
|
||||
{
|
||||
if (Enum.IsDefined(typeof(IndexOfIteminEquipmentInventory), slotIndex))
|
||||
@@ -1139,21 +1145,12 @@ namespace CSNetwork
|
||||
cmd_error_msg pCmd = GPDataTypeHelper.FromBytes<cmd_error_msg>(pDataBuf);
|
||||
#if UNITY_EDITOR
|
||||
BMLogger.LogError($"### GameDataSend: ERROR_MESSAGE parsed iMessage={pCmd.iMessage}");
|
||||
#endif
|
||||
Debug.LogError($"### GameDataSend: ERROR_MESSAGE: {errRaw}");
|
||||
if (pCmd.iMessage != 0)
|
||||
{
|
||||
// string szMsg = m_ErrorMsgs.GetWideString(pCmd.iMessage);
|
||||
// if (string.IsNullOrEmpty(szMsg))
|
||||
// BMLogger.LogError("SERVER - unknown error !");
|
||||
// else
|
||||
// {
|
||||
// BMLogger.LogError("SERVER - error: "+szMsg);
|
||||
// }
|
||||
// else if (pCmd.iMessage != 2)
|
||||
// g_pGame.GetGameRun().AddChatMessage(szMsg, GP_CHAT_MISC);
|
||||
EventBus.Publish(new ServerErrorEvent(pCmd.iMessage));
|
||||
}
|
||||
|
||||
#endif
|
||||
if (pCmd.iMessage == 2)
|
||||
{
|
||||
// Attack target is too far
|
||||
@@ -2038,10 +2035,9 @@ namespace CSNetwork
|
||||
string strSrcName = Encoding.Unicode.GetString(p.Name.ToArray());
|
||||
|
||||
string fmt = AUICommon.ConvertPrintfToCSharpFormat(pStrTab.GetWideString((int)FixedMsg.FIXMSG_CHAT));
|
||||
string nameWithTag = $"&{strSrcName}&";
|
||||
string formatted;
|
||||
try {
|
||||
formatted = string.Format(fmt, nameWithTag, strMsg);
|
||||
formatted = string.Format(fmt, strSrcName, strMsg);
|
||||
} catch {
|
||||
formatted = $"{strSrcName}: {strMsg}";
|
||||
}
|
||||
@@ -2265,12 +2261,9 @@ namespace CSNetwork
|
||||
// Format: "[Name] whispers to [You]: [Message]"
|
||||
string fmt = AUICommon.ConvertPrintfToCSharpFormat(pStrTab.GetWideString((int)FixedMsg.FIXMSG_PRIVATECHAT1));
|
||||
|
||||
// Wrap sender name in & so the AddChatMessage regex can color it.
|
||||
string nameWithTag = $"&{strSrcName}&";
|
||||
|
||||
string formatted;
|
||||
try {
|
||||
formatted = string.Format(fmt, nameWithTag, strMsg);
|
||||
formatted = string.Format(fmt, strSrcName, strMsg);
|
||||
} catch {
|
||||
formatted = $"{strSrcName} whispers to you: {strMsg}";
|
||||
}
|
||||
|
||||
@@ -1643,16 +1643,10 @@ namespace BrewMonster.Scripts.Task
|
||||
if (pTempl != null
|
||||
&& pTempl.m_FixedData.m_enumMethod== (uint)TaskCompletionMethod.enumTMSimpleClientTaskForceNavi)
|
||||
{
|
||||
UnityEngine.Debug.Log($"[CECTaskInterface] OnNewTask: Task {iTaskID} is force navigate task, triggering EM_PREPARE");
|
||||
SetForceNavigateFinishFlag(false);
|
||||
|
||||
// Trigger navigation event // 触发导航事件
|
||||
m_pHost.OnNaviageEvent(iTaskID, (int)CECNavigateCtrl.NavigateEvent.EM_PREPARE);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnityEngine.Debug.Log($"[CECTaskInterface] OnNewTask: Task {iTaskID} is not a force navigate task (pTempl={pTempl != null}, method={pTempl?.m_FixedData.m_enumMethod})");
|
||||
}
|
||||
}
|
||||
|
||||
public void OnTaskConfirmUpdate()
|
||||
@@ -1671,20 +1665,13 @@ namespace BrewMonster.Scripts.Task
|
||||
|
||||
public void OnCompleteTask(int iTaskID)
|
||||
{
|
||||
UnityEngine.Debug.Log($"[CECTaskInterface] OnCompleteTask: TaskID={iTaskID}");
|
||||
ATaskTempl pTempl = GetTaskTemplMan().GetTaskTemplByID((uint)iTaskID);
|
||||
if (pTempl != null &&
|
||||
pTempl.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMSimpleClientTaskForceNavi)
|
||||
{
|
||||
UnityEngine.Debug.Log($"[CECTaskInterface] OnCompleteTask: Task {iTaskID} is force navigate task, triggering EM_END");
|
||||
// Trigger navigation end event // 触发导航结束事件
|
||||
m_pHost.OnNaviageEvent(iTaskID, (int)CECNavigateCtrl.NavigateEvent.EM_END);
|
||||
SetForceNavigateFinishFlag(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnityEngine.Debug.Log($"[CECTaskInterface] OnCompleteTask: Task {iTaskID} is not a force navigate task");
|
||||
}
|
||||
}
|
||||
|
||||
public void TakeAwayCommonItem(uint ulTemplId, uint ulNum) {}
|
||||
|
||||
@@ -362,10 +362,13 @@ namespace BrewMonster.Scripts.Task
|
||||
{
|
||||
if (!needServerCheck || pTask == null || pTempl == null || entry == null) return;
|
||||
|
||||
// Auto-check for wait-time tasks and simple client tasks (emote/action tasks)
|
||||
// Auto-check for wait-time, simple client, and force-navigation tasks (path + optional wait timer).
|
||||
// 等待时间、简单客户端、强制导航任务:条件满足时通知服务器校验完成。
|
||||
// Without force-nav here, bezier/wait quests never send CHECK_FINISH and may only hit timeout / fail paths.
|
||||
TaskCompletionMethod method = (TaskCompletionMethod)pTempl.m_FixedData.m_enumMethod;
|
||||
if (method != TaskCompletionMethod.enumTMWaitTime &&
|
||||
method != TaskCompletionMethod.enumTMSimpleClientTask)
|
||||
if (method != TaskCompletionMethod.enumTMWaitTime &&
|
||||
method != TaskCompletionMethod.enumTMSimpleClientTask &&
|
||||
method != TaskCompletionMethod.enumTMSimpleClientTaskForceNavi)
|
||||
return;
|
||||
|
||||
if (entry.IsFinished()) return;
|
||||
|
||||
@@ -1808,13 +1808,25 @@ namespace BrewMonster.Scripts.Task
|
||||
break;
|
||||
|
||||
case TaskCompletionMethod.enumTMSimpleClientTask:
|
||||
case TaskCompletionMethod.enumTMSimpleClientTaskForceNavi:
|
||||
{
|
||||
// 简单客户端任务条件 // Simple client task condition
|
||||
ret = pTask.CheckSimpleTaskFinshConditon(m_FixedData.m_ID);
|
||||
}
|
||||
break;
|
||||
|
||||
case TaskCompletionMethod.enumTMSimpleClientTaskForceNavi:
|
||||
{
|
||||
// Path done (client flag) // 路径走完(客户端标记)
|
||||
ret = pTask.CheckSimpleTaskFinshConditon(m_FixedData.m_ID);
|
||||
// Optional post-path wait (m_ulWaitTime seconds from task accept) — same rule as enumTMWaitTime.
|
||||
// 可选路径后等待(接任务起 m_ulWaitTime 秒)— 与 enumTMWaitTime 判定一致。
|
||||
if (ret && m_FixedData.m_ulWaitTime > 0)
|
||||
{
|
||||
ret = pEntry.m_ulTaskTime + (ulong)m_FixedData.m_ulWaitTime < (ulong)ulCurTime;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case TaskCompletionMethod.enumTMReachLevel:
|
||||
// 达到等级条件 // Reach level condition
|
||||
ret = CheckReachLevel(pTask);
|
||||
|
||||
@@ -126,7 +126,10 @@ namespace BrewMonster.Scripts.Task.UI
|
||||
|
||||
public TaskTreeViewHolder GetItemByData(uint taskType)
|
||||
{
|
||||
|
||||
//This is work around to avoid the null proplem.
|
||||
//TODO: Refine Logic.
|
||||
if(this == null)
|
||||
return null;
|
||||
if (m_aTreeViewItems == null)
|
||||
{
|
||||
m_aTreeViewItems = new TaskTreeViewHolder[this.transform.childCount];
|
||||
|
||||
@@ -117,7 +117,7 @@ namespace BrewMonster.UI
|
||||
/// Convert/format printf-style strings (e.g. "ID:%d Name:%s") with C# args.
|
||||
/// Supports common specifiers and keeps "%%" as a literal percent.
|
||||
/// </summary>
|
||||
protected static string FormatPrintf(string formatStr, params object[] args)
|
||||
public static string FormatPrintf(string formatStr, params object[] args)
|
||||
{
|
||||
if (string.IsNullOrEmpty(formatStr))
|
||||
return formatStr;
|
||||
|
||||
@@ -90,8 +90,10 @@ namespace BrewMonster.UI
|
||||
|
||||
void OnWhisper(int characterId)
|
||||
{
|
||||
Debug.Log("OnWhisper: " + characterId);
|
||||
// TODO: open whisper/chat input with target when available
|
||||
string name = EC_ManMessageMono.Instance?.GetECManPlayer?.GetElsePlayer(characterId)?.GetName() ?? "";
|
||||
Debug.Log("OnWhisper: " + characterId + " name: " + name);
|
||||
|
||||
EventBus.Publish(new BrewMonster.Scripts.ChatUI.WhisperPlayerEvent(name));
|
||||
}
|
||||
|
||||
void PositionAtMouse()
|
||||
|
||||
@@ -146,44 +146,36 @@ namespace BrewMonster.Scripts.UI
|
||||
CECHostPlayer hostPlayer = EC_Game.GetGameRun()?.GetHostPlayer();
|
||||
if (hostPlayer != null)
|
||||
{
|
||||
bool shouldForceNavigate = false;
|
||||
|
||||
// 1) Prefer template flag (C++: enumTMSimpleClientTaskForceNavi)
|
||||
// 1) 优先使用任务模板标记(C++:enumTMSimpleClientTaskForceNavi)
|
||||
var taskMan = EC_Game.GetTaskTemplateMan();
|
||||
var templ = taskMan != null ? taskMan.GetTaskTemplByID((uint)taskId) : null;
|
||||
if (templ != null &&
|
||||
templ.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMSimpleClientTaskForceNavi)
|
||||
{
|
||||
shouldForceNavigate = true;
|
||||
}
|
||||
// Force-navigate dispatch is currently disabled here (see commented-out block below).
|
||||
// 强制导航的分发目前在这里被禁用(见下方注释块)。
|
||||
|
||||
// 2) Fallback: if force_navigate.txt contains this task, treat it as force-navigate even if template flag is missing.
|
||||
// 2) 回退:如果 force_navigate.txt 中存在该任务映射,即使模板标记缺失,也按强制导航处理。
|
||||
if (!shouldForceNavigate)
|
||||
{
|
||||
var np = hostPlayer.GetNavigatePlayer();
|
||||
var ctrl = np != null ? np.GetNavigateCtrl() : null;
|
||||
if (ctrl != null)
|
||||
{
|
||||
var tmp = new BrewMonster.Scripts.CECNavigateCtrl.INFO();
|
||||
if (ctrl.GetNavigateInfo(taskId, ref tmp))
|
||||
{
|
||||
shouldForceNavigate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// if (!shouldForceNavigate)
|
||||
// {
|
||||
// var np = hostPlayer.GetNavigatePlayer();
|
||||
// var ctrl = np != null ? np.GetNavigateCtrl() : null;
|
||||
// if (ctrl != null)
|
||||
// {
|
||||
// var tmp = new BrewMonster.Scripts.CECNavigateCtrl.INFO();
|
||||
// if (ctrl.GetNavigateInfo(taskId, ref tmp))
|
||||
// {
|
||||
// shouldForceNavigate = true;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// if (shouldForceNavigate)
|
||||
// {
|
||||
// UnityEngine.Debug.Log(
|
||||
// $"[CECUIHelper] FollowCoord: taskId={taskId} => force navigate (bezier) instead of normal auto-move");
|
||||
// hostPlayer.OnNaviageEvent(taskId,
|
||||
// (int)BrewMonster.Scripts.CECNavigateCtrl.NavigateEvent.EM_PREPARE);
|
||||
// hostPlayer.OnNaviageEvent(taskId,
|
||||
// (int)BrewMonster.Scripts.CECNavigateCtrl.NavigateEvent.EM_BEGIN);
|
||||
// return true;
|
||||
// }
|
||||
|
||||
if (shouldForceNavigate)
|
||||
{
|
||||
UnityEngine.Debug.Log(
|
||||
$"[CECUIHelper] FollowCoord: taskId={taskId} => force navigate (bezier) instead of normal auto-move");
|
||||
hostPlayer.OnNaviageEvent(taskId,
|
||||
(int)BrewMonster.Scripts.CECNavigateCtrl.NavigateEvent.EM_PREPARE);
|
||||
hostPlayer.OnNaviageEvent(taskId,
|
||||
(int)BrewMonster.Scripts.CECNavigateCtrl.NavigateEvent.EM_BEGIN);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -471,7 +471,7 @@ namespace BrewMonster.UI
|
||||
|
||||
if (isPlayerChannel && idPlayer > 0) // idPlayer > 0 is equivalent to C++ ISPLAYERID(id)
|
||||
{
|
||||
// TODO: pszMsg = FilterBadWords(pszMsg); when API is available
|
||||
CECUIManager.Instance.FilterBadWords(ref pszMsg);
|
||||
}
|
||||
|
||||
// C++: Booth Message check (cChannel == GP_CHAT_WHISPER && pszMsg ends with "!#")
|
||||
|
||||
@@ -41,18 +41,18 @@ namespace BrewMonster.UI
|
||||
// true = show male, false = show female
|
||||
private static readonly bool[] s_bShowMale = new bool[]
|
||||
{
|
||||
true, // 0: Warrior (武侠)
|
||||
false, // 1: Mage (法师)
|
||||
false, // 2: Priest (巫师)
|
||||
false, // 3: Assassin (妖精)
|
||||
true, // 4: Orc (妖兽)
|
||||
true, // 5: Monk (刺客)
|
||||
true, // 6: Elf (羽芒)
|
||||
false, // 7: Elf (羽灵)
|
||||
true, // 8: Ling (剑灵)
|
||||
false, // 9: Ling (魅灵)
|
||||
true, // 10: Oboro (夜影)
|
||||
false, // 11: Oboro (月仙)
|
||||
true, // 0: kiem khach (nhan toc)
|
||||
false, // 1: phap su (nhan toc)
|
||||
false, // 2: vu su (tich toc)
|
||||
false, // 3: tien thu (thu toc)
|
||||
true, // 4: than thu (thu toc)
|
||||
true, // 5: thich khach (tich toc)
|
||||
true, // 6: vu mang (vu toc)
|
||||
false, // 7: vu linh (vu toc)
|
||||
true, // 8: kiem linh (linh toc)
|
||||
false, // 9: mi linh (linh toc)
|
||||
true, // 10: da anh (long toc)
|
||||
false, // 11: nguyet tien (long toc)
|
||||
};
|
||||
|
||||
private void Start()
|
||||
|
||||
@@ -225,6 +225,7 @@ GameObject:
|
||||
- component: {fileID: 806170753671297629}
|
||||
- component: {fileID: 2621697629504226575}
|
||||
- component: {fileID: 5889020827802476297}
|
||||
- component: {fileID: 806784442167936328}
|
||||
m_Layer: 5
|
||||
m_Name: prefab_ChatSystemUI
|
||||
m_TagString: Untagged
|
||||
@@ -297,6 +298,19 @@ MonoBehaviour:
|
||||
button: {fileID: 1690303811971402318}
|
||||
- channel: 8
|
||||
button: {fileID: 5620031369785857446}
|
||||
--- !u!114 &806784442167936328
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 541196262870756845}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 94695abb88b0bff4b8b00ccc937f6d0f, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
errorDatabase: {fileID: 11400000, guid: 6016467082edf7a46ab650b0c04c82cd, type: 2}
|
||||
--- !u!1 &726262149639511024
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -1139,7 +1153,7 @@ RectTransform:
|
||||
m_AnchorMin: {x: 0.5, y: 0}
|
||||
m_AnchorMax: {x: 0.5, y: 0}
|
||||
m_AnchoredPosition: {x: -522, y: 24}
|
||||
m_SizeDelta: {x: 706.4468, y: 338.1244}
|
||||
m_SizeDelta: {x: 706.4468, y: 180}
|
||||
m_Pivot: {x: 0, y: 0}
|
||||
--- !u!222 &5165419663723014475
|
||||
CanvasRenderer:
|
||||
|
||||
@@ -153,8 +153,8 @@ MonoBehaviour:
|
||||
|
||||
'
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_fontAsset: {fileID: 11400000, guid: 369c2e14814cc9a4b8e3ad4e37769134, type: 2}
|
||||
m_sharedMaterial: {fileID: 9092487103257209053, guid: 369c2e14814cc9a4b8e3ad4e37769134, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
@@ -330,7 +330,9 @@ MonoBehaviour:
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
iconImage: {fileID: 2098686458651577804}
|
||||
messageText: {fileID: 5305392080666511277}
|
||||
messageText:
|
||||
legacy: {fileID: 0}
|
||||
tmp: {fileID: 5305392080666511277}
|
||||
--- !u!114 &-887576589064363463
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -75,6 +75,127 @@ MonoBehaviour:
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!1 &2335355260693615667
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 4002267172184040261}
|
||||
- component: {fileID: 2340503496181969335}
|
||||
- component: {fileID: 2112208504970652693}
|
||||
- component: {fileID: 5173447691193350084}
|
||||
m_Layer: 5
|
||||
m_Name: enter_game_btn
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &4002267172184040261
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2335355260693615667}
|
||||
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
|
||||
m_Children:
|
||||
- {fileID: 5671343588912430135}
|
||||
m_Father: {fileID: 8190183238285994582}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 1, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 0}
|
||||
m_AnchoredPosition: {x: -230, y: 100}
|
||||
m_SizeDelta: {x: 356, y: 99}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &2340503496181969335
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2335355260693615667}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &2112208504970652693
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2335355260693615667}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 21300000, guid: edd33299d4203c34e957ca4cc602468a, type: 3}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!114 &5173447691193350084
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 2335355260693615667}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Navigation:
|
||||
m_Mode: 3
|
||||
m_WrapAround: 0
|
||||
m_SelectOnUp: {fileID: 0}
|
||||
m_SelectOnDown: {fileID: 0}
|
||||
m_SelectOnLeft: {fileID: 0}
|
||||
m_SelectOnRight: {fileID: 0}
|
||||
m_Transition: 1
|
||||
m_Colors:
|
||||
m_NormalColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1}
|
||||
m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1}
|
||||
m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608}
|
||||
m_ColorMultiplier: 1
|
||||
m_FadeDuration: 0.1
|
||||
m_SpriteState:
|
||||
m_HighlightedSprite: {fileID: 0}
|
||||
m_PressedSprite: {fileID: 0}
|
||||
m_SelectedSprite: {fileID: 0}
|
||||
m_DisabledSprite: {fileID: 0}
|
||||
m_AnimationTriggers:
|
||||
m_NormalTrigger: Normal
|
||||
m_HighlightedTrigger: Highlighted
|
||||
m_PressedTrigger: Pressed
|
||||
m_SelectedTrigger: Selected
|
||||
m_DisabledTrigger: Disabled
|
||||
m_Interactable: 1
|
||||
m_TargetGraphic: {fileID: 2112208504970652693}
|
||||
m_OnClick:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
--- !u!1 &2432735602217839019
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -485,6 +606,142 @@ MonoBehaviour:
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_ShowMaskGraphic: 0
|
||||
--- !u!1 &4934455472919714949
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 5671343588912430135}
|
||||
- component: {fileID: 2419494351044922696}
|
||||
- component: {fileID: 8755002905980993026}
|
||||
m_Layer: 5
|
||||
m_Name: Text
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &5671343588912430135
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4934455472919714949}
|
||||
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
|
||||
m_Children: []
|
||||
m_Father: {fileID: 4002267172184040261}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 0, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &2419494351044922696
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4934455472919714949}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &8755002905980993026
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4934455472919714949}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: f4688fdb7df04437aeb418b961361dc5, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: "V\xE0o game"
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_fontSharedMaterials: []
|
||||
m_fontMaterial: {fileID: 0}
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontColor: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
m_fontColorGradient:
|
||||
topLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
topRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomLeft: {r: 1, g: 1, b: 1, a: 1}
|
||||
bottomRight: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_fontColorGradientPreset: {fileID: 0}
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: -1183493901
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 40.04
|
||||
m_fontSizeBase: 40.04
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 0
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
m_fontStyle: 0
|
||||
m_HorizontalAlignment: 2
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
m_TextWrappingMode: 1
|
||||
m_wordWrappingRatios: 0.4
|
||||
m_overflowMode: 0
|
||||
m_linkedTextComponent: {fileID: 0}
|
||||
parentLinkedComponent: {fileID: 0}
|
||||
m_enableKerning: 0
|
||||
m_ActiveFontFeatures: 6e72656b
|
||||
m_enableExtraPadding: 0
|
||||
checkPaddingRequired: 0
|
||||
m_isRichText: 1
|
||||
m_EmojiFallbackSupport: 1
|
||||
m_parseCtrlCharacters: 1
|
||||
m_isOrthographic: 1
|
||||
m_isCullingEnabled: 0
|
||||
m_horizontalMapping: 0
|
||||
m_verticalMapping: 0
|
||||
m_uvLineOffset: 0
|
||||
m_geometrySortingOrder: 0
|
||||
m_IsTextObjectScaleStatic: 0
|
||||
m_VertexBufferAutoSizeReduction: 0
|
||||
m_useMaxVisibleDescender: 1
|
||||
m_pageToDisplay: 1
|
||||
m_margin: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_isUsingLegacyAnimationComponent: 0
|
||||
m_isVolumetricText: 0
|
||||
m_hasFontAssetChanged: 0
|
||||
m_baseMaterial: {fileID: 0}
|
||||
m_maskOffset: {x: 0, y: 0, z: 0, w: 0}
|
||||
--- !u!1 &6031041715831305634
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -516,6 +773,7 @@ RectTransform:
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 6444858493086001938}
|
||||
- {fileID: 4002267172184040261}
|
||||
m_Father: {fileID: 5968911800527563993}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
@@ -657,6 +915,7 @@ MonoBehaviour:
|
||||
addCharacterItemPrefab: {fileID: 5263746738484752443, guid: a0b31ed0940ec9942b243a0b8cec8ad3, type: 3}
|
||||
parentItems: {fileID: 2643174602035272289}
|
||||
createCharacterButton: {fileID: 2685968509838782728}
|
||||
_btnEnterGame: {fileID: 5173447691193350084}
|
||||
createCharacterScreen: {fileID: 0}
|
||||
--- !u!1 &7510180475820570348
|
||||
GameObject:
|
||||
@@ -816,7 +1075,7 @@ GameObject:
|
||||
- component: {fileID: 65697960061454470}
|
||||
- component: {fileID: 2685968509838782728}
|
||||
m_Layer: 5
|
||||
m_Name: enter_game_btn
|
||||
m_Name: enter_game_btn??
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
|
||||
@@ -1018,7 +1018,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 335.91, y: -507.53912}
|
||||
m_AnchoredPosition: {x: 335.91, y: -431.53912}
|
||||
m_SizeDelta: {x: 651.82, y: 0}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &2731969899170380074
|
||||
@@ -1692,9 +1692,9 @@ RectTransform:
|
||||
- {fileID: 4504331075840543341}
|
||||
m_Father: {fileID: 1361524257611413148}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 108.9562, y: -31.05}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 179.9124, y: 68.0217}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &8804506040386004496
|
||||
@@ -4482,9 +4482,9 @@ RectTransform:
|
||||
- {fileID: 2027606699309904338}
|
||||
m_Father: {fileID: 1361524257611413148}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 468.781, y: -31.05}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 179.9124, y: 68.0217}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &6741821173640675138
|
||||
@@ -13996,9 +13996,9 @@ RectTransform:
|
||||
- {fileID: 911293677621153352}
|
||||
m_Father: {fileID: 1361524257611413148}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 1}
|
||||
m_AnchorMax: {x: 0, y: 1}
|
||||
m_AnchoredPosition: {x: 288.8686, y: -31.05}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 0, y: 0}
|
||||
m_AnchoredPosition: {x: 0, y: 0}
|
||||
m_SizeDelta: {x: 179.9124, y: 68.0217}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &5623009994815814977
|
||||
|
||||
@@ -390,7 +390,8 @@ RectTransform:
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Children:
|
||||
- {fileID: 7309247008755679928}
|
||||
m_Father: {fileID: 7908433956144043347}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0.5}
|
||||
@@ -661,6 +662,81 @@ MonoBehaviour:
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!1 &4596132992197834427
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 7309247008755679928}
|
||||
- component: {fileID: 6214481239893992401}
|
||||
- component: {fileID: 1695895101203069456}
|
||||
m_Layer: 5
|
||||
m_Name: FocusImage
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &7309247008755679928
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4596132992197834427}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1.1591, y: 1.1591, z: 1.1591}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 5880582069126801893}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0.5}
|
||||
m_AnchorMax: {x: 0, y: 0.5}
|
||||
m_AnchoredPosition: {x: 70.5, y: 3.8}
|
||||
m_SizeDelta: {x: 112, y: 112}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!222 &6214481239893992401
|
||||
CanvasRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4596132992197834427}
|
||||
m_CullTransparentMesh: 1
|
||||
--- !u!114 &1695895101203069456
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 4596132992197834427}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: fe87c0e1cc204ed48ad3b37840f39efc, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Material: {fileID: 0}
|
||||
m_Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_RaycastTarget: 1
|
||||
m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
|
||||
m_Maskable: 1
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_Sprite: {fileID: 21300000, guid: 360017f7378d2204da559134abb90341, type: 3}
|
||||
m_Type: 0
|
||||
m_PreserveAspect: 0
|
||||
m_FillCenter: 1
|
||||
m_FillMethod: 4
|
||||
m_FillAmount: 1
|
||||
m_FillClockwise: 1
|
||||
m_FillOrigin: 0
|
||||
m_UseSpriteMesh: 0
|
||||
m_PixelsPerUnitMultiplier: 1
|
||||
--- !u!1 &4863950106461546000
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -949,6 +1025,8 @@ MonoBehaviour:
|
||||
m_EditorClassIdentifier:
|
||||
btnClick: {fileID: 2876940671243353215}
|
||||
nameCharacter: {fileID: 1254458684095285810}
|
||||
_labelDetailInfo: {fileID: 5335385781983735630}
|
||||
_goFocusImage: {fileID: 4596132992197834427}
|
||||
--- !u!1 &6227331727854863199
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
@@ -345,7 +345,8 @@ namespace BrewMonster
|
||||
iWaitTime = pCmd.time + m_pCurSkill.GetExecuteTime();
|
||||
|
||||
CECHPWorkSpell pWork = (CECHPWorkSpell)m_pWorkMan.CreateWork(Host_work_ID.WORK_SPELLOBJECT);
|
||||
|
||||
BMLogger.LogError($"[SKILL_CAST_DEBUG] OnMsgPlayerCastSkill: Created CECHPWorkSpell for skillID={m_pCurSkill.GetSkillID()}, " +
|
||||
$"executeTime={m_pCurSkill.GetExecuteTime()}, waitTime={iWaitTime}");
|
||||
pWork.PrepareCast(pCmd.target, m_pCurSkill, iWaitTime);
|
||||
m_pWorkMan.StartWork_p1(pWork);
|
||||
// Debug.Log($"[SKILL_CAST_DEBUG] OnMsgPlayerCastSkill: OBJECT_CAST_SKILL - Created WORK_SPELLOBJECT, " +
|
||||
|
||||
@@ -90,6 +90,10 @@ public class CECUIManager : MonoSingleton<CECUIManager>
|
||||
return;
|
||||
}
|
||||
UpdateTaskUI();
|
||||
|
||||
// Hiển thị thông tin đăng nhập khi người chơi đã vào game an toàn / Show login info when host player is ready
|
||||
// Hàm này bên trong đã có cờ m_bAccountLoginInfoShown để tránh bị gọi nhiều lần, nên đặt ở Update là an toàn.
|
||||
EC_Game.GetGameRun()?.ShowAccountLoginInfo();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
using BrewMonster;
|
||||
using CSNetwork.Protocols.RPCData;
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Text;
|
||||
using BrewMonster.Network;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
@@ -11,22 +11,30 @@ public class CharacterItemUI : MonoBehaviour
|
||||
{
|
||||
[SerializeField] private Button btnClick;
|
||||
[SerializeField] private TextMeshProUGUI nameCharacter;
|
||||
[SerializeField] private TextMeshProUGUI _labelDetailInfo;
|
||||
[SerializeField] private GameObject _goFocusImage;
|
||||
RoleInfo dataItem;
|
||||
Action<RoleInfo> onClick;
|
||||
public RoleInfo RoleInfo => dataItem;
|
||||
Action<CharacterItemUI> onClick;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_goFocusImage.SetActive(false);
|
||||
}
|
||||
|
||||
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
||||
void Start()
|
||||
{
|
||||
btnClick.onClick.AddListener(OnClickBtn);
|
||||
}
|
||||
|
||||
public void InitItem(RoleInfo role, Action<RoleInfo> action)
|
||||
public void InitItem(RoleInfo role, Action<CharacterItemUI> action)
|
||||
{
|
||||
dataItem = role;
|
||||
onClick = action;
|
||||
string roleName = "(Error decoding name)";
|
||||
if (role.name != null && role.name.ByteArray != null)
|
||||
{
|
||||
|
||||
// Be careful with encoding, assume UTF8 is correct
|
||||
roleName = Encoding.Unicode.GetString(
|
||||
role.name.RawBuffer,
|
||||
@@ -35,10 +43,23 @@ public class CharacterItemUI : MonoBehaviour
|
||||
);
|
||||
}
|
||||
nameCharacter.text = roleName;
|
||||
if (EC_Game.GetGameRun() != null)
|
||||
{
|
||||
_labelDetailInfo.text =$"{EC_Game.GetGameRun().GetProfName(role.occupation)} Cấp {role.level.ToString()}";
|
||||
}
|
||||
else
|
||||
{
|
||||
BMLogger.LogError("No game run found");
|
||||
}
|
||||
}
|
||||
|
||||
public void OnClickBtn()
|
||||
{
|
||||
onClick?.Invoke(dataItem);
|
||||
onClick?.Invoke(this);
|
||||
}
|
||||
|
||||
public void SetFocus(bool focus)
|
||||
{
|
||||
_goFocusImage.SetActive(focus);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,18 @@ using CSNetwork;
|
||||
|
||||
namespace BrewMonster.Scripts.ChatUI
|
||||
{
|
||||
public struct ChatChannelFilterChangedEvent
|
||||
{
|
||||
public ChatChannel channel;
|
||||
public ChatChannelFilterChangedEvent(ChatChannel c) { channel = c; }
|
||||
}
|
||||
|
||||
public struct WhisperPlayerEvent
|
||||
{
|
||||
public string playerName;
|
||||
public WhisperPlayerEvent(string name) { playerName = name; }
|
||||
}
|
||||
|
||||
public class ChatInputHandler : MonoBehaviour
|
||||
{
|
||||
public TMP_InputField inputField;
|
||||
@@ -24,6 +36,14 @@ namespace BrewMonster.Scripts.ChatUI
|
||||
|
||||
private const int MAX_HISTORY = 10;
|
||||
private ChatChannel m_currentChannel = ChatChannel.GP_CHAT_LOCAL;
|
||||
private string m_whisperTarget = "";
|
||||
|
||||
public void SetWhisperTarget(string playerName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(playerName)) return;
|
||||
m_whisperTarget = playerName;
|
||||
OnCommand_speakmode(ChatChannel.GP_CHAT_WHISPER);
|
||||
}
|
||||
|
||||
private struct ChatMsg
|
||||
{
|
||||
@@ -40,6 +60,21 @@ namespace BrewMonster.Scripts.ChatUI
|
||||
private float m_dwTickFarCry = 0;
|
||||
private float m_dwTickFarCry2 = 0;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
EventBus.Subscribe<WhisperPlayerEvent>(OnWhisperPlayerEvent);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
EventBus.Unsubscribe<WhisperPlayerEvent>(OnWhisperPlayerEvent);
|
||||
}
|
||||
|
||||
private void OnWhisperPlayerEvent(WhisperPlayerEvent e)
|
||||
{
|
||||
SetWhisperTarget(e.playerName);
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
inputField.onSubmit.AddListener(OnSubmit);
|
||||
@@ -87,17 +122,45 @@ namespace BrewMonster.Scripts.ChatUI
|
||||
}
|
||||
}
|
||||
|
||||
m_currentChannel = channel;
|
||||
var config = chatSystem.channelIcons.Find(c => c.channel == channel);
|
||||
if (config.prefix != null)
|
||||
if (m_currentChannel != channel && channel != ChatChannel.GP_CHAT_WHISPER)
|
||||
{
|
||||
string currentText = inputField.text;
|
||||
currentText = RemoveKnownPrefix(currentText);
|
||||
inputField.text = config.prefix + currentText;
|
||||
m_whisperTarget = "";
|
||||
}
|
||||
|
||||
inputField.ActivateInputField();
|
||||
inputField.MoveTextEnd(false);
|
||||
m_currentChannel = channel;
|
||||
|
||||
// Handle System channel input restriction
|
||||
if (m_currentChannel == ChatChannel.GP_CHAT_SYSTEM)
|
||||
{
|
||||
inputField.interactable = false;
|
||||
inputField.text = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
inputField.interactable = true;
|
||||
|
||||
var config = chatSystem.channelIcons.Find(c => c.channel == channel);
|
||||
string currentText = inputField.text;
|
||||
currentText = RemoveKnownPrefix(currentText);
|
||||
|
||||
if (channel == ChatChannel.GP_CHAT_WHISPER && !string.IsNullOrEmpty(m_whisperTarget))
|
||||
{
|
||||
inputField.text = "/" + m_whisperTarget + " " + currentText;
|
||||
}
|
||||
else if (config.prefix != null)
|
||||
{
|
||||
inputField.text = config.prefix + currentText;
|
||||
}
|
||||
else
|
||||
{
|
||||
inputField.text = currentText;
|
||||
}
|
||||
|
||||
inputField.ActivateInputField();
|
||||
inputField.MoveTextEnd(false);
|
||||
}
|
||||
|
||||
EventBus.Publish(new ChatChannelFilterChangedEvent(m_currentChannel));
|
||||
}
|
||||
|
||||
private string RemoveKnownPrefix(string text)
|
||||
@@ -113,7 +176,15 @@ namespace BrewMonster.Scripts.ChatUI
|
||||
{
|
||||
return text.Substring(1);
|
||||
}
|
||||
// Không tự ý remove prefix của Whisper (bắt đầu bằng '/') vì nó đi kèm tên người chơi
|
||||
else if (text.StartsWith("/"))
|
||||
{
|
||||
int spaceIndex = text.IndexOf(' ');
|
||||
if (spaceIndex > 0)
|
||||
{
|
||||
return text.Substring(spaceIndex + 1);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
@@ -304,6 +375,19 @@ namespace BrewMonster.Scripts.ChatUI
|
||||
HandleWhisper(text, nPack, nSlot);
|
||||
return ChatChannel.GP_CHAT_WHISPER;
|
||||
}
|
||||
else if (channel == ChatChannel.GP_CHAT_WHISPER)
|
||||
{
|
||||
// Cho phép chat kênh Whisper mượt mà mà không bắt buộc gõ ký tự "/" ở đầu
|
||||
if (!string.IsNullOrEmpty(m_whisperTarget))
|
||||
{
|
||||
HandleWhisper("/" + m_whisperTarget + " " + text, nPack, nSlot);
|
||||
}
|
||||
else
|
||||
{
|
||||
HandleWhisper("/" + text, nPack, nSlot);
|
||||
}
|
||||
return ChatChannel.GP_CHAT_WHISPER;
|
||||
}
|
||||
// Không gõ prefix thủ công thì sẽ dùng m_currentChannel đã được gán ở đầu hàm
|
||||
|
||||
SendChat(channel, pszMsg, nPack, nSlot);
|
||||
@@ -329,6 +413,8 @@ namespace BrewMonster.Scripts.ChatUI
|
||||
string player = cmd.Substring(0, spaceIndex);
|
||||
string msg = cmd.Substring(spaceIndex + 1);
|
||||
|
||||
m_whisperTarget = player;
|
||||
|
||||
SendPrivateChat(player, msg, nPack, nSlot);
|
||||
}
|
||||
|
||||
@@ -350,7 +436,7 @@ namespace BrewMonster.Scripts.ChatUI
|
||||
UnityGameSession.Instance.GameSession.SendPrivateChatData(target, msg, 0, 0, pack, slot);
|
||||
|
||||
// Server không echo whisper lại cho chính mình → hiện local echo
|
||||
string localEcho = $"<color=#0065FE>[Whisper] → {target}: {msg}</color>";
|
||||
string localEcho = $"<color=#0065FE>{target}: {msg}</color>";
|
||||
EventBus.Publish(new GameSession.ChatMessageEvent(localEcho, (byte)ChatChannel.GP_CHAT_WHISPER));
|
||||
}
|
||||
|
||||
@@ -450,7 +536,14 @@ namespace BrewMonster.Scripts.ChatUI
|
||||
|
||||
private void ClearTextInInputField()
|
||||
{
|
||||
inputField.text = "";
|
||||
if (m_currentChannel == ChatChannel.GP_CHAT_WHISPER && !string.IsNullOrEmpty(m_whisperTarget))
|
||||
{
|
||||
inputField.text = "/" + m_whisperTarget + " ";
|
||||
}
|
||||
else
|
||||
{
|
||||
inputField.text = "";
|
||||
}
|
||||
}
|
||||
private void ChangeFocus()
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
|
||||
using BrewMonster;
|
||||
using BrewMonster.Network;
|
||||
using BrewMonster.Scripts.ChatUI;
|
||||
using UnityEngine;
|
||||
|
||||
public partial class CECGameRun
|
||||
@@ -8,7 +9,7 @@
|
||||
int m_iGameState; // Game state
|
||||
// Logout flag (C++: m_iLogoutFlag)
|
||||
private int m_iLogoutFlag = -1;
|
||||
|
||||
|
||||
// Logout
|
||||
public void Logout()
|
||||
{
|
||||
@@ -18,13 +19,13 @@
|
||||
BMLogger.LogError($"Logout called but game state is not GS_GAME, current state: {m_iGameState}");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// TODO: Check if we need to call OnLogout for UI and cross server here
|
||||
// overlay::GTOverlay::Instance().Logout();
|
||||
// CECCrossServer::Instance().OnLogout();
|
||||
|
||||
bool bExitApp = false;
|
||||
|
||||
EventBus.Publish(new OnEventClearChat());
|
||||
// if (CECUIConfig::Instance().GetLoginUI().bAvoidLoginUI && m_iLogoutFlag != 1){
|
||||
if( 1 == 2 && m_iLogoutFlag != 1){ // TODO: check if we need to avoid login UI based on config and logout flag here
|
||||
bExitApp = true;
|
||||
@@ -35,12 +36,12 @@
|
||||
else if (m_iLogoutFlag == 1) // Logout game and re-select role
|
||||
{
|
||||
UnityGameSession.ReturnToSelectRole();
|
||||
|
||||
|
||||
// TODO: Check if we need to send switch game for mini client here
|
||||
// Origin C++
|
||||
// Origin C++
|
||||
// StartLogin();
|
||||
StartLogin();
|
||||
|
||||
|
||||
//
|
||||
// // ÏÂÔØÆ÷ÏìÓ¦Í˳öÓÎϷ״̬
|
||||
// if( g_pGame->GetConfigs()->IsMiniClient() )
|
||||
@@ -70,7 +71,7 @@
|
||||
else if (m_iLogoutFlag == 2) // Logout game and goto login state
|
||||
{
|
||||
UnityGameSession.LogoutAccount();
|
||||
|
||||
|
||||
// TODO: Check if we need to send switch game for mini client here
|
||||
// Origin C++
|
||||
// StartLogin();
|
||||
@@ -92,8 +93,8 @@
|
||||
// ASSERT(NULL);
|
||||
bExitApp = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// if (m_pRandomMapProc)
|
||||
// A3DRELEASE(m_pRandomMapProc);
|
||||
|
||||
@@ -104,7 +105,7 @@
|
||||
// ::PostMessage(g_pGame->GetGameInit().hWnd, WM_QUIT, 0, 0);
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
// End current game state
|
||||
void EndGameState(bool bReset = true/* true */)
|
||||
{
|
||||
@@ -130,10 +131,10 @@
|
||||
|
||||
// if (bReset)
|
||||
// g_pGame.Reset();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Start login interface
|
||||
bool StartLogin()
|
||||
{
|
||||
@@ -164,7 +165,7 @@
|
||||
// }else{
|
||||
// m_pLogo->SetLinearFilter(true);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (af_IsFileExist("surfaces\\kr.dds"))
|
||||
// {
|
||||
// if (!m_pClassification){
|
||||
@@ -175,7 +176,7 @@
|
||||
// m_pClassification->SetLinearFilter(true);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// // Change cursor to default icon
|
||||
// g_pGame->ChangeCursor(RES_CUR_NORMAL);
|
||||
// // Discard current frame
|
||||
@@ -183,7 +184,7 @@
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// End login state
|
||||
void OnEndLoginState()
|
||||
{
|
||||
@@ -201,13 +202,13 @@
|
||||
void OnEndGameState()
|
||||
{
|
||||
ReleasePendingActions();
|
||||
|
||||
|
||||
// Release UI module
|
||||
// m_pUIManager.ChangeCurUIManager(-1);
|
||||
|
||||
|
||||
// Release shortcuts
|
||||
ReleaseShortcuts();
|
||||
|
||||
|
||||
// Release team manager
|
||||
// A3DRELEASE(m_pTeamMan);
|
||||
if (m_pTeamMan != null)
|
||||
@@ -215,23 +216,23 @@
|
||||
m_pTeamMan.Release();
|
||||
m_pTeamMan = null;
|
||||
}
|
||||
|
||||
|
||||
// Release host player before world released
|
||||
// ReleaseHostPlayer();
|
||||
|
||||
|
||||
// Release world
|
||||
// ReleaseWorld();
|
||||
|
||||
|
||||
// Release message manager
|
||||
// A3DRELEASE(m_pMessageMan);
|
||||
|
||||
|
||||
// g_pGame.ReleaseInGameRes();
|
||||
|
||||
|
||||
// Return the default memory state
|
||||
// m_pMemSimplify.OnEndGameState();
|
||||
// CECOptimize::Instance().OnEndGameState();
|
||||
}
|
||||
|
||||
|
||||
// Release shortcuts
|
||||
void ReleaseShortcuts()
|
||||
{
|
||||
@@ -240,14 +241,14 @@
|
||||
// A3DRELEASE(m_pTradeSCS);
|
||||
// A3DRELEASE(m_pPoseSCS);
|
||||
// A3DRELEASE(m_pFactionSCS);
|
||||
|
||||
|
||||
m_pNormalSCS = null;
|
||||
m_pTeamSCS = null;
|
||||
m_pTradeSCS = null;
|
||||
m_pPoseSCS = null;
|
||||
m_pFactionSCS = null;
|
||||
}
|
||||
|
||||
|
||||
// Release host player
|
||||
void ReleaseHostPlayer()
|
||||
{
|
||||
@@ -259,7 +260,7 @@
|
||||
// delete m_pHostPlayer;
|
||||
// m_pHostPlayer = NULL;
|
||||
// }
|
||||
|
||||
|
||||
// Release host player
|
||||
if (m_pHostPlayer)
|
||||
{
|
||||
@@ -268,7 +269,7 @@
|
||||
m_pHostPlayer = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Release world
|
||||
void ReleaseWorld()
|
||||
{
|
||||
@@ -276,7 +277,7 @@
|
||||
// m_pInputCtrl->ClearMouFilterStack();
|
||||
//
|
||||
// g_pGame->GetViewport()->SwitchCamera(false);
|
||||
|
||||
|
||||
if (m_pWorld != null)
|
||||
{
|
||||
// if (m_pHostPlayer)
|
||||
|
||||
@@ -303,6 +303,9 @@ public partial class CECGameRun : ITickable
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
// 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
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Net;
|
||||
using CSNetwork;
|
||||
using CSNetwork.GPDataType;
|
||||
using BrewMonster.Common;
|
||||
using BrewMonster.UI;
|
||||
using UnityEngine;
|
||||
|
||||
// Account login info struct
|
||||
@@ -34,41 +35,57 @@ partial class CECGameRun
|
||||
m_bAccountLoginInfoShown = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hiển thị thông tin đăng nhập của tài khoản (thời gian & IP).
|
||||
/// Hàm này được gọi khi người chơi vào thế giới game.
|
||||
/// Thông báo chỉ hiển thị một lần duy nhất theo phiên chơi nhờ biến m_bAccountLoginInfoShown.
|
||||
/// </summary>
|
||||
public void ShowAccountLoginInfo()
|
||||
{
|
||||
Debug.Log("[Cuong] ShowAccountLoginInfo");
|
||||
|
||||
// Kiểm tra cờ xem đã hiển thị thông tin đăng nhập chưa để tránh in lặp lại nhiều lần.
|
||||
if (!m_bAccountLoginInfoShown)
|
||||
{
|
||||
m_bAccountLoginInfoShown = true;
|
||||
|
||||
// Assuming CECUIConfig::Instance().GetGameUI().bEnableShowIP translates to true for now
|
||||
bool bEnableShowIP = true;
|
||||
if (bEnableShowIP)
|
||||
var pGameUI = CECUIManager.Instance?.GetInGameUIMan();
|
||||
if (pGameUI != null)
|
||||
{
|
||||
// Last login time
|
||||
DateTime Epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
DateTime t = Epoch.AddSeconds(m_AccountLoginInfo.login_time).ToLocalTime();
|
||||
m_bAccountLoginInfoShown = true;
|
||||
|
||||
string timeStr = string.Format("({0}-{1:00}-{2:00} {3:00}:{4:00})",
|
||||
t.Year, t.Month, t.Day, t.Hour, t.Minute);
|
||||
string textTime = string.Format("Lần đăng nhập trước: {0}", timeStr); // 9343
|
||||
// (Trong C++ gốc: CECUIConfig::Instance().GetGameUI().bEnableShowIP)
|
||||
// Hiện tại mặc định bật cờ hiển thị IP đăng nhập.
|
||||
bool bEnableShowIP = true;
|
||||
if (bEnableShowIP)
|
||||
{
|
||||
// 1. Tính toán và hiển thị thời gian đăng nhập lần trước (Last login time).
|
||||
DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
|
||||
DateTime t = epoch.AddSeconds(m_AccountLoginInfo.login_time).ToLocalTime();
|
||||
|
||||
EventBus.Publish(new GameSession.ChatMessageEvent { context = textTime, channel = (byte)ChatChannel.GP_CHAT_SYSTEM });
|
||||
Debug.Log($"[Cuong] ShowAccountLoginInfo {textTime}");
|
||||
// Table 8010: chuỗi dạng "%d-%d-%d %d:%d" hoặc tương tự
|
||||
string timeStr = AUIDialog.FormatPrintf(pGameUI.GetStringFromTable(8010),
|
||||
t.Year, t.Month, t.Day, t.Hour, t.Minute);
|
||||
// Table 9343: chuỗi dạng "Thời gian đăng nhập trước: %s"
|
||||
string textTime = AUIDialog.FormatPrintf(pGameUI.GetStringFromTable(9343), timeStr);
|
||||
|
||||
// Last login IP
|
||||
string ipStr = new IPAddress((long)m_AccountLoginInfo.login_ip).ToString();
|
||||
string textIp = string.Format("IP đăng nhập trước: {0}", ipStr); // 9344
|
||||
EventBus.Publish(new GameSession.ChatMessageEvent { context = textTime, channel = (byte)ChatChannel.GP_CHAT_SYSTEM });
|
||||
Debug.Log($"[Cuong] ShowAccountLoginInfo {textTime}");
|
||||
|
||||
EventBus.Publish(new GameSession.ChatMessageEvent { context = textIp, channel = (byte)ChatChannel.GP_CHAT_SYSTEM });
|
||||
Debug.Log($"[Cuong] ShowAccountLoginInfo {textIp}");
|
||||
// 2. Định dạng và hiển thị IP đăng nhập lần trước (Last login IP).
|
||||
// Table 9344: chuỗi dạng "IP đăng nhập trước: %s"
|
||||
string ipStr = new IPAddress((long)m_AccountLoginInfo.login_ip).ToString();
|
||||
string textIp = AUIDialog.FormatPrintf(pGameUI.GetStringFromTable(9344), ipStr);
|
||||
|
||||
// Current login IP
|
||||
string curIpStr = new IPAddress((long)m_AccountLoginInfo.current_ip).ToString();
|
||||
string textCurIp = string.Format("IP đăng nhập hiện tại: {0}", curIpStr); // 9345
|
||||
EventBus.Publish(new GameSession.ChatMessageEvent { context = textIp, channel = (byte)ChatChannel.GP_CHAT_SYSTEM });
|
||||
Debug.Log($"[Cuong] ShowAccountLoginInfo {textIp}");
|
||||
|
||||
EventBus.Publish(new GameSession.ChatMessageEvent { context = textCurIp, channel = (byte)ChatChannel.GP_CHAT_SYSTEM });
|
||||
Debug.Log($"[Cuong] ShowAccountLoginInfo {textCurIp}");
|
||||
// 3. Định dạng và hiển thị IP đăng nhập hiện tại (Current login IP).
|
||||
// Table 9345: chuỗi dạng "IP đăng nhập hiện tại: %s"
|
||||
string curIpStr = new IPAddress((long)m_AccountLoginInfo.current_ip).ToString();
|
||||
string textCurIp = AUIDialog.FormatPrintf(pGameUI.GetStringFromTable(9345), curIpStr);
|
||||
|
||||
EventBus.Publish(new GameSession.ChatMessageEvent { context = textCurIp, channel = (byte)ChatChannel.GP_CHAT_SYSTEM });
|
||||
Debug.Log($"[Cuong] ShowAccountLoginInfo {textCurIp}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,11 +13,25 @@ namespace BrewMonster.UI
|
||||
[SerializeField] private GameObject addCharacterItemPrefab;
|
||||
[SerializeField] private RectTransform parentItems;
|
||||
[SerializeField] private Button createCharacterButton;
|
||||
[SerializeField] private Button _btnEnterGame;
|
||||
[SerializeField] private CreateCharacterScreen createCharacterScreen;
|
||||
|
||||
private CharacterItemUI _selectingCharacterItemUI;
|
||||
private Action<RoleInfo> _onClickItemChar;
|
||||
private Action<RoleInfo> _onCreateCharacterComplete;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
_btnEnterGame.onClick.AddListener(OnClickedEnterGame);
|
||||
_btnEnterGame.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
_btnEnterGame.onClick.RemoveListener(OnClickedEnterGame);
|
||||
_selectingCharacterItemUI = null;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (createCharacterButton != null)
|
||||
@@ -48,7 +62,7 @@ namespace BrewMonster.UI
|
||||
if (characterItemPrefab != null && parentItems != null)
|
||||
{
|
||||
CharacterItemUI item = Instantiate(characterItemPrefab, parentItems).GetComponent<CharacterItemUI>();
|
||||
item.InitItem(info, OnClickItemChar);
|
||||
item.InitItem(info, OnSelectCharacter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,6 +111,23 @@ namespace BrewMonster.UI
|
||||
}
|
||||
}
|
||||
|
||||
private void OnSelectCharacter(CharacterItemUI characterItemUI)
|
||||
{
|
||||
if (_selectingCharacterItemUI == characterItemUI)
|
||||
{
|
||||
return;
|
||||
|
||||
}
|
||||
if(_selectingCharacterItemUI!=null)
|
||||
{
|
||||
_selectingCharacterItemUI.SetFocus(false);
|
||||
}
|
||||
|
||||
_selectingCharacterItemUI = characterItemUI;
|
||||
_selectingCharacterItemUI.SetFocus(true);
|
||||
_btnEnterGame.gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
private void OnCreateCharacterClicked()
|
||||
{
|
||||
if (createCharacterScreen != null)
|
||||
@@ -126,5 +157,17 @@ namespace BrewMonster.UI
|
||||
|
||||
gameObject.SetActive(true);
|
||||
}
|
||||
|
||||
private void OnClickedEnterGame()
|
||||
{
|
||||
if (_selectingCharacterItemUI != null)
|
||||
{
|
||||
_onClickItemChar?.Invoke(_selectingCharacterItemUI.RoleInfo);
|
||||
}
|
||||
else
|
||||
{
|
||||
BMLogger.LogError("No role selected");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+36
-9
File diff suppressed because one or more lines are too long
@@ -0,0 +1,100 @@
|
||||
# Luồng Hoạt Động Của Hệ Thống Chat (C#)
|
||||
|
||||
Tài liệu này tổng hợp luồng xử lý của hệ thống Chat S2C và C2S trong client, dựa trên hai hàm cốt lõi `SendChatData` và `OnPrtcChatMessage` thuộc lớp `GameSession.cs`.
|
||||
|
||||
---
|
||||
|
||||
## 1. Luồng Gửi Tin Nhắn (C2S) - Hàm `SendChatData`
|
||||
|
||||
Hàm này được gọi khi người chơi nhập tin nhắn ở Local và muốn gửi lên Server (hoặc sử dụng vật phẩm liên quan đến Chat). Đặc biệt, **Server sẽ KHÔNG tự động gửi lại (echo) tin nhắn cho người gửi**, do đó client phải chủ động tự hiển thị tin nhắn của chính mình lên UI.
|
||||
|
||||
**Các bước xử lý:**
|
||||
|
||||
1. **Khởi tạo và đóng gói dữ liệu:**
|
||||
- Tạo gói tin C2S `publicchat` và thiết lập các thông số cơ bản (`Channel`, `Roleid` của người gửi).
|
||||
|
||||
2. **Xử lý đính kèm vật phẩm (nếu có):**
|
||||
- **Vật phẩm thẻ (`GENERALCARD_PACK`):** Nếu tin nhắn được gửi cùng một thẻ (card), hệ thống sẽ tìm trong túi đồ client (Client Pack) theo slot (`iSlot`), lấy ra `cardId` và chèn byte data lệnh `CHAT_GENERALCARD_COLLECTION` vào giao thức.
|
||||
- **Vật phẩm trang bị thông thường:** Nếu `iPack` và `iSlot` hợp lệ, đóng gói định dạng `CHAT_EQUIP_ITEM` gồm vị trí túi `where` và vị trí slot `index` chèn vào gói tin.
|
||||
|
||||
3. **Gửi gói tin lên Server:**
|
||||
- Tin nhắn chuỗi (`szMsg`) được mã hóa sang `UTF-16 LE` (Unicode trong C#) và lưu vào `Msg` (kiểu Octets).
|
||||
- Gọi `SendProtocol(p)` để đẩy dữ liệu xuống tầng Network và gửi đi.
|
||||
|
||||
4. **Hiển thị tin nhắn Local ngay lập tức:**
|
||||
- Xác định `nEmotionSet` (nếu có), ví dụ kênh **Super Far Cry** sẽ có hiệu ứng bong bóng đầu đặc biệt (trim 8 character cuối của text).
|
||||
- **Bong bóng đầu (Head Bubble):** Áp dụng nếu kênh thuộc dạng lân cận (`GP_CHAT_LOCAL`, `GP_CHAT_FARCRY`, `GP_CHAT_SUPERFARCRY`, `GP_CHAT_BATTLE`, `GP_CHAT_COUNTRY`).
|
||||
- Lấy tên Host Player, ghép chuỗi với định dạng text của hệ thống (sử dụng cố định `FIXMSG_CHAT`).
|
||||
- Gọi `EC_Game.GetGameRun().AddChatMessage(...)`: Hàm này sẽ đẩy dữ liệu lên UI Chat Box và tự động xử lý bong bóng trên đầu nhân vật.
|
||||
|
||||
---
|
||||
|
||||
## 2. Luồng Nhận Tin Nhắn (S2C) - Hàm `OnPrtcChatMessage`
|
||||
|
||||
Hàm này nhận giao thức `chatmessage` từ Server và xử lý việc hiển thị lên kênh chat, bong bóng đầu player/NPC.
|
||||
Vì hàm OnPrtcChatMessage đang quá lớn nên tôi chia ra thêm 1 class Chat_GameSession để xử lý các logic nhỏ.
|
||||
**Các bước xử lý:**
|
||||
|
||||
1. **Tiền xử lý và Lọc (Filter):**
|
||||
- Kiểm tra cấp độ người gửi qua `Chat_GameSession.ShouldBlockByLevel()`. Nếu bị chặn, hàm ngắt ngang và bỏ qua tin nhắn.
|
||||
- Tạo `EC_IvtrItem` (Chat Item) từ dải byte đính kèm (nếu có vật phẩm).
|
||||
- Lọc các tag mã hóa không hợp lệ thông qua `AUICommon.FilterInvalidTags`.
|
||||
- Chạy qua các policy chặn lọc hệ thống (`Chat_GameSession.PolicyResolver()`) để ra chuỗi tinh chỉnh cuối cùng (`szMsg`).
|
||||
|
||||
2. **Phân loại Channel và RoleID để xử lý:**
|
||||
|
||||
Hệ thống phân chia theo 3 nhóm luồng chính:
|
||||
|
||||
### Nhóm A: Broadcast, System, hoặc System Role (Srcroleid == 0)
|
||||
- Nếu `Channel` là `GP_CHAT_SYSTEM` và có `Srcroleid > 0`, tin nhắn thuộc các thông báo riêng biệt của cục bộ tính năng, được chia nhánh theo `Srcroleid` (Hardcode ID):
|
||||
- **ID = 1,2,3,4,6,7:** Bản tin Chiến trường (Battle Message).
|
||||
- **ID = 18..22:** Bản tin Đấu giá (Auction Message). Gọi `ChatMessageEvent` đưa lên kênh system.
|
||||
- **ID = 24:** Bản tin Nhiệm vụ (Task Message).
|
||||
- **ID = 29..45:** Bản tin Pháo đài, Lãnh thổ (Fortress Message).
|
||||
- **ID = 46..49:** Bản tin Quốc chiến (Country Battle).
|
||||
- **ID = 50..59:** Bản tin Vua (King Chat).
|
||||
- **ID = 60..64:** Bản tin PVP Bang hội (Faction PVP).
|
||||
*(Lưu ý: Một số hàm của luồng C++ đang bị ẩn/ẩn implementation, nếu cần data pending chưa có sẽ hoãn và chờ lần gọi lại (`bCalledagain`).)*
|
||||
- Nếu không thuộc các ID đặc biệt trên, hệ thống đơn giản là phát ra `ChatMessageEvent` đẩy thẳng tin nhắn lên luồng EventBus.
|
||||
|
||||
### Nhóm B: Instance Channel (`GP_CHAT_INSTANCE` & `Srcroleid == 1`)
|
||||
- Tin nhắn riêng của Phó bản, hiện tại được thiết kế để ném vào luồng `AddHeartBeatHint` ở UIMan.
|
||||
|
||||
### Nhóm C: Dành cho người chơi khác (Player) hoặc NPC
|
||||
*Sử dụng chuỗi định dạng lấy từ `FixedMsg` kết hợp tên người / NPC.*
|
||||
|
||||
- **Nếu là người chơi (`ISPLAYERID`):**
|
||||
- Request tên người chơi `GetPlayerName`.
|
||||
- **Thiếu Data:** Nếu không tìm thấy tên player trong cache, tin nhắn yêu cầu Server lấy tên (`AddChatPlayerID`) và **treo** giao thức chat này vào Pending Protoco (`AddElemForPendingProtocols`). Giao thức này sẽ tự kích hoạt lại ở Tick sau khi Server trả về tên.
|
||||
- **Có Data:** Xây dựng câu (kiểu `[Kênh] Player: Message`), gọi `AddChatMessage(...)` đẩy vào hộp thoại Chat và bắn bong bóng đầu tự động.
|
||||
|
||||
- **Nếu là NPC (`ISNPCID`):**
|
||||
- Tìm kiếm `CECNPC` từ danh sách `NPCMan`.
|
||||
- Dựng chuỗi bằng format `FIXMSG_CHAT2`.
|
||||
- Gọi `AddChatMessage()` cho chat panel và `EventBus.Publish(ChatMessageEvent)` cho UI liên quan.
|
||||
- Lọc riêng Name Flag trên đầu NPC, rồi gán nội dung bằng hàm `pNPC.SetLastSaidWords(szMsg)` để hiện Bubble Text trên mô hình 3D NPC.
|
||||
|
||||
---
|
||||
|
||||
## 3. Phân Tích Khác Biệt Giữa C++ và C# (Triển khai `OnPrtcChatMessage`)
|
||||
|
||||
Trong quá trình chuyển đổi (port) hệ thống Chat từ C++ sang C# (Unity), kiến trúc đã được thay đổi từ **mô hình liên kết chặt chẽ (Tight Coupling)** sang **mô hình hướng sự kiện (Event-Driven)** nhằm tách biệt hoàn toàn tầng Network và tầng UI/Logic Game.
|
||||
|
||||
Dưới đây là các điểm khác biệt chính:
|
||||
|
||||
| Tiêu chí | C++ (`EC_GameSession.cpp`) | C# Unity (`GameSession.cs` & `UIPlayer.cs`) |
|
||||
| :--- | :--- | :--- |
|
||||
| **Kiến trúc liên kết (Giao tiếp với mô hình 3D)** | Tầng Network gọi trực tiếp vào hệ thống quản lý Game World. Code chủ động tìm kiếm player: `CECPlayer *pPlayer = GetWorld()->GetPlayerMan()->GetPlayer(...)` rồi gọi trực tiếp hàm `pPlayer->SetLastSaidWords(strTemp, p->emotion, pItem);`. | Gọi thông qua kiến trúc kênh Pub/Sub: `EventBus.PublishChannel(p.Srcroleid, new EventChatMessageOnTopPlayer(p.Srcroleid, strMsg));`. Tầng Network không cần biết đối tượng 3D có tồn tại hay không. |
|
||||
| **Bong bóng Chat trên đầu (Head Bubble)** | Đối tượng `CECPlayer` tự tính toán, lưu trữ Text và dựa vào Tick update trung tâm C++ để hiển thị/tắt text sau một khoảng thời gian. | Giao diện hiển thị `UIPlayer.cs` (gắn trên Prefab nhân vật) tự đăng ký sự kiện (`EventBus.SubscribeChannel`). Khi nhận event, tự đổi chuỗi `TextMeshProUGUI`, hiện Text và gọi một `UniTask` (`HideChatAsync`) độc lập để tự động tắt sau 5 giây. |
|
||||
| **Xử lý Thread/Đa luồng** | Toàn bộ Network và Logic xử lý trên chung một luồng chính đồng bộ. | Tầng Network (nhận Packet) và tầng UI hiển thị Unity có thể bất đồng bộ. Vì vậy C# dùng `ChatThreadDispatcher.Instance.Post(...)` trong `UIPlayer.SetChatMessage` để đồng bộ an toàn việc gán giá trị UI lên luồng chính của Unity. |
|
||||
| **Bảo trì / Mở rộng** | Gắn chặt UI với Data Network. Nếu UI thay đổi, sửa Network code. | Decoupled (Giảm kết dính). Việc hiển thị UI chat (khung Chat Panel lẫn Head Bubble trên đầu nhân vật) hoạt động độc lập và chỉ "lắng nghe" dữ liệu. |
|
||||
|
||||
**Ví Dụ Chi Tiết (Luồng Head Bubble Player):**
|
||||
* **C++:** Trong `OnPrtcChatMessage`, code thực hiện:
|
||||
`pPlayer->SetLastSaidWords(strTemp, p->emotion, pItem);`
|
||||
Tức là bắt ép đối tượng thực hiện cập nhật UI.
|
||||
* **C#:** Trong `GameSession.cs` (hoặc bên trong `AddChatMessage`), hệ thống gọi:
|
||||
`EventBus.PublishChannel(p.Srcroleid, new EventChatMessageOnTopPlayer(p.Srcroleid, strMsg));`
|
||||
Tương ứng bên kia, trong `UIPlayer.cs` chạy ở hàm `Start()`:
|
||||
`EventBus.SubscribeChannel<EventChatMessageOnTopPlayer>(hostplayer.GetCharacterID(), SetChatMessage);`
|
||||
Khi event kích hoạt, hàm `SetChatMessage` sẽ nhận Context và gỡ nó ra gán vào Text Mesh UI một cách an toàn.
|
||||
Reference in New Issue
Block a user