Addressable資源管理

1)Addressable資源管理
​2)Addressable熱更新問題
3)不合理舊圖集拆分紅新的小圖集
4)XLua中在Lua和C#傳遞自定義值類型
5)Toggle的onValueChanged如何正確移除某個匿名的監聽html


這是第216篇UWA技術知識分享的推送。今天咱們繼續爲你們精選了若干和開發、優化相關的問題,建議閱讀時間10分鐘,認真讀完必有收穫。緩存

UWA 問答社區:answer.uwa4d.com
UWA QQ羣2:793972859(原羣已滿員)網絡

Addressable

Q1:你們用Addressable管理資源,對於AssetsGroups的Bundle Mode:選用Pack Together好,仍是選用Pack Separately好?你們有什麼好的建議嗎?app

A:Pack Together是最簡單的管理方式,可是適合打包後比較小的資源集,好比少許通用的Shader能夠打包在一塊兒。可是每每仍是Pack Separately用的比較多,我的以爲Separately更容易管理。ide

其實具體如何選擇要看咱們須要打包的資源如何分類。假設一個遊戲的資源分出如下類型:玩家、怪物、NPC、地圖、特效、音樂和通用資源等,那麼從功能和管理的角度考慮,來對這些資源進行目錄管理。函數

RemoteAssets |__Players (Group) | |__Player01 (拖入Group) | | |__Animations (做爲SubAsset,不可修改,會被打包進Player01) | | |__Materials | | |__Textures | | |__Models | | |__Prefabs | |__Player02 |__Monsters | |__Common | |__Monster001 | |__Monster002 |__Maps |__Map001工具

不一樣Group內則以更新爲單位來考慮,好比版本2須要新加Monster003,版本4須要添Map002。天然應該按這些小分類作Bundle打包。測試

因而能夠以大分類作Group,選擇Pack Separately,以小分類的目錄拖進Group做爲AssetEntry,這樣基本就能管理好了。而且通常每一個Bundle的大小也能控制在合理範圍內。優化

可是分開打包可能由於各個包內資源引用到其餘共用資源,形成重複打包。所以總體尺寸會大於Together。因而咱們能夠在某個Group內創建一個Common的子目錄,將這個Group內可能被共用的部分提出來打包。網站

另一部分資源好比UI,能夠考慮納入一個Group,而後選擇按Label打包。按UI使用的界面和更新批次創建Label,咱們這個步驟是結合AssetGraph利用文件名自動生成Label來設置Group的。

一些通用資源能夠單獨創建Group,而後選擇Pack Together。可是咱們依然是創建一個叫Common的Group,而後仍是選擇Separately。

這個組裏面添加各個資源目錄:

Common |__ Fonts |__ Shaders |__ Materials

大體思路是這樣,可是還會要結合各個項目的實際需求,功能分割,更新和運營要求來作設計。

Q2:目前比較奇怪的現象是用Pack Separately打出的包要比Pack Together的大不少。

另外對於Addressable咱們會有針對性地設置它的Group分組,好比按照功能、按照資源類型進行分組,若是全部資源都是Pack Together模式,那麼Addressable會對應生成Group個數的Bundle文件,而後咱們利用Addressable的Analyze工具,進行冗餘資源分析,自動分析出的Group資源,咱們仍是用Separately模式在分析一次?檢驗下是否還有冗餘嗎?

另外還有個想法:把全部資源Group進行Separately打包,而後再用Analyze分析工具進行冗餘檢查,和先用Together模式進行打包再分析冗餘,這兩種操做方式,分析出的結果會是同樣的嗎?

A:其實咱們基本不用Analyze工具,咱們儘可能做到全部資源的具體去向(打到那個具體包)都能清晰地管理和掌握,最多結合UWA的AssetBundle分析工具來找出冗餘,而後手動來作移動和管理。只要每添加一個資源都能嚴格按照既定的規範來管理,目錄分割清晰。導出和生成預製體的流程使用工具自動化,那麼仍是很好管理的。

感謝黃程@UWA問答社區提供了回答


Addressable

