1
+ using System . IO ;
2
+ using FairyGUI ;
3
+ using GameFrameX . Runtime ;
4
+ using UnityEngine ;
5
+
6
+ namespace Unity . Startup
7
+ {
8
+ using System . Collections . Generic ;
9
+ using UnityEngine ;
10
+
11
+ public class LRUCache
12
+ {
13
+ private class CacheItem
14
+ {
15
+ public string key ;
16
+ public NTexture texture ;
17
+
18
+ public CacheItem ( string key , NTexture texture )
19
+ {
20
+ this . key = key ;
21
+ this . texture = texture ;
22
+ }
23
+ }
24
+
25
+ private readonly int maxSize ;
26
+ private Dictionary < string , CacheItem > cache ;
27
+ private LinkedList < CacheItem > lruList ;
28
+
29
+ public LRUCache ( int maxSize )
30
+ {
31
+ this . maxSize = maxSize ;
32
+ cache = new Dictionary < string , CacheItem > ( ) ;
33
+ lruList = new LinkedList < CacheItem > ( ) ;
34
+ }
35
+
36
+ public NTexture Get ( string key )
37
+ {
38
+ if ( cache . TryGetValue ( key , out CacheItem item ) )
39
+ {
40
+ // 移动到最近使用的位置
41
+ lruList . Remove ( item ) ;
42
+ lruList . AddFirst ( item ) ;
43
+ return item . texture ;
44
+ }
45
+
46
+ return null ; // 纹理未找到
47
+ }
48
+
49
+ public void Put ( string key , NTexture texture )
50
+ {
51
+ if ( key == null )
52
+ {
53
+ return ;
54
+ }
55
+
56
+ if ( cache . ContainsKey ( key ) )
57
+ {
58
+ // 更新已有项并移动到最近使用位置
59
+ CacheItem existingItem = cache [ key ] ;
60
+ lruList . Remove ( existingItem ) ;
61
+ existingItem . texture = texture ; // 更新纹理
62
+ lruList . AddFirst ( existingItem ) ;
63
+ }
64
+ else
65
+ {
66
+ // 如果超过最大数量,则移除最少使用的项
67
+ if ( cache . Count >= maxSize )
68
+ {
69
+ RemoveLeastRecentlyUsed ( ) ;
70
+ }
71
+
72
+ // 添加新项
73
+ CacheItem newItem = new CacheItem ( key , texture ) ;
74
+ cache [ key ] = newItem ;
75
+ lruList . AddFirst ( newItem ) ;
76
+ }
77
+ }
78
+
79
+ private void RemoveLeastRecentlyUsed ( )
80
+ {
81
+ if ( lruList . Count > 0 )
82
+ {
83
+ CacheItem leastUsedItem = lruList . Last . Value ;
84
+ lruList . RemoveLast ( ) ;
85
+ cache . Remove ( leastUsedItem . key ) ;
86
+ leastUsedItem . texture . Dispose ( ) ;
87
+ if ( leastUsedItem . texture . nativeTexture . IsNotNull ( ) )
88
+ {
89
+ Object . Destroy ( leastUsedItem . texture . nativeTexture ) ; // 释放纹理资源
90
+ }
91
+
92
+ if ( leastUsedItem . texture . alphaTexture . IsNotNull ( ) )
93
+ {
94
+ Object . Destroy ( leastUsedItem . texture . alphaTexture ) ; // 释放纹理资源
95
+ }
96
+ }
97
+ }
98
+
99
+ public void Clear ( )
100
+ {
101
+ foreach ( var item in lruList )
102
+ {
103
+ item . texture . Dispose ( ) ;
104
+ if ( item . texture . nativeTexture . IsNotNull ( ) )
105
+ {
106
+ Object . Destroy ( item . texture . nativeTexture ) ; // 释放纹理资源
107
+ }
108
+
109
+ if ( item . texture . alphaTexture . IsNotNull ( ) )
110
+ {
111
+ Object . Destroy ( item . texture . alphaTexture ) ; // 释放纹理资源
112
+ }
113
+ }
114
+
115
+ cache . Clear ( ) ;
116
+ lruList . Clear ( ) ;
117
+ }
118
+ }
119
+
120
+
121
+ public sealed class FairyGuiExtensionLoader : GLoader
122
+ {
123
+ private static LRUCache cache = new LRUCache ( 100 ) ;
124
+ private static string _cachePath ;
125
+
126
+ public FairyGuiExtensionLoader ( )
127
+ {
128
+ _cachePath = PathHelper . AppHotfixResPath + "/cache/images/" ;
129
+ if ( ! Directory . Exists ( _cachePath ) )
130
+ {
131
+ Directory . CreateDirectory ( _cachePath ) ;
132
+ }
133
+ }
134
+
135
+ protected override async void LoadExternal ( )
136
+ {
137
+ if ( url . IsNullOrWhiteSpace ( ) )
138
+ {
139
+ onExternalLoadFailed ( ) ;
140
+ return ;
141
+ }
142
+
143
+ NTexture tempTexture = null ;
144
+ if ( url . StartsWithFast ( "http://" ) || url . StartsWithFast ( "https://" ) )
145
+ {
146
+ // 网络资源
147
+ var nTexture = cache . Get ( url ) ;
148
+ if ( nTexture . IsNull ( ) )
149
+ {
150
+ var hash = Utility . Hash . MD5 . Hash ( url ) ;
151
+
152
+ var path = $ "{ _cachePath } { hash } .png";
153
+ var isExists = FileHelper . IsExists ( path ) ;
154
+ var texture2D = Texture2D . whiteTexture ;
155
+ if ( isExists )
156
+ {
157
+ var buffer = FileHelper . ReadAllBytes ( path ) ;
158
+ texture2D . LoadImage ( buffer ) ;
159
+ }
160
+ else
161
+ {
162
+ var webBufferResult = await GameApp . Web . GetToBytes ( url , null ) ;
163
+ FileHelper . WriteAllBytes ( path , webBufferResult . Result ) ;
164
+ texture2D . LoadImage ( webBufferResult . Result ) ;
165
+ }
166
+
167
+ tempTexture = new NTexture ( texture2D ) ;
168
+ cache . Put ( url , tempTexture ) ;
169
+ }
170
+ else
171
+ {
172
+ tempTexture = nTexture ;
173
+ }
174
+ }
175
+ else if ( url . StartsWithFast ( "ui://" ) )
176
+ {
177
+ // 包内资源
178
+ LoadContent ( ) ;
179
+ }
180
+ else
181
+ {
182
+ var nTexture = cache . Get ( url ) ;
183
+ if ( nTexture . IsNotNull ( ) )
184
+ {
185
+ tempTexture = nTexture ;
186
+ }
187
+ else
188
+ {
189
+ var assetInfo = GameApp . Asset . GetAssetInfo ( url ) ;
190
+ if ( assetInfo . IsInvalid == false )
191
+ {
192
+ var assetHandle = await GameApp . Asset . LoadAssetAsync < Texture2D > ( url ) ;
193
+ if ( assetHandle . IsSucceed )
194
+ {
195
+ tempTexture = new NTexture ( assetHandle . GetAssetObject < Texture2D > ( ) ) ;
196
+ cache . Put ( url , tempTexture ) ;
197
+ }
198
+ }
199
+ else
200
+ {
201
+ if ( FileHelper . IsExists ( url ) )
202
+ {
203
+ var buffer = FileHelper . ReadAllBytes ( url ) ;
204
+
205
+ var texture2D = new Texture2D ( Screen . width , Screen . height , TextureFormat . ARGB32 , false , false ) ;
206
+ texture2D . LoadImage ( buffer ) ;
207
+ tempTexture = new NTexture ( texture2D ) ;
208
+ cache . Put ( url , tempTexture ) ;
209
+ }
210
+ }
211
+ }
212
+ }
213
+
214
+ if ( tempTexture . IsNotNull ( ) )
215
+ {
216
+ onExternalLoadSuccess ( tempTexture ) ;
217
+ }
218
+ else
219
+ {
220
+ onExternalLoadFailed ( ) ;
221
+ }
222
+ }
223
+ }
224
+ }
0 commit comments