• hainv hainv

    9-Slice Trimmer là package để optimize Sprite hỗ trợ 9-Slice
    Để mở cửa sổ 9-Slice Trimmer. Chọn KH-Tools/Nine-Slice Trimmer trên thanh Menu
    4af61b63-eb82-44c5-b026-bed8f5c58831-image.png

    Cửa sổ của tool như sau:
    9aaa5257-011a-4a07-9b42-d4380e7205e9-image.png

    Hướng dẫn sử dụng:
    Bước 1: Chọn ảnh cần cắt và config vị trí cần slice
    80661fa4-2a51-4c26-9382-54c35934e2d1-image.png

    Bước 2: Bật Read/Write option và Apply
    cd3aa856-27ce-48ac-b3a1-bdfde826622d-image.png

    Bước 3: Kéo Sprite vào Sprite Texture trong tool
    95d4f722-13d5-4354-8416-e76bcf322a1f-image.png

    Bước 4: Bấm Preview để kiểm tra ảnh sau khi cắt đã đúng chưa
    5c63aa72-7688-45c5-ad9c-2f8f20f1e926-image.png

    Bước 5: Bấm Trim & Save để cắt Sprite
    2cda11e2-f615-419c-844f-f3acf2f17e17-image.png

    Bước 6: Tắt Read/Write trong ảnh vừa tạo
    Ảnh mới nhận được
    59092513-ac67-40aa-b92a-d28c41a3d013-image.png

    Tài liệu tham khảo thêm: https://github.com/KingHipUnity/Unity-NineSliceTrimmer/blob/main/README.md

    posted in Monkey Stories 2.0 read more
  • hainv hainv

    Viết thêm Cheat vào file CheatMethodHandle.cs
    01060da7-9512-4f97-8e94-29cf76a25a9f-image.png
    Quy tắc đặt tên Cheat mới

    _<Section> _<Tên Cheat>
    trong đó các Cheat có cùng Section sẽ được gộp vào chung 1 mục

    Cheat hỗ trợ 2 loại hàm void và biến static bool
    ví dụ

     public void _MS2_ShowLog()
     {
         Debug.Log("MS2 Show Log Clicked");
     }
    
     public static bool _IsDemoBool
     {
         get {
             return PlayerPrefs.GetInt("DebugKey_IsDemoBool", 0) == 1;
         }
         set {
             PlayerPrefs.SetInt("DebugKey_IsDemoBool", value ? 1 : 0);
         }
     }
    

    Để sử dụng Cheat, bấm vào button đầu khỉ ở ngoài màn hình
    611a6701-faf7-401d-af18-a2b49e07dae8-image.png

    aaaeecb2-2e3c-4dea-80b7-914643ed9619-image.png

    Click vào Section để mở ra các Cheat trong cùng 1 section
    Click vào từng Cheat để thực hiện hàm cheat

    posted in Monkey Stories 2.0 read more
  • hainv hainv

    Script Build được viết trong File MKBuild.cs

    • Đối với build bằng Unity Editor. Chọn Build trên thanh menu và chọn mục cần build
      da5e8199-4b6f-4646-bfc8-c469a67f32a3-image.png
      Sau khi build xong output file sẽ ở folder Build ( ngang hàng với Folder Assets )
      c25e56eb-7a91-4b75-8d0c-ab61fa0675b3-image.png
      Định dạng file APK: Android_yyyyMd_Hm.apk

    • Đối với sử dụng trong pipeline CI/CD
      Sử dụng Command:
      <Path To Unity Editor> -projectPath <Path To Project> -executeMethod Monkey.BuildTool.Editor.MKBuild.Build -outputPath <Path Output> -buildPlatform <Platform> -isProd true -batchmode -quit
      Platform: bao gồm: Android, iOS
      isProd: true hoặc false

    Ví dụ

    /Applications/Unity/Hub/Editor/2022.3.57f1/Unity.app/Contents/MacOS/Unity -projectPath /Users/monkey/Workspace/monkeyx_ci/monkey_story_2 -executeMethod Monkey.BuildTool.Editor.MKBuild.Build -buildPlatform iOS -isProd true -outputPath /Users/monkey/Workspace/monkeyx_ci/build/ios -batchmode -quit
    

    posted in Monkey Stories 2.0 read more
  • hainv hainv

    Các bước thực hiện để có thể test game bằng Game Tool
    Bước 1: Xoá các thành phần không cần thiết trong game nếu có
    3eec8679-69a8-4824-a028-6addaef20bbf-image.png
    128dd669-a838-4334-986a-3427f9ec9bf0-image.png
    EventSystem, SoundManager, AudioListener đã được load trong Game Tool nên không cần để trong scene game.

    Bước 2: Gán Addressable cho Scene game
    2.1: Mở cửa sổ Addressables Groups bằng cách sau:
    91e26b1b-6e99-419d-8a04-c0a5df57fdda-image.png
    2.2: Kéo Scene game vào group Games trong Addressable
    8e5bdf46-8966-4b1d-b855-7b674d884baa-image.png
    2.3: Chuột phải vào Addressable vừa kéo chọn Simplify Addressable Name
    b612b11b-a203-46d1-8968-8f9b6232ba60-image.png

    Bước 3: Thêm Game Config trong File GameConfigSO trong đường dẫn: Assets/5.Manager/GameTool/Data
    2470c00a-9ccf-4cc3-bcf4-f8f06f770403-image.png
    ở mục Addressable chọn scene vừa tạo
    faa31381-1116-476c-a790-e3c209657a67-image.png

    Bước 4: Chạy Scene GameTool và test lại.
    4f80f3ff-aaf3-499d-bfdb-ce7ee0c7bfba-image.png

    posted in Monkey Stories 2.0 read more
  • hainv hainv

    Hướng Dẫn Quy Tắc Sử Dụng Git Trong Unity Project

    1. Quy tắc đặt tên Branch

    Việc đặt tên branch có hệ thống giúp quản lý dễ dàng hơn và tránh nhầm lẫn trong quá trình phát triển. Dưới đây là quy tắc đặt tên branch áp dụng cho dự án Unity:

    1.1. Các loại branch chính

    • main: Chứa phiên bản ổn định của dự án, chỉ merge code đã kiểm thử kỹ lưỡng.
    • develop: Nhánh chính để phát triển, nơi tập hợp các tính năng trước khi merge vào main.
    • [user]/feature/: Dành cho các tính năng mới.
    • [user]/bugfix/: Dành cho các sửa lỗi.
    • [user]/hotfix/: Sửa lỗi khẩn cấp trên main.

    1.2. Cách đặt tên branch

    Khi dự án có nhiều thành viên, mỗi người nên có namespace riêng để dễ dàng xác định ai đang làm việc trên nhánh nào.

    Cấu trúc chung:

    [tên-thành-viên]/[loại-branch]/[mô-tả-ngắn-gọn]
    

    Ví dụ:

    • hainv/feature/weapon-system
    • hainv/bugfix/fix-ui-button
    • hainv/hotfix/crash-loading-screen

    Việc sử dụng tên thành viên giúp dễ dàng theo dõi ai chịu trách nhiệm cho từng nhánh và tránh trùng lặp tên branch.

    2. Quy tắc Commit

    Commit nên rõ ràng, ngắn gọn và có ý nghĩa để dễ theo dõi lịch sử thay đổi.

    Chỉ commit những file mà mình thay đổi

    2.1. Cấu trúc commit message

    [Loại commit]: [Mô tả ngắn gọn]
    
    [Giải thích chi tiết (nếu cần)]
    

    Loại commit phổ biến:

    • feat: Thêm tính năng mới
    • fix: Sửa lỗi
    • refactor: Cải tiến code không làm thay đổi tính năng
    • docs: Cập nhật tài liệu
    • style: Thay đổi không ảnh hưởng logic (format, tab, dấu cách)

    Ví dụ:

    feat: Thêm hệ thống quản lý vũ khí
    
    - Thêm cơ chế trang bị vũ khí
    - Thêm animation thay đổi vũ khí
    
    fix: Sửa lỗi nhân vật không thể nhảy khi đang chạy
    
    - Cập nhật input system
    - Điều chỉnh logic kiểm tra trạng thái nhân vật
    

    3. Merge Flow

    Việc merge code cần tuân theo một quy trình nhất định để tránh lỗi và đảm bảo tính ổn định.

    3.1. Quy trình Merge

    1. Tạo branch mới từ develop hoặc main trong trường hợp hotfix.
    2. Commit & Push: Sau khi hoàn thành công việc, commit code và push lên remote repository.
    3. Tạo Pull Request (PR): Yêu cầu merge vào develop hoặc main.
    4. Code Review: Thành viên nhóm kiểm tra code và đưa ra phản hồi.
    5. Fix review (nếu có): Chỉnh sửa theo góp ý.
    6. Merge: Gộp commit nếu cần trước khi merge vào nhánh chính.
    7. Xóa branch (sau 3 bản release, branch của thành viên nào thì thành viên đó sẽ chịu trách nhiệm xoá branch của mình).

    3.2. Các quy tắc khi Merge

    • Chỉ merge vào main từ develop hoặc hotfix/*.
    • Các tính năng mới nên merge vào develop trước khi lên main.
    • Không merge trực tiếp vào main.
    • Luôn đảm bảo code đã được test kỹ trước khi merge.

    4. Lưu ý Khi Dùng Git Trong Unity

    • Sử dụng .gitignore: Yêu cầu file .gitignore có các mục như Library/, Temp/, Logs/, *.csproj, *.unitypackage, *.sln, *.userprefs để tránh đẩy file không cần thiết lên repository.
    • Tránh merge conflict: Luôn pull bản mới nhất trước khi làm việc để tránh xung đột.
    • Commit thường xuyên: Giúp theo dõi tiến trình dễ dàng và giảm thiểu mất mát dữ liệu.

    Tài liệu này giúp chuẩn hóa quy trình làm việc với Git trong dự án Unity, giúp nhóm làm việc hiệu quả và giảm thiểu lỗi khi quản lý mã nguồn.

    posted in Chung read more
  • hainv hainv

    Coding Convention cho Unity - C#

    1. Quy tắc đặt tên (Naming Conventions)

    1.1 Biến và hằng số

    • Biến cục bộ (Local variables): sử dụng camelCase, bắt buộc có access modifier.
      private int playerScore;
      protected float moveSpeed;
      
    • Biến thành viên (Fields):
      • Luôn có access modifier, không dùng _ trước biến private.
      private int health;
      
      • Nếu là public, protected dùng PascalCase và bắt buộc quy định { get; set; }.
      public int MaxHealth { get; set; }
      [SerializeField] private float moveSpeed;
      
    • Hằng số: Dùng toàn bộ chữ hoa với _ giữa các từ.
      public const float GRAVITY = 9.81f;
      private readonly int MAX_LIVES = 3;
      

    1.2 Hàm và phương thức (Methods)

    • Dùng PascalCase.
      void MovePlayer();
      int CalculateScore();
      

    1.3 Class, Struct và Interface

    • Class & Struct: PascalCase.
      public class PlayerController {}
      public struct PlayerStats {}
      
    • Interface: Bắt đầu với chữ I, dùng PascalCase.
      public interface IDamageable {}
      

    1.4 Namespace

    • Dùng PascalCase, nên có cấu trúc theo thư mục.
      namespace Game.Core {}
      namespace Game.UI {}
      

    1.5 Enum

    • Dùng PascalCase và gán giá trị mặc định.
      public enum GameState { Idle = 0, Playing = 1, Paused = 2, GameOver = 3 }
      

    2. Quy tắc định dạng mã (Formatting)

    2.1 Dấu ngoặc nhọn {}

    • Mở dấu { trên cùng dòng với khai báo.
      if (isRunning) {
        Run();
      }
      
    • Với khối code một dòng, luôn sử dụng {}.
      if (isJumping) {
        Jump();
      }
      

    2.2 Khoảng trắng

    • Dùng 2 dấu cách (không dùng tab).
    • Giữa các toán tử, thêm khoảng trắng.
      int sum = a + b;
      
    • Không có khoảng trắng trước dấu ( trong phương thức.
      void Attack(int damage) {}
      

    3. Quy tắc tổ chức mã (Code Organization)

    3.1 Thứ tự trong Class

    • Fields
    • Properties
    • Unity Methods (Start, Update, FixedUpdate, LateUpdate, ...)
    • Methods (Public → Private)
    • Event Handlers

    Ví dụ:

    public class Player : MonoBehaviour {
      // Fields
      private int health;
    
      // Properties
      public int Health { get; set; }
    
      // Unity Methods
      private void Start() {
        Debug.Log("Game Started");
      }
    
      private void Update() {
        Move();
      }
    
      // Methods
      public void TakeDamage(int amount) {
        health -= amount;
      }
    }
    

    3.2 Quy tắc sử dụng MonoBehaviour

    • Tránh sử dụng Find(), FindObjectOfType() trong Update() vì hiệu suất kém.
    • Dùng SerializeField thay vì public cho biến cần hiển thị trên Inspector.

    4. Bình luận và Tài liệu (Comments & Documentation)

    • Sử dụng /// để thêm mô tả.
    /// <summary>
    /// Di chuyển người chơi theo hướng chỉ định.
    /// </summary>
    /// <param name="direction">Hướng di chuyển.</param>
    public void Move(Vector3 direction) {}
    
    • Chỉ bình luận những đoạn code khó hiểu hoặc cần giải thích.
    // Giảm máu của người chơi khi bị tấn công
    health -= damage;
    

    5. Xử lý sự kiện và delegate

    • Tên event dùng PascalCase, có hậu tố Event.
    public event Action OnPlayerDeathEvent;
    
    • Khi gọi event, kiểm tra null.
    OnPlayerDeathEvent?.Invoke();
    

    6. Sử dụng ScriptableObject

    • Dùng ScriptableObject để lưu dữ liệu chung thay vì Singleton.
    [CreateAssetMenu(fileName = "GameSettings", menuName = "Game/GameSettings")]
    public class GameSettings : ScriptableObject {
      public float volume;
      public int maxEnemies;
    }
    

    7. Best Practices

    • Sử dụng readonly hoặc const cho các biến không thay đổi.
    • Tránh sử dụng static trừ khi cần thiết.
    • Tránh sử dụng string so sánh trực tiếp (==), thay vào đó dùng enum hoặc nameof.
    • Sử dụng Linq cẩn thận, tránh dùng trong Update().
    • Luôn kiểm tra null trước khi truy cập đối tượng.
    • Sử dụng LogMe thay vì Debug

    8. Hướng dẫn import Convention Rule cho Visual Studio 2019 và Rider

    Visual Studio 2019

    1. Mở Visual Studio 2019.
    2. Vào ToolsOptions.
    3. Chọn Text EditorC#Code Style.
    4. Chỉnh sửa theo quy tắc đặt tên và format đã đề cập.
    5. Lưu lại và áp dụng.

    Rider

    1. Mở Rider.
    2. Vào FileSettings.
    3. Chọn EditorCode StyleC#.
    4. Cấu hình quy tắc đặt tên, format theo convention.
    5. Lưu lại và áp dụng.

    Tài liệu này giúp duy trì mã nguồn thống nhất, dễ bảo trì và tối ưu hiệu suất trong Unity C#. Việc tuân theo coding convention sẽ giúp dự án của bạn dễ đọc, dễ mở rộng và chuyên nghiệp hơn.

    posted in Chung read more
  • hainv hainv

    Support Base for Monkey Junior 5.0

    Core Structure:

    Support System: Management of all the services
    We implemented multiple Services to Support Monkey Junior 5.0

    How to use the Support System:
    SupportSystem class is a Singleton class and DontDestroyOnScene Object.
    Support System must attached to the GameObject and Execute before any class.
    eb1e52b5-22a7-4246-979b-e62e08b9fd5f-image.png

    The services will automatically initialize.
    To use the Service, follow the code

     IDownloadService DownloadService = SupportSystem.Instance[SupportSystem.ServiceIDs.DownloadService] as IDownloadService;
    

    Explanation:
    IDownloadSerivce: Interface of Service
    SupportSystem.ServiceIDs.DownloadService: Service type name


    Services:

    1. UpdateService: Manage the update method of the MonoBehaviour class
    Based on the best practice: Update in every class is worse on the performance.
    https://blog.unity.com/engine-platform/10000-update-calls
    So Update Service is the solution for that:

    1.1. Sample:

    using Monkey.Support;
    using UnityEngine;
    
    public class TestUpdateServiceScript : MonoBehaviour, IUpdate
    {
        public void OnDisable()
        {
            this.RemoveMe();
        }
    
        public void OnEnable()
        {
            this.AddMe();
        }
    
        public void UpdateMe()
        {
            Debug.Log("Update Me: " + Time.realtimeSinceStartup);
        }
    }
    
    

    1.2. Explanation:

    • The class that uses UpdateService must inherit IUpdate interface
    • The UpdateMe method will be called every frame.
    • UpdateService will work for both the MonoBehaviour class and the normal class.
    • Manage list classes active in Update Service:
      77f5d749-a64a-4c6d-b513-cb9404bfc2e7-image.png

    2. UserDataService: Manage the User Data, Profile Data, and Profile Setting of Users. To use UserDataService, call from Interface IUserDataService.

    2.1. Interface:

    public interface IUserDataService
        {
            /// <summary>
            /// Get Profile Data
            /// </summary>
            /// <returns>UserProfileModel</returns>
            public UserProfileModel GetProfile();
    
            /// <summary>
            /// Get User Data
            /// </summary>
            /// <returns>UserModel</returns>
            public UserModel GetUser();
    
            /// <summary>
            /// Get All Profile Settings
            /// </summary>
            /// <returns>List of ProfileSettingModel</returns>
            public List<ProfileSettingModel> GetProfileSettings();
    
            /// <summary>
            /// Get Specific Profile Setting
            /// </summary>
            /// <param name="setting">Setting Name</param>
            /// <returns>ProfileSettingModel</returns>
            public ProfileSettingModel GetProfileSetting(string setting);
    
        }
    

    2.2. Sample:

    var userService = SupportSystem.Instance[SupportSystem.ServiceIDs.UserDataService] as IUserDataService;
    var user = userService.GetUser();
    

    3. DataSyncService: Manage the Course Data, and Award Data (Pet Items, Sticker, Coin). To use UserDataService, call from Interface IDataSyncService.
    3.1. Interface:

    public interface IDataSyncService
        {
            #region Data Course
            /// <summary>
            /// Get Lesson Data
            /// </summary>
            /// <param name="course">Course ID</param>
            /// <param name="lessonId">Lesson ID</param>
            /// <returns></returns>
            LessonReportDataSync GetLessonData(TYPE_COURSE course, string lessonId);
            /// <summary>
            /// Get Course Data
            /// </summary>
            /// <param name="course">Course ID</param>
            /// <returns></returns>
            DataCourseSyncModel GetCourseData(TYPE_COURSE course);
            /// <summary>
            /// Update Lesson Data
            /// </summary>
            /// <param name="course">Course ID</param>
            /// <param name="lesson">New Lesson Data</param>
            void UpdateLessonData(TYPE_COURSE course, LessonReportDataSync lesson);
            #endregion
    
            #region Pet&Award
            /// <summary>
            /// Get Current Coin
            /// </summary>
            /// <returns></returns>
            int GetCoin();
            /// <summary>
            /// Set Coin Data
            /// </summary>
            /// <param name="coinChanged">Coin Changed</param>
            void SetCoin(int coinChanged);
            /// <summary>
            /// Get Theme Data
            /// </summary>
            /// <param name="themeId">Theme ID</param>
            /// <returns></returns>
            DataThemesModel GetTheme(string themeId);
            /// <summary>
            /// Add new Sticker
            /// </summary>
            /// <param name="themeId">Theme ID</param>
            /// <param name="stickerId">Sticker ID</param>
            void AddSticker(string themeId, int stickerId);
            /// <summary>
            /// Get All Pet Items
            /// </summary>
            /// <returns></returns>
            List<PetItem> GetPetItems();
            /// <summary>
            /// Get List Used Pet Item
            /// </summary>
            /// <returns></returns>
            List<int> GetUsedItems();
            /// <summary>
            /// Check Pet Item is Used
            /// </summary>
            /// <param name="itemId">Item ID</param>
            /// <returns></returns>
            bool IsUsedItem(int itemId);
            /// <summary>
            /// Get List New Pet Items
            /// </summary>
            /// <returns></returns>
            List<int> GetNewItems();
            /// <summary>
            /// Check Pet Item is New
            /// </summary>
            /// <param name="itemId"></param>
            /// <returns></returns>
            bool IsNewItem(int itemId);
            /// <summary>
            /// Add a Pet Item
            /// </summary>
            /// <param name="ItemId">Item ID</param>
            /// <param name="isNew">Is tag New Item, for the default IsNew = false</param>
            void AddItem(int ItemId, bool isNew = false);
            /// <summary>
            /// Change Pet Item State: Used, Unuse
            /// </summary>
            /// <param name="ItemId">Item ID</param>
            /// <param name="isUsed">Is Item Used</param>
            void ChangeItemState(int ItemId, bool isUsed);
            #endregion
        }
    

    3.2. Sample:

    var syncData = SupportSystem.Instance[SupportSystem.ServiceIDs.DataSyncService] as IDataSyncService;
    syncData.GetCourseData(TYPE_COURSE.MJ5);
    

    4. EventTrackingService: Send tracking, events, data to React Native. To use UserDataService, call from Interface IEventTrackingService.

    4.1. Interface

     public interface IEventTrackingService
        {
            /// <summary>
            /// Push Event to React Native to Tracking, Sync Data
            /// </summary>
            /// <param name="nameEvent">Event name</param>
            /// <param name="typeEvent">Event Type</param>
            /// <param name="properties">Properties</param>
            /// <param name="typeToPushEvent">Event Type: AWS, CLEVERTAP, AWS_AND_CLEVERTAP, AIRBRIDGE</param>
            void PushEvent(string nameEvent, string typeEvent, Dictionary<string, object> properties, TYPE_EVENT typeToPushEvent = TYPE_EVENT.AWS);
        }
    

    4.2. Sample

    var trackingService = SupportSystem.Instance[SupportSystem.ServiceIDs.EventTrackingService] as IEventTrackingService;
    Dictionary<string, object> properties = new Dictionary<string, object>() {
                { "completed", complete},
                { "time_on_screeen", endTimeLesson - startTimeLesson},
                { "age", UserManager.instance.currentProfile.Age}
            };
    trackingService.PushEvent("mx_learn_AI_lesson", EnvironmentConfig.awsLearnLesson, properties, TYPE_EVENT.CLEVERTAP);
    

    5. AddressableService: Download Game assets and course assets. To use UserDataService, call from Interface IAddressableService.

    5.1. Interface

    public interface IAddressableService
        {
            /// <summary>
            /// Download Addressable Group
            /// </summary>
            /// <param name="groupName">Group Name</param>
            /// <param name="callback">Callback when Download finished</param>
            /// <param name="progress">Callback the progress</param>
            /// <param name="total_retry">No need to change the value</param>
            /// <returns></returns>
            IEnumerator DownloadGroup(string groupName, Action<bool> callback, Action<float> progress = null, int total_retry = 0);
    
            void LoadAssets<T>(string asset_name, Action<AsyncOperationHandle<T>> callback) where T : UnityEngine.Object;
    
            /// <summary>
            /// Check when Addressable service ready
            /// </summary>
            /// <returns></returns>
            bool IsServiceActive();
        }
    

    5.2. Sample

    var AddressableService = SupportSystem.Instance[SupportSystem.ServiceIDs.AddressableService] as IAddressableService;
    yield return new WaitUntil(() => AddressableService.IsServiceActive());
    yield return AddressableService.DownloadGroup("lrc", (success)=> {
          Debug.Log("Download Success? " + success);
    }, (progress)=> {
          Debug.Log("Progress: " + progress);
    });
    

    6. DownloadService: Manage the Download process for Assetbundle, words, and lesson data. To use DownloadService, call from Interface IDownloadService.

    6.1. Interface

    public interface IDownloadService
        {   
            /// <summary>
            /// Download a file in the background.
            /// </summary>
            /// <param name="info"> Info item download </param>
            public void DownLoadFileInBackGround(ItemDownload info);
            /// <summary>
            ///  Download list files in the background.
            /// </summary>
            /// <param name="list_info"> List info item download </param>
            /// <param name="sucessCallBack"> Call back when successful download </param>
            /// <param name="progressCallBack"> Call back while downloading, this call back return percent </param>
            /// <param name="errorCallBack"> Call back when download fail, this call back return a message error </param>
            public void DownLoadListFileInBackGround(List<ItemDownload> list_info, Action<object> sucessCallBack, Action<object> progressCallBack, Action<object> errorCallBack);
            /// <summary>
            /// Download a file in the background by priority.
            /// </summary>
            /// <param name="info">Info item priority download</param>
            public void DownLoadFilePriority(ItemDownload info);
            /// <summary>
            /// Download list files in the background by priority.
            /// </summary>
            /// <param name="list_info"> List info item priority download </param>
            /// <param name="sucessCallBack"> Call back when successful download </param>
            /// <param name="progressCallBack"> Call back while downloading, this call back return percent </param>
            /// <param name="errorCallBack"> Call back when download fail, this call back return a message error </param>
            public void DownLoadListFilePriority(List<ItemDownload> list_info, Action<object> sucessCallBack, Action<object> progressCallBack, Action<object> errorCallBack);
            /// <summary>
            /// Download all files bundle words in Lesson.
            /// </summary>
            /// <param name="idLesson"> Id of lesson </param>
            /// <param name="sucessCallBack"> Call back when successful download </param>
            /// <param name="progressCallBack"> Call back while downloading, this call back return percent </param>
            /// <param name="errorCallBack"> Call back when download fail, this call back return a message error </param>
            public void DownLoadWordsInLesson(int idLesson, Action<object> sucessCallBack, Action<object> progressCallBack, Action<object> errorCallBack);
            /// <summary>
            ///  DownLoad file addressable by name addressable
            /// </summary>
            /// <param name="nameAddressable"> Name of addressable </param>
            /// <param name="sucessCallBack"> Call back when successful download </param>
            /// <param name="progressCallBack"> Call back while downloading, this call back return percent </param>
            /// <param name="errorCallBack"> Call back when download fail, this call back return a message error </param>
            public void DownLoadAddressable(string nameAddressable, Action<object> sucessCallBack, Action<object> progressCallBack, Action<object> errorCallBack);
            /// <summary>
            /// Get link host download file bundle word in course.
            /// </summary>
            /// <returns> Return link host link host download file bundle word </returns>
            public string GetLinkDownloadWord();
            /// <summary>
            /// Get link host download file zip activity in course.
            /// </summary>
            /// <returns> Return link host link host download file zip activity </returns>
            public string GetLinkDownloadAct();
        }
    

    6.2. Sample

    var downloadService = SupportSystem.Instance[SupportSystem.ServiceIDs.DownloadService] as IDownloadService;
    downloadService.GetLinkDownloadAct();
    

    7. Popup Service: Manage the Popups in the game, Push and Pop the Popup on scene. To use PopupService, call from Interface IPopupService.

    7.1. Interface

    public interface IPopupService
        {
            /// <summary>
            /// Show popup by name class
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="data"></param>
            /// <param name="showType"></param>
            /// <param name="actionShow"></param>
            /// <returns> return popup </returns>
            public T Show<T>(object data = null, ShowType showType = ShowType.DissmissCurrent, Action actionShow = null) where T : Panel;
            /// <summary>
            /// Close popup by name class
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="data"></param>
            /// <param name="actHide"></param>
            public void Hide<T>(object data = null, Action actHide = null) where T : Panel;
            /// <summary>
            /// Close all popups
            /// </summary>
            /// <param name="actHideAll"></param>
            public void HideAll(Action actHideAll = null);
        }
    

    7.2. Sample

    public class PopupTestService : Panel
    {
        public override void Hide(object data = null, Action actionHide = null)
        {
            base.Hide(data, actionHide);
        }
    
        public override void Show(object data = null, bool duplicated = false, Action actionShow = null)
        {
            base.Show(data, duplicated, actionShow);
        }
    
        public void OnClickBtnClose()
        {
            Hide(null, () => { Debug.LogError("OnClickBtnClose"); });
        }
    
        public void OnClickBtnOpenPopup2()
        {
            var popup = SupportSystem.Instance[SupportSystem.ServiceIDs.PopupService] as IPopupService;
            popup.Show<PopupTestService2>(null, PopupService.ShowType.NotHide);
        }
    }
    

    8. Assetbundles Service: Manager the Asset Bundle and get data game. To use AssetbundlesService, call interface IAssetbundlesService..

    8.1. Interface

    public interface IAssetbundlesService
        {
            /// <summary>
            /// Get Data Game Primitive
            /// </summary>
            /// <param name="dictWordInforDetail"> Dictionary info word detail with key is link down load word and value is WordInforDetail </param>
            /// <param name="listWord"> List word model in file word.json </param>
            /// <returns> Dictionary<int, DataGamePrimitive> </returns>
            public Task<Dictionary<int, DataGamePrimitive>> GetDataGamePrimitive(Dictionary<string, WordInforDetail> dictWordInforDetail, List<ListWordModel> listWord);
            /// <summary>
            /// Get asset in bundle by type T
            /// </summary>
            /// <typeparam name="T"> Type asset </typeparam>
            /// <param name="bundle_name"> Name bundle </param>
            /// <param name="asset_name"> Name asset </param>
            /// <param name="local_path_file"> Path bundle in storage device </param>
            /// <param name="on_done"> Action invoke when get asset complete </param>
            /// <param name="on_error"> Action invoke when get asset fail </param>
            /// <returns> Asset with type T </returns>
            public Task<T> ResourceGetAssetInBundle<T>(string bundle_name, string asset_name, string local_path_file, string link_download, Action<object> on_done = null, Action<object> on_error = null) where T : UnityEngine.Object;
        }
    

    8.2. Sample

    
     var assetbundleService = SupportSystem.Instance[SupportSystem.ServiceIDs.AssetbundleService] as IAssetbundlesService;
    
            string linkBundle = "https://monkeymedia.vcdn.com.vn/App/uploads/course_install/bundle/hdr/ios/";//course.d.w_b;
            string linkWord = "https://vnmedia2.monkeyuni.net/App/zip/hdr/word_bundle/ios/";//course.d.w_b;
            string bundle_name = "course_install_ai_speaking_v2_78_1716429352.bundle";
            string asset_name = "course_installation.json";
            string local_path = $"{Ultis.persistentDataPath}/zips/{bundle_name}";
            var json = await assetbundleService.ResourceGetAssetInBundle<TextAsset>(bundle_name, asset_name, local_path, linkBundle + bundle_name, 
                (object d) => { Debug.LogError("Complete" + d?.ToString());}, (object d) => { Debug.LogError("Fail" + d?.ToString()); });
    
    

    posted in Base read more