Q1:Addressable打熱更新資源的時候會生成一個新的資源在原來的目錄下,和舊的資源在一個目錄,那我是每次都要把這整個文件夾都上傳到CDN上嗎?有沒有什麼辦法能把每次須要熱更新的資源單獨提取出來放在一個額外版本文件夾呢?

A:主要有如下幾點:

  1. 只要傳新的AssetBundle和Catalog。
  2. 若是不包含Hash,那麼AssetBundle文件名同樣的狀況下會覆蓋舊資源(可能存在CDN緩存問題)。
  3. 能夠每次出更新包修改RemoteBuildPath,指向不一樣目錄。
  4. 繼承一個BuildScriptPackedMode本身去實現一個Build腳本。

Addressables自己不對更新資源作版本號管理的,這個須要本身作。

Q2:麻煩問下,若是本身添加了版本控制,Addressable能夠作到回退版本嗎?例如已經使用版本2的Catalogs完成了更新,此時須要回退回版本1,用客戶端版本2的Catalogs和服務端版本1的對比,能夠再更回去嗎?

A:沒有試過,理論上能夠,由於Addressable沒有版本號概念,只對比Hash,不一樣就認爲有更新,至於新舊,它無論。

Q3:組設置裏,有個Use Asset Bundle Crc.,若是勾選這個,那客戶端的文件CRC校驗失敗(例如被修改器之類的改了),Addressable會怎麼處理呢?看描述說,這個是本地文件和遠程文件都起做用的,這裏對於Load Path分別是本地和遠程的組來講,有什麼不一樣嗎?

A:CRC檢測失敗,天然這個資源的載入就失敗了,Addressable會提示錯誤。這個過程通常來講至關於用記錄在Catalog內的CRC對下載的Bundle作校驗。這個和本地遠程應該沒多大關係,就算放在本地的包,其實也能夠經過更新來作替換使用的。這個時候也是能夠作CRC檢驗的。更細節的部分我也沒有具體關注過,你也能夠讀一下源代碼,看看具體怎麼實現的。

感謝黃程@UWA問答社區提供了回答


Texture

Q:咱們這邊有這樣的一個問題:用的TexturePacker打出的圖集有大量的無效區域(好久的老圖集了)有沒有什麼辦法能夠將這些圖集拆分一下(須要考慮材質的分割和從新引用)。

A1:若是還有TexturePacker的工程,那麼將ForceSquared的勾去掉,這樣就不會強制正方形貼圖,會根據實際使用的尺寸進行縮減了。

若是沒有原工程,那麼能夠解析導出的.tpsheet文件,都是文本形式的。好比:

不一樣版本可能格式不一樣,可是都是能夠解析的。而後作個小工具就能夠分解而且重組了。粗暴點直接修改也行。通常只要Sprite名字不變,那麼使用TexturePacker的SDK應該不須要考慮材質的分割和從新引用。

感謝黃程@UWA問答社區提供了回答

A2:TP打圖集後期想拆分很難了,包括Sprite更名字都麻煩。若是大家能保證每一個Sprite的名字都是惟一的,能夠寫腳本批量替換,不然就放棄。

感謝Walker@UWA問答社區提供了回答

A3:感受是有不太有自動化的方法,推薦是手寫腳本批量替換,我倒以爲Sprite名不定要惟一。

假設圖集名字爲a,新圖集爲b。

  1. 先遍歷工程,找出對圖集a引用的資源A等等。
  2. 將A引用的Sprite替換爲b中對應的Sprite。
  3. 都替換完成後,再重複1,肯定a沒有被引用。

還有1種狀況是Atlas - Sprite對在代碼中被使用,而非直接引用。那可能要定向查詢配表信息/字符串常量了。

感謝cloud@UWA問答社區提供了回答


Script

Q:XLua在傳遞值類型的時候,可經過GCOptimizeAttribute來優化GC表現,經過AdditionalPropertiesAttribute來聲明在C#和Lua之間作值傳遞時,看成字段來傳遞的屬性(Property)。此外,對例如 UnityEngine.Vector3 的類型,Lua一側在一些狀況下可直接用Table傳遞,如:

