ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 07/26 Assetbundle 에셋번들
    게임 네트워크 프로그래밍 2021. 7. 26. 15:27

    프로젝트 생성

    Assetbundle

     

    에셋을 받아 하이어라키 창에 가져와 언팩

     

     

    Resources > Prefabs 폴더 생성하고

    프리팹 넣기

     

     

     

    스크립트 작성

     

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEditor;
    using System.IO;
    
    public class CreateAssetBundles
    {
        [MenuItem("Assets/Build AssetBundles")]
        static void BuildAllAssetBundles()
        {
            string path = "Assets/AssetBundles";
            if(!Directory.Exists(path))
            {
                Directory.CreateDirectory(path);
            }
            BuildPipeline.BuildAssetBundles(path, BuildAssetBundleOptions.None, BuildTarget.Android);
        }
    }

     

     

     

     

     

    App

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class App : MonoBehaviour
    {
    
        void Start()
        {
            StartCoroutine(
                AssetManager.instance.LoadFromMemoryAsync("Assets/AssetBundles/characters", (bundle) => {
                    Debug.LogFormat("bundle: {0}", bundle);
                    var prefab = bundle.LoadAsset<GameObject>("ch_01_01");
                    var model = Instantiate<GameObject>(prefab);
                }));
    
        }
    }

    AssetManager

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using System.IO;
    
    public class AssetManager : MonoBehaviour
    {
        public static AssetManager instance;
    
        private void Awake()
        {
            AssetManager.instance = this;
        }
    
        public IEnumerator LoadFromMemoryAsync(string path, System.Action<AssetBundle> callback)
        {
            //파일을 바이트배열로 읽어서 비동기 방식으로 로드 한다 
            byte[] binary = File.ReadAllBytes(path);
            Debug.Log(binary.Length);
            AssetBundleCreateRequest req = AssetBundle.LoadFromMemoryAsync(binary);
            yield return req;
            callback(req.assetBundle);
        }
    
    }

     

     

     

     

    AssetBundle Browser 사용해보기

    https://docs.unity3d.com/Manual/AssetBundles-Browser.html

     

    Unity - Manual: Unity Asset Bundle Browser tool

    AssetBundle Download Integrity and Security Unity Asset Bundle Browser tool You can use the Asset Bundle Browser to view and edit the configuration of asset bundles in your Unity project. For more information, see the Unity Asset Bundle Browser documentati

    docs.unity3d.com

     

     

     

     

     

     

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using System.IO;
    using UnityEngine.Networking;
    using System.Text;
    
    public class AssetManager : MonoBehaviour
    {
        public static AssetManager instance;
    
        private void Awake()
        {
            AssetManager.instance = this;
        }
    
        public IEnumerator LoadFromMemoryAsync(string path, System.Action<AssetBundle> callback)
        {
            //파일을 바이트배열로 읽어서 비동기 방식으로 로드 한다 
            byte[] binary = File.ReadAllBytes(path);
            Debug.Log(binary.Length);
            AssetBundleCreateRequest req = AssetBundle.LoadFromMemoryAsync(binary);
            yield return req;
            callback(req.assetBundle);
        }
    
        public IEnumerator LoadFromServer(string uri)
        {
            UnityWebRequest req = UnityWebRequestAssetBundle.GetAssetBundle(uri);
            yield return req.SendWebRequest();
    
            AssetBundle bundle = DownloadHandlerAssetBundle.GetContent(req);
            Debug.Log(bundle);
        }
    
    }

     

    App

    기존 코드 주석 후 아래 코드 추가

     

     

     

    서버로부터 어셋번들 로드해서 로컬에 저장하기

     

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.Networking;
    using System.IO;
    using System.Text;
    using System.Runtime.Serialization.Formatters.Binary;
    
    public class AssetManager : MonoBehaviour
    {
        public static AssetManager instance;
    
        private void Awake()
        {
            AssetManager.instance = this;
        }
    
        public IEnumerator LoadFromMemoryAsync(string path, System.Action<AssetBundle> callback) {
            //파일을 바이트배열로 읽어서 비동기 방식으로 로드 한다 
            byte[] binary = File.ReadAllBytes(path);
            Debug.Log(binary.Length);
            AssetBundleCreateRequest req = AssetBundle.LoadFromMemoryAsync(binary);
            yield return req;
            callback(req.assetBundle);
        }
    
        public IEnumerator LoadFromServer(string path, string fileName) {
            string bundleUri = string.Format("{0}/{1}", path, fileName);
            UnityWebRequest req1 = UnityWebRequest.Get(bundleUri);
            yield return req1.SendWebRequest();
            var bytes = req1.downloadHandler.data;
            Debug.Log(bytes.Length);
    
            var manifestUri = string.Format("{0}.manifest", bundleUri);
            UnityWebRequest req2 = UnityWebRequest.Get(manifestUri);
            yield return req2.SendWebRequest();
            var manifest = Encoding.UTF8.GetString(req2.downloadHandler.data);
    
            //저장 
            string bundlePath = string.Format("{0}/{1}", Application.persistentDataPath, fileName);
            Debug.Log(bundlePath);
            File.WriteAllBytes(bundlePath, bytes);
    
            string manifestPath = string.Format("{0}.manifest", bundlePath);
            File.WriteAllBytes(manifestPath, ObjectToByteArray(manifest));
        }
    
        private byte[] ObjectToByteArray(object obj) {
            if (obj == null) return null;
            BinaryFormatter bf = new BinaryFormatter();
            MemoryStream ms = new MemoryStream();
            bf.Serialize(ms, obj);
            return ms.ToArray();
        }
    }

     

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class App : MonoBehaviour
    {
        
        void Start()
        {
            //StartCoroutine(
            //    AssetManager.instance.LoadFromMemoryAsync("Assets/AssetBundles/characters", (bundle) => {
            //        Debug.LogFormat("bundle: {0}", bundle);
            //        var prefab = bundle.LoadAsset<GameObject>("ch_01_01");
            //        var model = Instantiate<GameObject>(prefab);
            //    }));
    
            StartCoroutine(AssetManager.instance.LoadFromServer("ftp://[서버ip]/AssetBundles", "characters"));
        }
    }

     

     

     

     

    로컬에서 어셋번들 불러오기 

     

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class App : MonoBehaviour
    {
        void Start()
        {
            //StartCoroutine(
            //    AssetManager.instance.LoadFromMemoryAsync("Assets/AssetBundles/characters", (bundle) => {
            //        Debug.LogFormat("bundle: {0}", bundle);
            //        var prefab = bundle.LoadAsset<GameObject>("ch_01_01");
            //        var model = Instantiate<GameObject>(prefab);
            //    }));
    
            //StartCoroutine(AssetManager.instance.LoadFromServer("ftp://[서버ip]/AssetBundles", "characters"));
    
            StartCoroutine(AssetManager.instance.LoadFromFileAsync(Application.persistentDataPath, "characters", () =>
            {
                var prefab = AssetManager.instance.LoadAsset("characters", "ch_01_01");
                var go = Instantiate<GameObject>(prefab);
            }));
        }
    }

     

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.Networking;
    using System.IO;
    using System.Text;
    using System.Runtime.Serialization.Formatters.Binary;
    
    public class AssetManager : MonoBehaviour
    {
        public static AssetManager instance;
        public Dictionary<string, AssetBundle> dicBundles = new Dictionary<string, AssetBundle>();
    
        private void Awake()
        {
            AssetManager.instance = this;
        }
    
        public IEnumerator LoadFromMemoryAsync(string path, System.Action<AssetBundle> callback)
        {
            //파일을 바이트배열로 읽어서 비동기 방식으로 로드 한다 
            byte[] binary = File.ReadAllBytes(path);
            Debug.Log(binary.Length);
            AssetBundleCreateRequest req = AssetBundle.LoadFromMemoryAsync(binary);
            yield return req;
            callback(req.assetBundle);
        }
    
        public IEnumerator LoadFromFileAsync(string path, string fileName, System.Action callback)
        {
            var req = AssetBundle.LoadFromFileAsync(string.Format("{0}/{1}", path, fileName));
            yield return req;
            var bundle = req.assetBundle;
            Debug.LogFormat("bundle: {0}", bundle);
            dicBundles.Add(fileName, bundle);
            callback();
        }
    
        public GameObject LoadAsset(string bundleName, string prefabName)
        {
            return this.dicBundles[bundleName].LoadAsset<GameObject>(prefabName);
        }
    
        public IEnumerator LoadFromServer(string path, string fileName)
        {
            string bundleUri = string.Format("{0}/{1}", path, fileName);
            UnityWebRequest req1 = UnityWebRequest.Get(bundleUri);
            yield return req1.SendWebRequest();
            var bytes = req1.downloadHandler.data;
            Debug.Log(bytes.Length);
    
            var manifestUri = string.Format("{0}.manifest", bundleUri);
            UnityWebRequest req2 = UnityWebRequest.Get(manifestUri);
            yield return req2.SendWebRequest();
            var manifest = Encoding.UTF8.GetString(req2.downloadHandler.data);
    
            //저장 
            string bundlePath = string.Format("{0}/{1}", Application.persistentDataPath, fileName);
            Debug.Log(bundlePath);
            File.WriteAllBytes(bundlePath, bytes);
    
            string manifestPath = string.Format("{0}.manifest", bundlePath);
            File.WriteAllBytes(manifestPath, ObjectToByteArray(manifest));
        }
    
        private byte[] ObjectToByteArray(object obj)
        {
            if (obj == null) return null;
            BinaryFormatter bf = new BinaryFormatter();
            MemoryStream ms = new MemoryStream();
            bf.Serialize(ms, obj);
            return ms.ToArray();
        }
    }

     

     

     

     

     

    언로드 


    Unload (true) : 어셋번들을 언로드 하고 생성된 모든 인스턴스도 언로드함

     

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class App : MonoBehaviour
    {
        public Button btnUnLoad;
        void Start()
        {
            this.btnUnLoad.onClick.AddListener(() => {
                AssetManager.instance.UnLoadBundle("characters");
            });
    
            StartCoroutine(AssetManager.instance.LoadFromFileAsync(Application.persistentDataPath, "characters", () => {
                var prefab = AssetManager.instance.LoadAsset("characters", "ch_01_01");
                var go = Instantiate<GameObject>(prefab);
            }));
    
        }
    }

     

     

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.Networking;
    using System.IO;
    using System.Text;
    using System.Runtime.Serialization.Formatters.Binary;
    
    public class AssetManager : MonoBehaviour
    {
        public static AssetManager instance;
        public Dictionary<string, AssetBundle> dicBundles = new Dictionary<string, AssetBundle>();
    
        private void Awake()
        {
            AssetManager.instance = this;
        }
    
        public IEnumerator LoadFromMemoryAsync(string path, System.Action<AssetBundle> callback)
        {
            //파일을 바이트배열로 읽어서 비동기 방식으로 로드 한다 
            byte[] binary = File.ReadAllBytes(path);
            Debug.Log(binary.Length);
            AssetBundleCreateRequest req = AssetBundle.LoadFromMemoryAsync(binary);
            yield return req;
            callback(req.assetBundle);
        }
    
        public IEnumerator LoadFromFileAsync(string path, string fileName, System.Action callback)
        {
            var req = AssetBundle.LoadFromFileAsync(string.Format("{0}/{1}", path, fileName));
            yield return req;
            var bundle = req.assetBundle;
            Debug.LogFormat("bundle: {0}", bundle);
            dicBundles.Add(fileName, bundle);
            callback();
        }
    
        public GameObject LoadAsset(string bundleName, string prefabName)
        {
            return this.dicBundles[bundleName].LoadAsset<GameObject>(prefabName);
        }
    
        public IEnumerator LoadFromServer(string path, string fileName)
        {
            string bundleUri = string.Format("{0}/{1}", path, fileName);
            UnityWebRequest req1 = UnityWebRequest.Get(bundleUri);
            yield return req1.SendWebRequest();
            var bytes = req1.downloadHandler.data;
            Debug.Log(bytes.Length);
    
            var manifestUri = string.Format("{0}.manifest", bundleUri);
            UnityWebRequest req2 = UnityWebRequest.Get(manifestUri);
            yield return req2.SendWebRequest();
            var manifest = Encoding.UTF8.GetString(req2.downloadHandler.data);
    
            //저장 
            string bundlePath = string.Format("{0}/{1}", Application.persistentDataPath, fileName);
            Debug.Log(bundlePath);
            File.WriteAllBytes(bundlePath, bytes);
    
            string manifestPath = string.Format("{0}.manifest", bundlePath);
            File.WriteAllBytes(manifestPath, ObjectToByteArray(manifest));
        }
    
        private byte[] ObjectToByteArray(object obj)
        {
            if (obj == null) return null;
            BinaryFormatter bf = new BinaryFormatter();
            MemoryStream ms = new MemoryStream();
            bf.Serialize(ms, obj);
            return ms.ToArray();
        }
    
        public void UnLoadBundle(string bundleName)
        {
            this.dicBundles[bundleName].Unload(true);
        }
    }

     

     

     

    에셋번들+암호화+패치

    https://smilejsu.tistory.com/1202

     

    Unity2018 Assetbundle (어셋번들 + 암호화 + 패치)

    AssetBundle ? - 유니티에서 사용되는 Asset들을 하나로 묶는 기능 (LZMA 압축 알고리즘 사용) LZMA(Lempel–Ziv–Markov chain algorithm)는 데이터 압축에 쓰이는 알고리즘이다. 1998년 이후로 계속 개발 중이..

    smilejsu.tistory.com

     

Designed by Tistory.