local v = {x=1, y=2, z=3} + Vector3(4, 5, 6)

獲得的V是個份量爲五、七、9的Vector3。這個行爲在生成Wrapper代碼,或者以反射模式運行的時候,都是成立的。

可是我自定義的Struct類型,聲明瞭上述Attribute,也生成了代碼(包括CopyByValues等),相似行爲只有生成Wrapper才能正確執行,在反射模式下傳遞的值都是0。請問爲何?

Struct代碼:

public struct SB { private int intField; private float floatField; private long longField; public static SB operator +(SB a, SB b) { return new SB { IntField = a.IntField + b.IntField, FloatField = a.FloatField + b.FloatField, LongField = a.LongField + b.LongField, }; } public int IntField { get => intField; set => intField = value; } public float FloatField { get => floatField; set => floatField = value; } public long LongField { get => longField; set => longField = value; } public override string ToString() { return $"int: {intField}, float: {floatField}, long: {longField}"; } public static SB Create(int intField, float floatField, long longField) { return new SB { IntField = intField, FloatField = floatField, LongField = longField, }; } }

Lua側:

local SB = CS.SB local sb1 = SB.Create(1, 2.0, 3) local sb2 = SB.Create(2, 3.0, 4) Logger.LogWarningSafe(sb1 + sb2) Logger.LogWarningSafe(sb1 + {IntField=1, FloatField=2, LongField=3}) Logger.LogWarningSafe({IntField=1, FloatField=2, LongField=3} + sb1)

用反射模式運行的結果:

生成Wrapper代碼後的運行結果:

後者運行結果正確。因此,使用AdditionalProperties,是否還須要作什麼額外工做才能使得上述代碼在反射模式和Wrapper模式下都能正確運行呢?

環境:Unity 2018.4.18f1,以及大約是2019年較早時候的xlua-framework。

A:你看一下AdditionalPropertiesAttribute的被引用狀況就知道了,只在Generator裏用到,反射模式下根本不判斷這個的。

Vector3能夠,是由於X、Y、Z都是Field。在反射方式下,只會用Field方式去嘗試匹配(見ObjectCaster.cs 672行)。

感謝snuc@UWA問答社區提供了回答


Script

Q:以下述測試代碼,OnDisable內的沒法正確移除Test(), 其結果是屢次OnEnable後 onValueChanged時調用了不少次Test();

`public void OnEnable() { toggle.onValueChanged.AddListener(_ => Test()); }

public void OnDisable()
{
    toggle.onValueChanged.RemoveListener(_ => Test());
}

public void Test()
{

}`

A:RemoveListener的時候_ => Test()做爲匿名函數是單獨的實例,和Add的時候不是同一個,天然沒法移除了。

`public void OnEnable() {

toggle.onValueChanged.AddListener(this.Test);
}

public void OnDisable()    {
    toggle.onValueChanged.RemoveListener(this.Test);
}

public void Test()    {

}`

試試:

`private Data _data;

private delegate void OnValueChangedDelegate;

private OnValueChangedDelegate onValueChanged;

public void OnEnable() { this.onValueChanged = ()=>{ OnValueChange_FileDelete(this.toggle, this._data); }; toggle.onValueChanged.AddListener(this.onValueChanged); }

public void OnDisable() { toggle.onValueChanged.RemoveListener(this.onValueChanged); }

public void OnValueChange_FileDelete(Toggle toggle, Data _data) {

}`

感謝黃程@UWA問答社區提供了回答

封面圖來源於網絡


今天的分享就到這裏。固然,生有涯而知無涯。在漫漫的開發週期中,您看到的這些問題也許都只是冰山一角,咱們早已在UWA問答網站上準備了更多的技術話題等你一塊兒來探索和分享。歡迎熱愛進步的你加入,也許你的方法恰能解別人的燃眉之急;而他山之「石」,也能攻你之「玉」。

官網:www.uwa4d.com
官方技術博客:blog.uwa4d.com
官方問答社區:answer.uwa4d.com
UWA學堂:edu.uwa4d.com 官方技術QQ羣:793972859(原羣已滿員)

相關文章
相關標籤/搜索