Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Sign in / Register
Toggle navigation
Y
ygopro2
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Locked Files
Issues
1
Issues
1
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Security & Compliance
Security & Compliance
Dependency List
License Compliance
Packages
Packages
List
Container Registry
Analytics
Analytics
CI / CD
Code Review
Insights
Issues
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
hex
ygopro2
Commits
3e267a81
Commit
3e267a81
authored
Jul 19, 2025
by
hex
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Optimized GameTextureManager
parent
a992169d
Pipeline
#39190
failed
Changes
5
Pipelines
1
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
538 additions
and
928 deletions
+538
-928
Assets/SibylSystem/Program.cs
Assets/SibylSystem/Program.cs
+53
-1
Assets/SibylSystem/ResourceManagers/GameTextureManager.cs
Assets/SibylSystem/ResourceManagers/GameTextureManager.cs
+465
-885
Assets/SibylSystem/ResourceManagers/GameTextureManagerRunner.cs
.../SibylSystem/ResourceManagers/GameTextureManagerRunner.cs
+0
-23
Assets/SibylSystem/ResourceManagers/GameTextureManagerRunner.cs.meta
...lSystem/ResourceManagers/GameTextureManagerRunner.cs.meta
+0
-11
Assets/SibylSystem/ResourceManagers/UnityFileDownloader.cs
Assets/SibylSystem/ResourceManagers/UnityFileDownloader.cs
+20
-8
No files found.
Assets/SibylSystem/Program.cs
View file @
3e267a81
...
@@ -367,7 +367,13 @@ public class Program : MonoBehaviour
...
@@ -367,7 +367,13 @@ public class Program : MonoBehaviour
InterString
.
initialize
(
"config/translation.conf"
);
InterString
.
initialize
(
"config/translation.conf"
);
// 显示一个简单的加载提示
// 显示一个简单的加载提示
PrintToChat
(
InterString
.
Get
(
"正在加载本地数据..."
));
PrintToChat
(
InterString
.
Get
(
"正在加载本地数据..."
));
// GameTextureManager.initialize();
if
(!
GameTextureManager
.
IsInitialized
)
{
GameTextureManager
.
InitializeAssets
();
// 1. 同步加载核心资源
GameTextureManager
.
StartBackgroundThread
();
// 2. 启动后台图片加载线程
}
Config
.
initialize
(
"config/config.conf"
);
Config
.
initialize
(
"config/config.conf"
);
// [新增] 封装文件加载逻辑,避免重复检查
// [新增] 封装文件加载逻辑,避免重复检查
...
@@ -1205,6 +1211,39 @@ public class Program : MonoBehaviour
...
@@ -1205,6 +1211,39 @@ public class Program : MonoBehaviour
Resources
.
UnloadUnusedAssets
();
Resources
.
UnloadUnusedAssets
();
onRESIZED
();
onRESIZED
();
}
}
if
(
GameTextureManager
.
IsInitialized
)
{
// 1. 检查并处理下载请求
if
(
GameTextureManager
.
HasDownloadRequests
())
{
var
request
=
GameTextureManager
.
GetNextDownloadRequest
();
if
(!
string
.
IsNullOrEmpty
(
request
.
Url
))
{
// Program 自身就是 MonoBehaviour,所以可以直接启动协程
StartCoroutine
(
DownloadAndProcessFile
(
request
));
}
}
// 2. 检查并处理纹理创建任务 (分帧处理避免卡顿)
int
tasksProcessedThisFrame
=
0
;
int
maxTasksPerFrame
=
5
;
while
(
GameTextureManager
.
HasMainThreadTasks
()
&&
tasksProcessedThisFrame
<
maxTasksPerFrame
)
{
var
resource
=
GameTextureManager
.
GetNextMainThreadTask
();
if
(
resource
!=
null
)
{
GameTextureManager
.
CreateTextureFromResource
(
resource
);
tasksProcessedThisFrame
++;
}
else
{
break
;
}
}
}
fixALLcamerasPreFrame
();
fixALLcamerasPreFrame
();
wheelValue
=
UICamera
.
GetAxis
(
"Mouse ScrollWheel"
)
*
50
;
wheelValue
=
UICamera
.
GetAxis
(
"Mouse ScrollWheel"
)
*
50
;
pointedGameObject
=
null
;
pointedGameObject
=
null
;
...
@@ -1269,6 +1308,15 @@ public class Program : MonoBehaviour
...
@@ -1269,6 +1308,15 @@ public class Program : MonoBehaviour
}
}
}
}
// NEW: 这个辅助协程也从 Runner 移到了这里
private
static
IEnumerator
DownloadAndProcessFile
(
GameTextureManager
.
DownloadRequest
request
)
{
yield
return
UnityFileDownloader
.
DownloadFileAsync
(
request
.
Url
,
request
.
FilePath
,
(
success
)
=>
{
GameTextureManager
.
OnDownloadComplete
(
success
,
request
);
});
}
private
void
onRESIZED
()
private
void
onRESIZED
()
{
{
preWid
=
Screen
.
width
;
preWid
=
Screen
.
width
;
...
@@ -1330,6 +1378,10 @@ public class Program : MonoBehaviour
...
@@ -1330,6 +1378,10 @@ public class Program : MonoBehaviour
{
{
servants
[
i
].
OnQuit
();
servants
[
i
].
OnQuit
();
}
}
// 在应用退出时,优雅地关闭 GameTextureManager 的后台线程
GameTextureManager
.
Shutdown
();
Running
=
false
;
Running
=
false
;
try
try
{
{
...
...
Assets/SibylSystem/ResourceManagers/GameTextureManager.cs
View file @
3e267a81
using
System
;
using
System
;
using
System.Collections
;
using
System.Collections
;
using
System.Collections.Generic
;
using
System.Collections.Generic
;
using
System.Drawing
;
using
System.Drawing.Imaging
;
using
System.IO
;
using
System.IO
;
using
System.Threading
;
using
System.Threading
;
using
UnityEngine
;
using
UnityEngine
;
using
YGOSharp.OCGWrapper.Enums
;
using
YGOSharp.OCGWrapper.Enums
;
public
enum
GameTextureType
public
enum
GameTextureType
{
{
card_picture
=
0
,
card_picture
=
0
,
...
@@ -17,153 +16,87 @@ public enum GameTextureType
...
@@ -17,153 +16,87 @@ public enum GameTextureType
public
class
GameTextureManager
public
class
GameTextureManager
{
{
#
region
---
线程安全与主线程桥接
---
#
region
Main
-
Thread
Bridge
&
Initialization
// 真正的线程锁,用于保护所有共享的集合
// ADDED: A structure to hold download request details.
private
static
readonly
object
_lock
=
new
object
();
internal
struct
DownloadRequest
// 'internal' is good practice for helper structs
{
public
string
Url
;
public
string
FilePath
;
public
PictureResource
PicResource
;
}
// ADDED: A thread-safe queue for download requests from the background thread.
private
static
readonly
Queue
<
DownloadRequest
>
downloadRequestQueue
=
new
Queue
<
DownloadRequest
>();
// ADDED: Unity will automatically call this method once when the game loads,
// before any scene loads. This is the perfect place to set up our helper.
[
RuntimeInitializeOnLoadMethod
(
RuntimeInitializeLoadType
.
BeforeSceneLoad
)]
private
static
void
InitializeOnLoad
()
{
// Create a hidden GameObject to host our runner.
GameObject
runnerObject
=
new
GameObject
(
"GameTextureManagerRunner"
);
// Add our runner component to it.
runnerObject
.
AddComponent
<
GameTextureManagerRunner
>();
// Ensure it persists across scene changes.
GameObject
.
DontDestroyOnLoad
(
runnerObject
);
// The original initialize logic now goes here.
Initialize
();
}
// ADDED: Helper methods for the runner to interact with the queue.
internal
static
bool
HasDownloadRequests
()
{
return
downloadRequestQueue
.
Count
>
0
;
}
internal
static
DownloadRequest
GetNextDownloadRequest
()
{
lock
(
downloadRequestQueue
)
{
return
downloadRequestQueue
.
Dequeue
();
}
}
#
endregion
// 待加载队列: 主线程请求 -> 背景线程处理
private
static
readonly
Stack
<
PictureResource
>
_requestStack
=
new
Stack
<
PictureResource
>();
static
bool
bLock
=
false
;
// 待应用队列: 背景线程处理完毕 -> 主线程创建Texture2D
private
static
readonly
Queue
<
PictureResource
>
_mainThreadApplyQueue
=
new
Queue
<
PictureResource
>();
static
Stack
<
PictureResource
>
waitLoadStack
=
new
Stack
<
PictureResource
>();
// 已加载资源缓存
private
static
readonly
Dictionary
<
ulong
,
PictureResource
>
_loadedCache
=
new
Dictionary
<
ulong
,
PictureResource
>();
static
Dictionary
<
ulong
,
PictureResource
>
loadedList
=
new
Dictionary
<
ulong
,
PictureResource
>();
// 防止重复请求的字典
private
static
readonly
HashSet
<
ulong
>
_requestedSet
=
new
HashSet
<
ulong
>();
static
Dictionary
<
ulong
,
bool
>
addedMap
=
new
Dictionary
<
ulong
,
bool
>();
// 下载请求队列
private
static
readonly
Queue
<
DownloadRequest
>
_downloadRequestQueue
=
new
Queue
<
DownloadRequest
>();
static
readonly
HttpDldFile
df
=
new
HttpDldFile
();
// 背景I/O线程
private
static
Thread
_ioThread
;
private
static
bool
_isRunning
=
false
;
public
class
BitmapHelper
public
static
bool
IsInitialized
=
false
;
{
public
System
.
Drawing
.
Color
[,]
colors
=
null
;
public
BitmapHelper
(
string
path
)
// 内部结构体,用于传递下载任务
internal
struct
DownloadRequest
{
{
Bitmap
bitmap
;
public
string
Url
;
try
public
string
FilePath
;
{
public
PictureResource
PicResource
;
bitmap
=
(
Bitmap
)
Image
.
FromFile
(
path
);
}
}
catch
(
Exception
)
{
// 主线程Runner的交互接口
bitmap
=
new
Bitmap
(
10
,
10
);
internal
static
bool
HasMainThreadTasks
()
for
(
int
i
=
0
;
i
<
10
;
i
++)
{
{
for
(
int
w
=
0
;
w
<
10
;
w
++
)
lock
(
_lock
)
{
{
bitmap
.
SetPixel
(
i
,
w
,
System
.
Drawing
.
Color
.
White
)
;
return
_mainThreadApplyQueue
.
Count
>
0
;
}
}
}
}
}
var
bmpData
=
bitmap
.
LockBits
(
new
Rectangle
(
0
,
0
,
bitmap
.
Width
,
bitmap
.
Height
),
ImageLockMode
.
ReadOnly
,
PixelFormat
.
Format32bppArgb
);
IntPtr
ptr
=
bmpData
.
Scan0
;
int
bytes
=
Math
.
Abs
(
bmpData
.
Stride
)
*
bitmap
.
Height
;
byte
[]
rgbValues
=
new
byte
[
bytes
];
System
.
Runtime
.
InteropServices
.
Marshal
.
Copy
(
ptr
,
rgbValues
,
0
,
bytes
);
colors
=
new
System
.
Drawing
.
Color
[
bitmap
.
Width
,
bitmap
.
Height
];
for
(
int
counter
=
0
;
counter
<
rgbValues
.
Length
;
counter
+=
4
)
{
int
i_am
=
counter
/
4
;
colors
[
i_am
%
bitmap
.
Width
,
i_am
/
bitmap
.
Width
]
=
System
.
Drawing
.
Color
.
FromArgb
(
rgbValues
[
counter
+
3
],
rgbValues
[
counter
+
2
],
rgbValues
[
counter
+
1
],
rgbValues
[
counter
+
0
]
);
}
bitmap
.
UnlockBits
(
bmpData
);
bitmap
.
Dispose
();
}
public
System
.
Drawing
.
Color
GetPixel
(
int
a
,
int
b
)
internal
static
PictureResource
GetNextMainThreadTask
()
{
lock
(
_lock
)
{
{
return
colors
[
a
,
b
]
;
return
_mainThreadApplyQueue
.
Count
>
0
?
_mainThreadApplyQueue
.
Dequeue
()
:
null
;
}
}
}
}
public
static
void
clearUnloaded
()
internal
static
bool
HasDownloadRequests
()
{
while
(
true
)
{
try
{
{
while
(
waitLoadStack
.
Count
>
0
)
lock
(
_lock
)
{
{
var
a
=
waitLoadStack
.
Pop
();
return
_downloadRequestQueue
.
Count
>
0
;
addedMap
.
Remove
((
UInt64
)
a
.
type
<<
32
|
(
UInt64
)
a
.
code
);
}
}
break
;
}
}
catch
(
Exception
e
)
internal
static
DownloadRequest
GetNextDownloadRequest
()
{
{
Thread
.
Sleep
(
10
);
lock
(
_lock
)
Debug
.
Log
(
e
);
{
}
return
_downloadRequestQueue
.
Count
>
0
?
_downloadRequestQueue
.
Dequeue
()
:
default
(
DownloadRequest
);
}
}
}
}
public
static
void
clearAll
()
public
static
void
Shutdown
()
{
while
(
true
)
{
{
try
_isRunning
=
false
;
if
(
_ioThread
!=
null
&&
_ioThread
.
IsAlive
)
{
{
waitLoadStack
.
Clear
();
// 给线程一个正常退出的机会
loadedList
.
Clear
();
_ioThread
.
Join
(
500
);
addedMap
.
Clear
();
break
;
}
catch
(
Exception
e
)
{
Thread
.
Sleep
(
10
);
Debug
.
Log
(
e
);
}
}
}
}
}
#
endregion
#
region
---
资源数据结构
---
public
class
PictureResource
public
class
PictureResource
{
{
public
GameTextureType
type
;
public
GameTextureType
type
;
...
@@ -171,928 +104,569 @@ public class GameTextureManager
...
@@ -171,928 +104,569 @@ public class GameTextureManager
public
bool
pCard
=
false
;
public
bool
pCard
=
false
;
public
float
k
=
1
;
public
float
k
=
1
;
//public bool autoMade = false;
// --- 数据流 ---
public
byte
[]
data
=
null
;
// 1. [背景线程] 从文件读取的原始字节
public
float
[,,]
hashed_data
=
null
;
public
byte
[]
rawData
=
null
;
public
Texture2D
u_data
=
null
;
// 2. [主线程] 从rawData转换来的像素数据,用于处理
public
Texture2D
nullReturen
=
null
;
public
Color32
[]
pixelData
=
null
;
public
int
pixelWidth
;
public
int
pixelHeight
;
// 3. [主线程] 最终生成的Unity纹理
public
Texture2D
finalTexture
=
null
;
public
Texture2D
nullReturn
=
null
;
public
PictureResource
(
GameTextureType
t
,
long
c
,
Texture2D
n
)
public
PictureResource
(
GameTextureType
t
,
long
c
,
Texture2D
n
)
{
{
type
=
t
;
type
=
t
;
code
=
c
;
code
=
c
;
nullReturen
=
n
;
nullReturn
=
n
;
}
}
}
private
class
UIPictureResource
// 辅助方法,用于在Texture创建后释放中间内存
public
void
ClearIntermediateData
()
{
{
public
string
name
;
rawData
=
null
;
public
Texture2D
data
=
null
;
pixelData
=
null
;
}
}
}
static
BetterList
<
UIPictureResource
>
allUI
=
new
BetterList
<
UIPictureResource
>();
#
endregion
public
static
Texture2D
myBack
=
null
;
public
static
Texture2D
opBack
=
null
;
public
static
Texture2D
unknown
=
null
;
public
static
Texture2D
attack
=
null
;
public
static
Texture2D
negated
=
null
;
public
static
Texture2D
bar
=
null
;
public
static
Texture2D
exBar
=
null
;
public
static
Texture2D
lp
=
null
;
public
static
Texture2D
time
=
null
;
public
static
Texture2D
L
=
null
;
public
static
Texture2D
R
=
null
;
public
static
Texture2D
Chain
=
null
;
public
static
Texture2D
Mask
=
null
;
public
static
Texture2D
N
=
null
;
public
static
Texture2D
LINK
=
null
;
public
static
Texture2D
LINKm
=
null
;
public
static
Texture2D
nt
=
null
;
public
static
Texture2D
bp
=
null
;
public
static
Texture2D
ep
=
null
;
public
static
Texture2D
mp1
=
null
;
public
static
Texture2D
mp2
=
null
;
public
static
Texture2D
dp
=
null
;
public
static
Texture2D
sp
=
null
;
public
static
Texture2D
phase
=
null
;
public
static
bool
AutoPicDownload
;
public
static
Texture2D
rs
=
null
;
#
region
---
核心公共接口
(
API
)
---
public
static
Texture2D
ts
=
null
;
// 对外接口保持不变
public
static
Texture2D
get
(
long
code
,
GameTextureType
type
,
Texture2D
nullReturnValue
=
null
)
{
UInt64
key
=
hashPic
(
code
,
type
);
internal
static
IEnumerator
DownloadAndProcessFile
(
DownloadRequest
request
)
lock
(
_lock
)
{
{
yield
return
UnityFileDownloader
.
DownloadFileAsync
(
request
.
Url
,
request
.
FilePath
,
(
success
)
=>
PictureResource
resource
;
if
(
_loadedCache
.
TryGetValue
(
key
,
out
resource
))
{
{
if
(
success
)
// 如果已经有最终纹理,直接返回
if
(
resource
.
finalTexture
!=
null
)
{
{
Debug
.
Log
(
"Download successful, processing card picture: "
+
request
.
PicResource
.
code
);
// myBack作为未找到图片时的替代品,这里返回用户指定的默认值
LoadCardPicture
(
request
.
PicResource
,
request
.
FilePath
)
;
return
resource
.
finalTexture
==
myBack
?
nullReturnValue
:
resource
.
finalTexture
;
}
}
else
// 否则返回 null,主线程Runner正在处理它
{
return
null
;
Debug
.
LogWarning
(
"Download failed for card: "
+
request
.
PicResource
.
code
);
LoadCardPicture
(
request
.
PicResource
,
request
.
FilePath
);
// Let it handle the missing file
}
});
}
}
private
static
Thread
main_thread
;
// 如果已经请求过,但还未处理完,则直接返回null,防止重复请求
if
(
_requestedSet
.
Contains
(
key
))
// MODIFIED: In your original code, Program.Running was used. This is a more robust way.
private
static
bool
IsRunning
=
true
;
// Call this method from your main game logic on application quit to stop the thread.
public
static
void
Shutdown
()
{
IsRunning
=
false
;
if
(
main_thread
!=
null
&&
main_thread
.
IsAlive
)
{
{
main_thread
.
Join
(
100
)
;
return
null
;
}
}
// 创建新请求
PictureResource
newResource
=
new
PictureResource
(
type
,
code
,
nullReturnValue
);
_requestStack
.
Push
(
newResource
);
_requestedSet
.
Add
(
key
);
}
}
static
void
thread_run
()
return
null
;
{
}
while
(
IsRunning
)
{
public
static
float
getK
(
long
code
,
GameTextureType
type
)
try
{
{
Thread
.
Sleep
(
50
);
UInt64
key
=
hashPic
(
code
,
type
);
int
thu
=
0
;
lock
(
_lock
)
while
(
waitLoadStack
.
Count
>
0
)
{
{
thu
++
;
PictureResource
r
;
if
(
thu
==
10
)
if
(
_loadedCache
.
TryGetValue
(
key
,
out
r
)
)
{
{
Thread
.
Sleep
(
50
);
return
r
.
k
;
thu
=
0
;
}
}
if
(
bLock
==
false
)
{
PictureResource
pic
;
pic
=
waitLoadStack
.
Pop
();
try
{
pic
.
pCard
=
(
YGOSharp
.
CardsManager
.
Get
((
int
)
pic
.
code
).
Type
&
(
int
)
CardType
.
Pendulum
)
>
0
;
}
}
catch
(
Exception
e
)
return
1.0f
;
{
Debug
.
Log
(
"e 0"
+
e
.
ToString
());
}
}
switch
(
pic
.
type
)
#
endregion
#
region
---
背景线程处理
(
Background
I
/
O
Thread
)
---
// 背景线程只做文件I/O,不做任何Unity API调用
static
void
IoThreadRun
()
{
{
case
GameTextureType
.
card_feature
:
while
(
_isRunning
)
{
{
ProcessingCardFeature
(
pic
);
PictureResource
resourceToProcess
=
null
;
break
;
lock
(
_lock
)
}
case
GameTextureType
.
card_picture
:
{
ProcessingCardPicture
(
pic
);
break
;
}
case
GameTextureType
.
card_verticle_drawing
:
{
{
ProcessingVerticleDrawing
(
pic
);
if
(
_requestStack
.
Count
>
0
)
break
;
}
}
}
}
}
catch
(
Exception
e
)
{
{
Debug
.
Log
(
"error 1"
+
e
.
ToString
());
resourceToProcess
=
_requestStack
.
Pop
();
}
}
}
}
}
private
static
void
ProcessingCardFeature
(
PictureResource
pic
)
if
(
resourceToProcess
!=
null
)
{
{
try
try
{
{
if
(
File
.
Exists
(
"picture/closeup/"
+
pic
.
code
.
ToString
()
+
".png"
))
// 检查卡片是否是灵摆怪兽
{
var
card
=
YGOSharp
.
CardsManager
.
Get
((
int
)
resourceToProcess
.
code
);
string
path
=
"picture/closeup/"
+
pic
.
code
.
ToString
()
+
".png"
;
if
(
card
!=
null
)
if
(
Program
.
ANDROID_API_N
)
{
BitmapHelper
bitmap
=
new
BitmapHelper
(
path
);
int
left
;
int
right
;
int
up
;
int
down
;
CutTop
(
bitmap
,
out
left
,
out
right
,
out
up
,
out
down
);
up
=
CutLeft
(
bitmap
,
up
);
down
=
CutRight
(
bitmap
,
down
);
right
=
CutButton
(
bitmap
,
right
);
int
width
=
right
-
left
;
int
height
=
down
-
up
;
pic
.
hashed_data
=
new
float
[
width
,
height
,
4
];
for
(
int
w
=
0
;
w
<
width
;
w
++)
{
for
(
int
h
=
0
;
h
<
height
;
h
++)
{
System
.
Drawing
.
Color
color
=
bitmap
.
GetPixel
(
left
+
w
,
up
+
h
);
float
a
=
(
float
)
color
.
A
/
255f
;
if
(
w
<
40
)
if
(
a
>
(
float
)
w
/
(
float
)
40
)
a
=
(
float
)
w
/
(
float
)
40
;
if
(
w
>
(
width
-
40
))
if
(
a
>
1f
-
(
float
)(
w
-
(
width
-
40
))
/
(
float
)
40
)
a
=
1f
-
(
float
)(
w
-
(
width
-
40
))
/
(
float
)
40
;
if
(
h
<
40
)
if
(
a
>
(
float
)
h
/
(
float
)
40
)
a
=
(
float
)
h
/
(
float
)
40
;
if
(
h
>
(
height
-
40
))
if
(
a
>
1f
-
(
float
)(
h
-
(
height
-
40
))
/
(
float
)
40
)
a
=
1f
-
(
float
)(
h
-
(
height
-
40
))
/
(
float
)
40
;
pic
.
hashed_data
[
w
,
height
-
h
-
1
,
0
]
=
(
float
)
color
.
R
/
255f
;
pic
.
hashed_data
[
w
,
height
-
h
-
1
,
1
]
=
(
float
)
color
.
G
/
255f
;
pic
.
hashed_data
[
w
,
height
-
h
-
1
,
2
]
=
(
float
)
color
.
B
/
255f
;
pic
.
hashed_data
[
w
,
height
-
h
-
1
,
3
]
=
a
;
}
}
caculateK
(
pic
);
}
else
{
byte
[]
data
;
using
(
FileStream
file
=
new
FileStream
(
path
,
FileMode
.
Open
,
FileAccess
.
Read
))
{
{
file
.
Seek
(
0
,
SeekOrigin
.
Begin
);
resourceToProcess
.
pCard
=
(
card
.
Type
&
(
int
)
CardType
.
Pendulum
)
>
0
;
data
=
new
byte
[
file
.
Length
];
file
.
Read
(
data
,
0
,
(
int
)
file
.
Length
);
}
}
pic
.
data
=
data
;
}
}
catch
(
Exception
e
)
if
(!
loadedList
.
ContainsKey
(
hashPic
(
pic
.
code
,
pic
.
type
)))
{
{
loadedList
.
Add
(
hashPic
(
pic
.
code
,
pic
.
type
),
pic
);
Debug
.
LogWarning
(
"Get card type failed for code "
+
resourceToProcess
.
code
+
": "
+
e
.
Message
);
}
}
ProcessResourceRequest
(
resourceToProcess
);
}
}
else
else
{
{
string
path
=
"picture/card/"
+
pic
.
code
.
ToString
()
+
".png"
;
// 没有任务时短暂休眠
if
(!
File
.
Exists
(
path
))
Thread
.
Sleep
(
30
);
{
path
=
"picture/card/"
+
pic
.
code
.
ToString
()
+
".jpg"
;
}
}
bool
Iam8
=
false
;
if
(!
File
.
Exists
(
path
))
{
Iam8
=
true
;
path
=
"expansions/pics/"
+
pic
.
code
.
ToString
()
+
".jpg"
;
}
}
if
(!
File
.
Exists
(
path
))
{
Iam8
=
true
;
path
=
"pics/"
+
pic
.
code
.
ToString
()
+
".jpg"
;
}
}
if
(!
File
.
Exists
(
path
))
{
private
static
void
ProcessResourceRequest
(
PictureResource
pic
)
Iam8
=
true
;
path
=
"picture/cardIn8thEdition/"
+
pic
.
code
.
ToString
()
+
".jpg"
;
}
if
(!
File
.
Exists
(
path
))
{
{
pic
.
hashed_data
=
new
float
[
10
,
10
,
4
];
string
path
=
FindImagePath
(
pic
);
for
(
int
w
=
0
;
w
<
10
;
w
++)
if
(!
string
.
IsNullOrEmpty
(
path
)
&&
File
.
Exists
(
path
))
{
{
for
(
int
h
=
0
;
h
<
10
;
h
++)
try
{
{
pic
.
hashed_data
[
w
,
h
,
0
]
=
0
;
pic
.
rawData
=
File
.
ReadAllBytes
(
path
);
pic
.
hashed_data
[
w
,
h
,
1
]
=
0
;
pic
.
hashed_data
[
w
,
h
,
2
]
=
0
;
pic
.
hashed_data
[
w
,
h
,
3
]
=
0
;
}
}
}
if
(!
loadedList
.
ContainsKey
(
hashPic
(
pic
.
code
,
pic
.
type
))
)
catch
(
Exception
e
)
{
{
loadedList
.
Add
(
hashPic
(
pic
.
code
,
pic
.
type
),
pic
);
Debug
.
LogError
(
"Failed to read file: "
+
path
+
". Error: "
+
e
.
Message
);
pic
.
rawData
=
null
;
// 确保失败时rawData为null
}
}
}
}
else
else
if
(
pic
.
type
==
GameTextureType
.
card_picture
&&
pic
.
code
!=
0
&&
AutoPicDownload
)
{
pic
.
hashed_data
=
getCuttedPic
(
path
,
pic
.
pCard
,
Iam8
);
int
width
=
pic
.
hashed_data
.
GetLength
(
0
);
int
height
=
pic
.
hashed_data
.
GetLength
(
1
);
int
size
=
(
int
)(
height
*
0.8
);
int
empWidth
=
(
width
-
size
)
/
2
;
int
empHeight
=
(
height
-
size
)
/
2
;
int
right
=
width
-
empWidth
;
int
buttom
=
height
-
empHeight
;
for
(
int
w
=
0
;
w
<
width
;
w
++)
{
{
for
(
int
h
=
0
;
h
<
height
;
h
++)
// 文件不存在,且是卡图,则尝试下载
string
url
=
"https://cdn02.moecube.com:444/images/ygopro-images-zh-CN/"
+
pic
.
code
.
ToString
()
+
".jpg"
;
string
finalPath
=
"picture/card/"
+
pic
.
code
.
ToString
()
+
".jpg"
;
lock
(
_lock
)
{
{
float
a
=
pic
.
hashed_data
[
w
,
h
,
3
];
_downloadRequestQueue
.
Enqueue
(
new
DownloadRequest
if
(
w
<
empWidth
)
if
(
a
>
((
float
)
w
)
/
(
float
)
empWidth
)
a
=
((
float
)
w
)
/
(
float
)
empWidth
;
if
(
h
<
empHeight
)
if
(
a
>
((
float
)
h
)
/
(
float
)
empHeight
)
a
=
((
float
)
h
)
/
(
float
)
empHeight
;
if
(
w
>
right
)
if
(
a
>
1f
-
((
float
)(
w
-
right
))
/
(
float
)
empWidth
)
a
=
1f
-
((
float
)(
w
-
right
))
/
(
float
)
empWidth
;
if
(
h
>
buttom
)
if
(
a
>
1f
-
((
float
)(
h
-
buttom
))
/
(
float
)
empHeight
)
a
=
1f
-
((
float
)(
h
-
buttom
))
/
(
float
)
empHeight
;
pic
.
hashed_data
[
w
,
h
,
3
]
=
a
*
0.7f
;
}
}
if
(!
loadedList
.
ContainsKey
(
hashPic
(
pic
.
code
,
pic
.
type
)))
{
{
loadedList
.
Add
(
hashPic
(
pic
.
code
,
pic
.
type
),
pic
);
Url
=
url
,
}
FilePath
=
finalPath
,
}
PicResource
=
pic
});
}
}
// 下载任务已入队,直接返回,等待下载回调来继续处理
return
;
}
}
catch
(
Exception
e
)
// I/O操作完成,将资源推入主线程处理队列
lock
(
_lock
)
{
{
Debug
.
Log
(
"e 1"
+
e
.
ToString
()
);
_mainThreadApplyQueue
.
Enqueue
(
pic
);
}
}
}
}
private
static
void
caculateK
(
PictureResource
pic
)
private
static
string
FindImagePath
(
PictureResource
pic
)
{
int
width
=
pic
.
hashed_data
.
GetLength
(
0
);
int
height
=
pic
.
hashed_data
.
GetLength
(
1
);
int
h
=
0
;
for
(
h
=
height
-
1
;
h
>
0
;
h
--)
{
int
all
=
0
;
for
(
int
w
=
0
;
w
<
width
;
w
++)
{
{
if
(
pic
.
hashed_data
[
w
,
h
,
3
]
>
0.05f
)
// ... (原代码中的路径查找逻辑,这里可以保持或优化)
{
// 为了清晰,我把它提取成了一个独立方法
all
+=
1
;
string
path
=
""
;
}
switch
(
pic
.
type
)
}
if
(
all
*
5
>
width
)
{
{
case
GameTextureType
.
card_picture
:
path
=
"picture/card/"
+
pic
.
code
+
".png"
;
if
(!
File
.
Exists
(
path
))
path
=
"picture/card/"
+
pic
.
code
+
".jpg"
;
if
(!
File
.
Exists
(
path
))
path
=
"expansions/pics/"
+
pic
.
code
+
".jpg"
;
if
(!
File
.
Exists
(
path
))
path
=
"pics/"
+
pic
.
code
+
".jpg"
;
if
(!
File
.
Exists
(
path
))
path
=
"picture/cardIn8thEdition/"
+
pic
.
code
+
".jpg"
;
break
;
break
;
}
case
GameTextureType
.
card_feature
:
}
case
GameTextureType
.
card_verticle_drawing
:
pic
.
k
=
((
float
)
h
)
/
((
float
)
height
)
;
path
=
"picture/closeup/"
+
pic
.
code
+
".png"
;
if
(
pic
.
k
>
1
)
if
(!
File
.
Exists
(
path
)
)
{
{
pic
.
k
=
1f
;
// 回退到卡图路径
path
=
"picture/card/"
+
pic
.
code
+
".png"
;
if
(!
File
.
Exists
(
path
))
path
=
"picture/card/"
+
pic
.
code
+
".jpg"
;
if
(!
File
.
Exists
(
path
))
path
=
"expansions/pics/"
+
pic
.
code
+
".jpg"
;
if
(!
File
.
Exists
(
path
))
path
=
"pics/"
+
pic
.
code
+
".jpg"
;
if
(!
File
.
Exists
(
path
))
path
=
"picture/cardIn8thEdition/"
+
pic
.
code
+
".jpg"
;
}
}
if
(
pic
.
k
<
0
)
break
;
{
pic
.
k
=
0.1f
;
}
}
return
path
;
}
}
private
static
float
[,,]
getCuttedPic
(
string
path
,
bool
pCard
,
bool
EightEdition
)
// 下载完成后的回调
internal
static
void
OnDownloadComplete
(
bool
success
,
DownloadRequest
request
)
{
{
BitmapHelper
bitmap
=
new
BitmapHelper
(
path
);
if
(
success
)
int
left
=
0
,
top
=
0
,
right
=
bitmap
.
colors
.
GetLength
(
0
),
buttom
=
bitmap
.
colors
.
GetLength
(
1
);
//right is width and buttom is height now
if
(
EightEdition
)
{
{
if
(
pCard
)
Debug
.
Log
(
"Download successful, reading file: "
+
request
.
FilePath
);
try
{
{
left
=
(
int
)(
16f
*
((
float
)
right
)
/
177f
);
request
.
PicResource
.
rawData
=
File
.
ReadAllBytes
(
request
.
FilePath
);
right
=
(
int
)(
162f
*
((
float
)
right
)
/
177f
);
top
=
(
int
)(
50f
*
((
float
)
buttom
)
/
254f
);
buttom
=
(
int
)(
158f
*
((
float
)
buttom
)
/
254f
);
}
}
else
catch
(
Exception
ex
)
{
{
left
=
(
int
)(
26f
*
((
float
)
right
)
/
177f
);
Debug
.
LogError
(
"Failed to read downloaded file: "
+
ex
.
Message
);
right
=
(
int
)(
152f
*
((
float
)
right
)
/
177f
);
request
.
PicResource
.
rawData
=
null
;
top
=
(
int
)(
55f
*
((
float
)
buttom
)
/
254f
);
buttom
=
(
int
)(
180f
*
((
float
)
buttom
)
/
254f
);
}
}
}
}
else
else
{
{
if
(
pCard
)
Debug
.
LogWarning
(
"Download failed for card: "
+
request
.
PicResource
.
code
);
{
request
.
PicResource
.
rawData
=
null
;
left
=
(
int
)(
25f
*
((
float
)
right
)
/
322f
);
right
=
(
int
)(
290f
*
((
float
)
right
)
/
322f
);
top
=
(
int
)(
73f
*
((
float
)
buttom
)
/
402f
);
buttom
=
(
int
)(
245f
*
((
float
)
buttom
)
/
402f
);
}
else
{
left
=
(
int
)(
40f
*
((
float
)
right
)
/
322f
);
right
=
(
int
)(
280f
*
((
float
)
right
)
/
322f
);
top
=
(
int
)(
75f
*
((
float
)
buttom
)
/
402f
);
buttom
=
(
int
)(
280f
*
((
float
)
buttom
)
/
402f
);
}
}
}
float
[,,]
returnValue
=
new
float
[
right
-
left
,
buttom
-
top
,
4
];
for
(
int
w
=
0
;
w
<
right
-
left
;
w
++)
// 将任务推入主线程处理队列
{
lock
(
_lock
)
for
(
int
h
=
0
;
h
<
buttom
-
top
;
h
++)
{
{
System
.
Drawing
.
Color
color
=
bitmap
.
GetPixel
(
_mainThreadApplyQueue
.
Enqueue
(
request
.
PicResource
);
(
int
)(
left
+
w
),
(
int
)(
buttom
-
1
-
h
)
);
returnValue
[
w
,
h
,
0
]
=
(
float
)
color
.
R
/
255f
;
returnValue
[
w
,
h
,
1
]
=
(
float
)
color
.
G
/
255f
;
returnValue
[
w
,
h
,
2
]
=
(
float
)
color
.
B
/
255f
;
returnValue
[
w
,
h
,
3
]
=
(
float
)
color
.
A
/
255f
;
}
}
}
}
return
returnValue
;
#
endregion
}
private
static
int
CutButton
(
BitmapHelper
bitmap
,
int
right
)
#
region
---
主线程纹理处理
(
Main
Thread
Texture
Creation
)
---
{
for
(
int
w
=
bitmap
.
colors
.
GetLength
(
0
)
-
1
;
w
>=
0
;
w
--)
{
for
(
int
h
=
0
;
h
<
bitmap
.
colors
.
GetLength
(
1
);
h
++)
{
System
.
Drawing
.
Color
color
=
bitmap
.
GetPixel
(
w
,
h
);
if
(
color
.
A
>
10
)
{
right
=
w
;
return
right
;
}
}
}
return
right
;
}
private
static
int
CutRight
(
BitmapHelper
bitmap
,
int
down
)
// 这个方法由 GameTextureManagerRunner 在主线程的 Update 中调用
{
public
static
void
CreateTextureFromResource
(
PictureResource
pic
)
for
(
int
h
=
bitmap
.
colors
.
GetLength
(
1
)
-
1
;
h
>=
0
;
h
--)
{
for
(
int
w
=
0
;
w
<
bitmap
.
colors
.
GetLength
(
0
);
w
++)
{
{
System
.
Drawing
.
Color
color
=
bitmap
.
GetPixel
(
w
,
h
);
Texture2D
texture
=
null
;
if
(
color
.
A
>
10
)
{
down
=
h
;
return
down
;
}
}
}
return
down
;
}
private
static
int
CutLeft
(
BitmapHelper
bitmap
,
int
up
)
// 步骤1: 加载原始图像数据
{
if
(
pic
.
rawData
!=
null
&&
pic
.
rawData
.
Length
>
0
)
for
(
int
h
=
0
;
h
<
bitmap
.
colors
.
GetLength
(
1
);
h
++)
{
{
for
(
int
w
=
0
;
w
<
bitmap
.
colors
.
GetLength
(
0
);
w
++)
// 使用LoadImage将字节数组解码为纹理
// 它会自动处理PNG/JPG格式
// 创建一个临时的2x2纹理,LoadImage会自动调整其大小
Texture2D
tempTexture
=
new
Texture2D
(
2
,
2
);
if
(
tempTexture
.
LoadImage
(
pic
.
rawData
))
{
{
System
.
Drawing
.
Color
color
=
bitmap
.
GetPixel
(
w
,
h
);
// 步骤2: 根据类型进行图像处理
if
(
color
.
A
>
10
)
switch
(
pic
.
type
)
{
{
up
=
h
;
case
GameTextureType
.
card_picture
:
return
up
;
// 卡图直接使用,无需额外处理
}
texture
=
tempTexture
;
}
// 因为我们直接用了tempTexture,所以不要销毁它
}
break
;
return
up
;
}
private
static
void
CutTop
(
case
GameTextureType
.
card_feature
:
BitmapHelper
bitmap
,
texture
=
ProcessFeatureTexture
(
pic
,
tempTexture
);
out
int
left
,
Destroy
(
tempTexture
);
// 销毁临时纹理
out
int
right
,
break
;
out
int
up
,
out
int
down
)
{
///////切边算法
left
=
0
;
right
=
bitmap
.
colors
.
GetLength
(
0
);
up
=
0
;
down
=
bitmap
.
colors
.
GetLength
(
1
);
for
(
int
w
=
0
;
w
<
bitmap
.
colors
.
GetLength
(
0
);
w
++)
{
for
(
int
h
=
0
;
h
<
bitmap
.
colors
.
GetLength
(
1
);
h
++)
{
System
.
Drawing
.
Color
color
=
bitmap
.
GetPixel
(
w
,
h
);
if
(
color
.
A
>
10
)
{
left
=
w
;
return
;
}
}
}
}
private
static
void
ProcessingVerticleDrawing
(
PictureResource
pic
)
case
GameTextureType
.
card_verticle_drawing
:
{
texture
=
ProcessVerticleDrawingTexture
(
pic
,
tempTexture
);
try
Destroy
(
tempTexture
);
// 销毁临时纹理
{
break
;
string
path
=
"picture/closeup/"
+
pic
.
code
.
ToString
()
+
".png"
;
if
(!
File
.
Exists
(
path
))
{
if
(
Program
.
ANDROID_API_N
)
{
path
=
"picture/card/"
+
pic
.
code
.
ToString
()
+
".png"
;
if
(!
File
.
Exists
(
path
))
{
path
=
"picture/card/"
+
pic
.
code
.
ToString
()
+
".jpg"
;
}
bool
Iam8
=
false
;
if
(!
File
.
Exists
(
path
))
{
Iam8
=
true
;
path
=
"expansions/pics/"
+
pic
.
code
.
ToString
()
+
".jpg"
;
}
if
(!
File
.
Exists
(
path
))
{
Iam8
=
true
;
path
=
"pics/"
+
pic
.
code
.
ToString
()
+
".jpg"
;
}
if
(!
File
.
Exists
(
path
))
{
Iam8
=
true
;
path
=
"picture/cardIn8thEdition/"
+
pic
.
code
.
ToString
()
+
".jpg"
;
}
}
LoadCloseupFromCardPicture
(
pic
,
path
,
Iam8
);
}
}
else
else
{
{
path
=
"picture/null.png"
;
Debug
.
LogWarning
(
"LoadImage failed for card code: "
+
pic
.
code
);
byte
[]
data
;
Destroy
(
tempTexture
);
using
(
FileStream
file
=
new
FileStream
(
path
,
FileMode
.
Open
,
FileAccess
.
Read
))
}
{
file
.
Seek
(
0
,
SeekOrigin
.
Begin
);
data
=
new
byte
[
file
.
Length
];
file
.
Read
(
data
,
0
,
(
int
)
file
.
Length
);
}
}
pic
.
data
=
data
;
if
(!
loadedList
.
ContainsKey
(
hashPic
(
pic
.
code
,
pic
.
type
)))
// 步骤3: 处理加载失败或无数据的情况
if
(
texture
==
null
)
{
{
loadedList
.
Add
(
hashPic
(
pic
.
code
,
pic
.
type
),
pic
);
if
(
pic
.
type
==
GameTextureType
.
card_picture
)
}
}
}
else
{
{
LoadCloseupPicture
(
pic
,
path
)
;
texture
=
(
pic
.
code
>
0
)
?
unknown
:
myBack
;
}
}
}
else
catch
(
Exception
e
)
{
{
Debug
.
Log
(
"e 3"
+
e
.
ToString
());
// 对于feature等,失败时返回一个完全透明的小纹理
texture
=
N
;
}
}
}
}
private
static
void
LoadCloseupFromCardPicture
(
PictureResource
pic
,
string
path
,
bool
Iam8
)
// 步骤4: 完成并缓存
{
pic
.
finalTexture
=
texture
;
try
pic
.
ClearIntermediateData
();
// 释放中间数据内存
{
if
(!
File
.
Exists
(
path
))
UInt64
key
=
hashPic
(
pic
.
code
,
pic
.
type
);
lock
(
_lock
)
{
{
path
=
"picture/null.png"
;
if
(!
_loadedCache
.
ContainsKey
(
key
))
}
if
(!
File
.
Exists
(
path
))
{
{
path
=
"textures/unknown.jpg"
;
//YGOMobile Paths
_loadedCache
.
Add
(
key
,
pic
);
}
}
pic
.
hashed_data
=
getCuttedPic
(
path
,
pic
.
pCard
,
Iam8
);
else
softVtype
(
pic
,
0.5f
);
pic
.
k
=
1
;
if
(!
loadedList
.
ContainsKey
(
hashPic
(
pic
.
code
,
pic
.
type
)))
{
{
loadedList
.
Add
(
hashPic
(
pic
.
code
,
pic
.
type
),
pic
);
// 如果因为某些原因(例如,下载失败后重试)已经存在,则更新它
_loadedCache
[
key
]
=
pic
;
}
}
}
}
catch
{
}
}
}
private
static
void
LoadCloseupPicture
(
PictureResource
pic
,
string
path
)
// 从Unity的Texture2D中裁剪出需要的区域
{
private
static
RectInt
GetCardArtRect
(
PictureResource
pic
,
int
texWidth
,
int
texHeight
)
try
{
if
(
Program
.
ANDROID_API_N
)
{
BitmapHelper
bitmap
=
new
BitmapHelper
(
path
);
int
left
;
int
right
;
int
up
;
int
down
;
CutTop
(
bitmap
,
out
left
,
out
right
,
out
up
,
out
down
);
up
=
CutLeft
(
bitmap
,
up
);
down
=
CutRight
(
bitmap
,
down
);
right
=
CutButton
(
bitmap
,
right
);
int
width
=
right
-
left
;
int
height
=
down
-
up
;
pic
.
hashed_data
=
new
float
[
width
,
height
,
4
];
for
(
int
w
=
0
;
w
<
width
;
w
++)
{
for
(
int
h
=
0
;
h
<
height
;
h
++)
{
{
System
.
Drawing
.
Color
color
=
bitmap
.
GetPixel
(
left
+
w
,
up
+
h
);
// 根据原代码的比例进行裁剪
pic
.
hashed_data
[
w
,
height
-
h
-
1
,
0
]
=
(
float
)
color
.
R
/
255f
;
// 注意:原代码的路径有好几种,对应不同尺寸的卡图,这里简化为一种常见比例
pic
.
hashed_data
[
w
,
height
-
h
-
1
,
1
]
=
(
float
)
color
.
G
/
255f
;
// 你可能需要根据实际卡图源的尺寸来微调这些比值
pic
.
hashed_data
[
w
,
height
-
h
-
1
,
2
]
=
(
float
)
color
.
B
/
255f
;
// 以YGOPRO标准卡图尺寸 177x254 为例
pic
.
hashed_data
[
w
,
height
-
h
-
1
,
3
]
=
(
float
)
color
.
A
/
255f
;
float
ratioW
=
(
float
)
texWidth
/
177f
;
}
float
ratioH
=
(
float
)
texHeight
/
254f
;
}
float
wholeUNalpha
=
0
;
int
x
,
y
,
width
,
height
;
for
(
int
w
=
0
;
w
<
width
;
w
++)
{
if
(
pic
.
pCard
)
// 灵摆
if
(
pic
.
hashed_data
[
w
,
0
,
3
]
>
0.1f
)
{
{
wholeUNalpha
+=
((
float
)
Math
.
Abs
(
w
-
width
/
2
))
/
((
float
)(
width
/
2
));
x
=
(
int
)(
16f
*
ratioW
);
width
=
(
int
)((
162f
-
16f
)
*
ratioW
);
y
=
(
int
)((
254f
-
158f
)
*
ratioH
);
// Y坐标在Unity中从下往上
height
=
(
int
)((
158f
-
50f
)
*
ratioH
);
}
}
if
(
pic
.
hashed_data
[
w
,
height
-
1
,
3
]
>
0.1f
)
else
// 普通
{
{
wholeUNalpha
+=
1
;
x
=
(
int
)(
26f
*
ratioW
);
width
=
(
int
)((
152f
-
26f
)
*
ratioW
);
y
=
(
int
)((
254f
-
180f
)
*
ratioH
);
// Y坐标在Unity中从下往上
height
=
(
int
)((
180f
-
55f
)
*
ratioH
);
}
}
// 边界检查,防止计算出的区域超出纹理范围
x
=
Math
.
Max
(
0
,
x
);
y
=
Math
.
Max
(
0
,
y
);
width
=
Math
.
Min
(
width
,
texWidth
-
x
);
height
=
Math
.
Min
(
height
,
texHeight
-
y
);
return
new
RectInt
(
x
,
y
,
width
,
height
);
}
}
for
(
int
h
=
0
;
h
<
height
;
h
++)
private
static
Texture2D
ProcessFeatureTexture
(
PictureResource
pic
,
Texture2D
source
)
{
{
if
(
pic
.
hashed_data
[
0
,
h
,
3
]
>
0.1f
)
RectInt
cropRect
=
GetCardArtRect
(
pic
,
source
.
width
,
source
.
height
);
if
(
cropRect
.
width
<=
0
||
cropRect
.
height
<=
0
)
return
null
;
Color32
[]
pixels
=
source
.
GetPixels32
();
int
sourceWidth
=
source
.
width
;
int
newWidth
=
cropRect
.
width
;
int
newHeight
=
cropRect
.
height
;
Color32
[]
newPixels
=
new
Color32
[
newWidth
*
newHeight
];
// 复制裁剪区域的像素
for
(
int
row
=
0
;
row
<
newHeight
;
row
++)
{
{
wholeUNalpha
+=
1
;
for
(
int
col
=
0
;
col
<
newWidth
;
col
++)
}
if
(
pic
.
hashed_data
[
width
-
1
,
h
,
3
]
>
0.1f
)
{
{
wholeUNalpha
+=
1
;
int
sourceIndex
=
(
cropRect
.
y
+
row
)
*
sourceWidth
+
(
cropRect
.
x
+
col
);
int
destIndex
=
row
*
newWidth
+
col
;
newPixels
[
destIndex
]
=
pixels
[
sourceIndex
];
}
}
}
}
if
(
wholeUNalpha
>=
((
width
+
height
)
*
0.5f
*
0.12f
))
{
// 应用边缘淡出效果
softVtype
(
pic
,
0.7f
);
float
fadeMargin
=
40f
;
}
for
(
int
y
=
0
;
y
<
newHeight
;
y
++)
caculateK
(
pic
);
}
else
{
{
byte
[]
data
;
for
(
int
x
=
0
;
x
<
newWidth
;
x
++)
using
(
FileStream
file
=
new
FileStream
(
path
,
FileMode
.
Open
,
FileAccess
.
Read
))
{
{
file
.
Seek
(
0
,
SeekOrigin
.
Begin
)
;
float
alpha
=
1.0f
;
data
=
new
byte
[
file
.
Length
];
// 计算到四条边的距离
file
.
Read
(
data
,
0
,
(
int
)
file
.
Length
)
;
float
distToLeft
=
x
;
}
float
distToRight
=
newWidth
-
1
-
x
;
pic
.
data
=
data
;
float
distToTop
=
newHeight
-
1
-
y
;
}
float
distToBottom
=
y
;
if
(!
loadedList
.
ContainsKey
(
hashPic
(
pic
.
code
,
pic
.
type
)))
if
(
distToLeft
<
fadeMargin
)
alpha
=
Mathf
.
Min
(
alpha
,
distToLeft
/
fadeMargin
);
{
if
(
distToRight
<
fadeMargin
)
alpha
=
Mathf
.
Min
(
alpha
,
distToRight
/
fadeMargin
);
loadedList
.
Add
(
hashPic
(
pic
.
code
,
pic
.
type
),
pic
);
if
(
distToTop
<
fadeMargin
)
alpha
=
Mathf
.
Min
(
alpha
,
distToTop
/
fadeMargin
);
if
(
distToBottom
<
fadeMargin
)
alpha
=
Mathf
.
Min
(
alpha
,
distToBottom
/
fadeMargin
);
int
index
=
y
*
newWidth
+
x
;
newPixels
[
index
].
a
=
(
byte
)(
newPixels
[
index
].
a
*
alpha
*
0.7f
);
// 乘以0.7f以匹配原效果
}
}
}
}
catch
{
}
// 创建最终纹理
Texture2D
finalTexture
=
new
Texture2D
(
newWidth
,
newHeight
,
TextureFormat
.
RGBA32
,
false
);
finalTexture
.
SetPixels32
(
newPixels
);
finalTexture
.
Apply
();
// 计算k值(基于alpha不为0的最后一行)
CalculateKValue
(
pic
,
newPixels
,
newWidth
,
newHeight
);
return
finalTexture
;
}
}
private
static
void
softVtype
(
PictureResource
pic
,
float
si
)
private
static
Texture2D
ProcessVerticleDrawingTexture
(
PictureResource
pic
,
Texture2D
source
)
{
{
int
width
=
pic
.
hashed_data
.
GetLength
(
0
);
// 对于立绘,我们通常直接使用整个 PNG,但要应用软边
int
height
=
pic
.
hashed_data
.
GetLength
(
1
);
int
width
=
source
.
width
;
int
size
=
(
int
)(
height
*
si
);
int
height
=
source
.
height
;
Color32
[]
pixels
=
source
.
GetPixels32
();
// 应用软边效果 (类似原softVtype)
float
softenSizeRatio
=
0.7f
;
int
size
=
(
int
)(
height
*
softenSizeRatio
);
int
empWidth
=
(
width
-
size
)
/
2
;
int
empWidth
=
(
width
-
size
)
/
2
;
int
empHeight
=
(
height
-
size
)
/
2
;
int
empHeight
=
(
height
-
size
)
/
2
;
int
right
=
width
-
empWidth
;
int
buttom
=
height
-
empHeight
;
for
(
int
y
=
0
;
y
<
height
;
y
++)
float
dui
=
(
float
)
Math
.
Sqrt
((
width
/
2
)
*
(
width
/
2
)
+
(
height
/
2
)
*
(
height
/
2
));
for
(
int
w
=
0
;
w
<
width
;
w
++)
{
{
for
(
int
h
=
0
;
h
<
height
;
h
++)
for
(
int
x
=
0
;
x
<
width
;
x
++)
{
{
float
a
=
pic
.
hashed_data
[
w
,
h
,
3
];
float
alpha
=
1.0f
;
float
distToLeft
=
x
;
float
distToRight
=
width
-
1
-
x
;
float
distToTop
=
height
-
1
-
y
;
float
distToBottom
=
y
;
if
(
h
<
height
/
2
)
if
(
empWidth
>
0
)
{
float
l
=
(
float
)
Math
.
Sqrt
(
(
width
/
2
-
w
)
*
(
width
/
2
-
w
)
+
(
height
/
2
-
h
)
*
(
height
/
2
-
h
)
);
l
-=
width
*
0.3f
;
if
(
l
<
0
)
{
{
l
=
0
;
if
(
distToLeft
<
empWidth
)
alpha
=
Mathf
.
Min
(
alpha
,
distToLeft
/
empWidth
);
if
(
distToRight
<
empWidth
)
alpha
=
Mathf
.
Min
(
alpha
,
distToRight
/
empWidth
);
}
}
float
alpha
=
1f
-
l
/
(
0.6f
*
(
dui
-
width
*
0.3f
));
if
(
empHeight
>
0
)
if
(
alpha
<
0
)
{
{
alpha
=
0
;
if
(
distToTop
<
empHeight
)
alpha
=
Mathf
.
Min
(
alpha
,
distToTop
/
empHeight
);
}
if
(
distToBottom
<
empHeight
)
alpha
=
Mathf
.
Min
(
alpha
,
distToBottom
/
empHeight
);
if
(
a
>
alpha
)
a
=
alpha
;
}
}
if
(
w
<
empWidth
)
int
index
=
y
*
width
+
x
;
if
(
a
>
((
float
)
w
)
/
(
float
)
empWidth
)
pixels
[
index
].
a
=
(
byte
)(
pixels
[
index
].
a
*
alpha
);
a
=
((
float
)
w
)
/
(
float
)
empWidth
;
if
(
h
<
empHeight
)
if
(
a
>
((
float
)
h
)
/
(
float
)
empHeight
)
a
=
((
float
)
h
)
/
(
float
)
empHeight
;
if
(
w
>
right
)
if
(
a
>
1f
-
((
float
)(
w
-
right
))
/
(
float
)
empWidth
)
a
=
1f
-
((
float
)(
w
-
right
))
/
(
float
)
empWidth
;
if
(
h
>
buttom
)
if
(
a
>
1f
-
((
float
)(
h
-
buttom
))
/
(
float
)
empHeight
)
a
=
1f
-
((
float
)(
h
-
buttom
))
/
(
float
)
empHeight
;
pic
.
hashed_data
[
w
,
h
,
3
]
=
a
;
}
}
}
}
}
private
static
void
ProcessingCardPicture
(
PictureResource
pic
)
Texture2D
finalTexture
=
new
Texture2D
(
width
,
height
,
TextureFormat
.
RGBA32
,
false
);
{
finalTexture
.
SetPixels32
(
pixels
);
try
finalTexture
.
Apply
();
{
string
path
=
"picture/card/"
+
pic
.
code
.
ToString
()
+
".png"
;
if
(!
File
.
Exists
(
path
))
{
path
=
"picture/card/"
+
pic
.
code
.
ToString
()
+
".jpg"
;
}
if
(!
File
.
Exists
(
path
))
{
path
=
"expansions/pics/"
+
pic
.
code
.
ToString
()
+
".jpg"
;
}
if
(!
File
.
Exists
(
path
))
{
path
=
"pics/"
+
pic
.
code
.
ToString
()
+
".jpg"
;
}
if
(!
File
.
Exists
(
path
))
{
path
=
"picture/cardIn8thEdition/"
+
pic
.
code
.
ToString
()
+
".jpg"
;
}
if
(!
File
.
Exists
(
path
)
&&
pic
.
code
!=
0
&&
AutoPicDownload
)
{
// //YGOMobile (177x254)
// df.Download(
// "http://cdn01.moestart.com/images/ygopro-images-zh-CN/"
// + pic.code.ToString()
// + ".jpg",
// "picture/card/" + pic.code.ToString() + ".jpg"
// );
// path = "picture/card/" + pic.code.ToString() + ".jpg";
string
url
=
"https://cdn02.moecube.com:444/images/ygopro-images-zh-CN/"
+
pic
.
code
.
ToString
()
+
".jpg"
;
// string url = "http://cdn01.moestart.com/images/ygopro-images-zh-CN/" + pic.code.ToString() + ".jpg";
string
finalPath
=
"picture/card/"
+
pic
.
code
.
ToString
()
+
".jpg"
;
// Enqueue the request. The runner on the main thread will pick it up.
CalculateKValue
(
pic
,
pixels
,
width
,
height
);
lock
(
downloadRequestQueue
)
{
return
finalTexture
;
downloadRequestQueue
.
Enqueue
(
new
DownloadRequest
{
Url
=
url
,
FilePath
=
finalPath
,
PicResource
=
pic
});
}
}
else
{
LoadCardPicture
(
pic
,
path
);
}
}
catch
(
Exception
e
)
{
Debug
.
Log
(
"e 2"
+
e
.
ToString
());
}
}
}
private
static
void
LoadCardPicture
(
PictureResource
pic
,
string
path
)
private
static
void
CalculateKValue
(
PictureResource
pic
,
Color32
[]
pixels
,
int
width
,
int
height
)
{
{
try
int
lastVisibleRow
=
0
;
for
(
int
y
=
height
-
1
;
y
>=
0
;
y
--)
{
{
if
(!
File
.
Exists
(
path
))
int
opaquePixelsInRow
=
0
;
{
for
(
int
x
=
0
;
x
<
width
;
x
++)
if
(
pic
.
code
>
0
)
{
pic
.
u_data
=
unknown
;
}
else
{
{
pic
.
u_data
=
myBack
;
if
(
pixels
[
y
*
width
+
x
].
a
>
12
)
// 0.05 * 255 ≈ 12
}
if
(!
loadedList
.
ContainsKey
(
hashPic
(
pic
.
code
,
pic
.
type
)))
{
{
loadedList
.
Add
(
hashPic
(
pic
.
code
,
pic
.
type
),
pic
)
;
opaquePixelsInRow
++
;
}
}
}
}
else
if
(
opaquePixelsInRow
*
5
>
width
)
{
byte
[]
data
;
using
(
FileStream
file
=
new
FileStream
(
path
,
FileMode
.
Open
,
FileAccess
.
Read
))
{
file
.
Seek
(
0
,
SeekOrigin
.
Begin
);
data
=
new
byte
[
file
.
Length
];
file
.
Read
(
data
,
0
,
(
int
)
file
.
Length
);
}
pic
.
data
=
data
;
if
(!
loadedList
.
ContainsKey
(
hashPic
(
pic
.
code
,
pic
.
type
)))
{
{
loadedList
.
Add
(
hashPic
(
pic
.
code
,
pic
.
type
),
pic
);
lastVisibleRow
=
y
;
break
;
}
}
}
}
pic
.
k
=
(
float
)(
lastVisibleRow
+
1
)
/
(
float
)
height
;
pic
.
k
=
Mathf
.
Clamp
(
pic
.
k
,
0.1f
,
1.0f
);
}
}
catch
(
Exception
e
)
{
Debug
.
Log
(
"e 2"
+
e
.
ToString
());
#
endregion
}
}
#
region
---
工具方法和初始化
---
private
static
UInt64
hashPic
(
long
code
,
GameTextureType
type
)
private
static
UInt64
hashPic
(
long
code
,
GameTextureType
type
)
{
{
return
((
(
UInt64
)
type
<<
32
)
|
((
UInt64
)
code
))
;
return
((
UInt64
)
type
<<
32
)
|
(
UInt64
)(
uint
)
code
;
}
}
public
static
Texture2D
get
(
long
code
,
GameTextureType
type
,
Texture2D
nullReturnValue
=
null
)
private
static
void
Destroy
(
UnityEngine
.
Object
obj
)
{
try
{
{
PictureResource
r
;
if
(
Application
.
isPlaying
)
if
(
loadedList
.
TryGetValue
(
hashPic
(
code
,
type
),
out
r
))
{
{
Texture2D
re
=
null
;
UnityEngine
.
Object
.
Destroy
(
obj
);
if
(
r
.
u_data
!=
null
)
{
if
(
r
.
u_data
==
myBack
)
{
return
nullReturnValue
;
}
}
else
else
{
{
return
r
.
u_data
;
// 在编辑器模式下且非播放状态时使用 DestroyImmediate
UnityEngine
.
Object
.
DestroyImmediate
(
obj
);
}
}
}
}
if
(
r
.
data
!=
null
)
{
// 省略UI部分和静态资源定义,它们与原版类似,但get(string)方法已优化
re
=
new
Texture2D
(
400
,
600
);
public
static
Texture2D
myBack
,
opBack
,
unknown
,
attack
,
negated
,
bar
,
exBar
,
lp
,
time
,
L
,
R
,
Chain
,
Mask
,
N
;
re
.
LoadImage
(
r
.
data
);
public
static
Texture2D
nt
,
bp
,
ep
,
mp1
,
mp2
,
dp
,
sp
,
phase
,
rs
,
ts
,
LINK
,
LINKm
;
r
.
u_data
=
re
;
public
static
bool
AutoPicDownload
;
return
re
;
public
static
UnityEngine
.
Color
chainColor
=
UnityEngine
.
Color
.
white
;
}
public
static
bool
uiLoaded
=
false
;
if
(
r
.
hashed_data
!=
null
)
private
static
Dictionary
<
string
,
Texture2D
>
_uiCache
=
new
Dictionary
<
string
,
Texture2D
>();
public
static
Texture2D
get
(
string
name
)
{
{
int
width
=
r
.
hashed_data
.
GetLength
(
0
);
if
(!
uiLoaded
)
int
height
=
r
.
hashed_data
.
GetLength
(
1
);
UnityEngine
.
Color
[]
cols
=
new
UnityEngine
.
Color
[
width
*
height
];
re
=
new
Texture2D
(
width
,
height
);
for
(
int
h
=
0
;
h
<
height
;
h
++)
{
{
for
(
int
w
=
0
;
w
<
width
;
w
++)
uiLoaded
=
true
;
string
uiPath
=
"textures/ui"
;
if
(
Directory
.
Exists
(
uiPath
))
{
{
cols
[
h
*
width
+
w
]
=
new
UnityEngine
.
Color
(
FileInfo
[]
fileInfos
=
(
new
DirectoryInfo
(
uiPath
)).
GetFiles
(
"*.png"
);
r
.
hashed_data
[
w
,
h
,
0
],
foreach
(
var
fileInfo
in
fileInfos
)
r
.
hashed_data
[
w
,
h
,
1
],
r
.
hashed_data
[
w
,
h
,
2
],
r
.
hashed_data
[
w
,
h
,
3
]
);
}
}
re
.
SetPixels
(
0
,
0
,
width
,
height
,
cols
);
re
.
Apply
();
r
.
u_data
=
re
;
return
re
;
}
}
else
{
{
if
(!
addedMap
.
ContainsKey
(
hashPic
(
code
,
type
)))
string
key
=
Path
.
GetFileNameWithoutExtension
(
fileInfo
.
Name
);
if
(!
_uiCache
.
ContainsKey
(
key
))
{
{
PictureResource
a
=
new
PictureResource
(
type
,
code
,
nullReturnValue
);
// 这里假设UIHelper.getTexture2D是同步加载,如果也是异步需要相应修改
bLock
=
true
;
Texture2D
tex
=
UIHelper
.
getTexture2D
(
fileInfo
.
FullName
);
waitLoadStack
.
Push
(
a
);
_uiCache
.
Add
(
key
,
tex
);
bLock
=
false
;
addedMap
.
Add
((
UInt64
)
type
<<
32
|
(
UInt64
)
code
,
true
);
}
}
}
}
}
}
catch
(
Exception
e
)
{
Debug
.
Log
(
"BIGERROR1:"
+
e
.
ToString
());
}
}
return
null
;
Texture2D
result
=
null
;
_uiCache
.
TryGetValue
(
name
,
out
result
);
return
result
;
}
}
public
static
float
getK
(
long
code
,
GameTextureType
type
)
// 清理方法也需要加锁
public
static
void
clearUnloaded
()
{
{
float
ret
=
1
;
lock
(
_lock
)
PictureResource
r
;
if
(
loadedList
.
TryGetValue
(
hashPic
(
code
,
type
),
out
r
))
{
{
ret
=
r
.
k
;
_requestStack
.
Clear
();
_requestedSet
.
Clear
();
}
}
return
ret
;
}
}
public
static
bool
uiLoaded
=
false
;
public
static
void
clearAll
()
public
static
Texture2D
get
(
string
name
)
{
{
if
(
uiLoaded
==
false
)
lock
(
_lock
)
{
{
uiLoaded
=
true
;
_requestStack
.
Clear
();
FileInfo
[]
fileInfos
=
(
new
DirectoryInfo
(
"textures/ui"
)).
GetFiles
();
//YGOMobile Paths
_mainThreadApplyQueue
.
Clear
();
for
(
int
i
=
0
;
i
<
fileInfos
.
Length
;
i
++)
foreach
(
var
pair
in
_loadedCache
)
{
{
if
(
fileInfos
[
i
].
Name
.
Length
>
4
)
if
(
pair
.
Value
.
finalTexture
!=
null
&&
pair
.
Value
.
finalTexture
!=
N
)
{
{
if
(
fileInfos
[
i
].
Name
.
Substring
(
fileInfos
[
i
].
Name
.
Length
-
4
,
4
)
==
".png"
)
// 确保不销毁共享的静态纹理
if
(
pair
.
Value
.
finalTexture
!=
unknown
&&
pair
.
Value
.
finalTexture
!=
myBack
)
{
{
UIPictureResource
r
=
new
UIPictureResource
();
Destroy
(
pair
.
Value
.
finalTexture
);
r
.
name
=
fileInfos
[
i
].
Name
.
Substring
(
0
,
fileInfos
[
i
].
Name
.
Length
-
4
);
r
.
data
=
UIHelper
.
getTexture2D
(
"textures/ui/"
+
fileInfos
[
i
].
Name
);
//YGOMobile Paths
allUI
.
Add
(
r
);
}
}
}
}
}
}
_loadedCache
.
Clear
();
_requestedSet
.
Clear
();
}
}
Texture2D
re
=
null
;
for
(
int
i
=
0
;
i
<
allUI
.
size
;
i
++)
{
if
(
allUI
[
i
].
name
==
name
)
{
re
=
allUI
[
i
].
data
;
break
;
}
}
if
(
re
==
null
)
{
}
return
re
;
}
}
public
static
UnityEngine
.
Color
chainColor
=
UnityEngine
.
Color
.
white
;
// 初始化方法
public
static
void
InitializeAssets
()
internal
static
void
Initialize
()
{
{
if
(
IsInitialized
)
return
;
attack
=
UIHelper
.
getTexture2D
(
"textures/attack.png"
);
//YGOMobile Paths
attack
=
UIHelper
.
getTexture2D
(
"textures/attack.png"
);
//YGOMobile Paths
myBack
=
UIHelper
.
getTexture2D
(
"textures/cover.jpg"
);
//YGOMobile Paths
myBack
=
UIHelper
.
getTexture2D
(
"textures/cover.jpg"
);
//YGOMobile Paths
opBack
=
UIHelper
.
getTexture2D
(
"textures/cover2.jpg"
);
//YGOMobile Paths
opBack
=
UIHelper
.
getTexture2D
(
"textures/cover2.jpg"
);
//YGOMobile Paths
...
@@ -1122,27 +696,33 @@ public class GameTextureManager
...
@@ -1122,27 +696,33 @@ public class GameTextureManager
rs
=
UIHelper
.
getTexture2D
(
"textures/duel/phase/rs.png"
);
//YGOMobile Paths
rs
=
UIHelper
.
getTexture2D
(
"textures/duel/phase/rs.png"
);
//YGOMobile Paths
ts
=
UIHelper
.
getTexture2D
(
"textures/duel/phase/ts.png"
);
//YGOMobile Paths
ts
=
UIHelper
.
getTexture2D
(
"textures/duel/phase/ts.png"
);
//YGOMobile Paths
N
=
new
Texture2D
(
10
,
10
);
// 创建一个1x1的透明纹理,用于失败时的占位符
for
(
int
i
=
0
;
i
<
10
;
i
++)
N
=
new
Texture2D
(
1
,
1
,
TextureFormat
.
RGBA32
,
false
);
{
N
.
SetPixel
(
0
,
0
,
new
Color
(
0
,
0
,
0
,
0
));
for
(
int
a
=
0
;
a
<
10
;
a
++)
{
N
.
SetPixel
(
i
,
a
,
new
UnityEngine
.
Color
(
0
,
0
,
0
,
0
));
}
}
N
.
Apply
();
N
.
Apply
();
try
try
{
{
ColorUtility
.
TryParseHtmlString
(
ColorUtility
.
TryParseHtmlString
(
File
.
ReadAllText
(
"textures/duel/chainColor.txt"
),
out
chainColor
);
File
.
ReadAllText
(
"textures/duel/chainColor.txt"
),
out
chainColor
);
//YGOMobile Paths
}
}
catch
(
Exception
)
{
}
catch
(
Exception
)
{
}
if
(
main_thread
==
null
)
// 标记为初始化完成
IsInitialized
=
true
;
Debug
.
Log
(
"[GameTextureManager] Assets initialized successfully."
);
}
// NEW: 这个方法现在只负责启动后台线程
public
static
void
StartBackgroundThread
()
{
if
(
_ioThread
==
null
)
{
{
main_thread
=
new
Thread
(
thread_run
);
_isRunning
=
true
;
main_thread
.
Start
();
_ioThread
=
new
Thread
(
IoThreadRun
);
_ioThread
.
IsBackground
=
true
;
// 确保主程序退出时线程也退出
_ioThread
.
Start
();
Debug
.
Log
(
"[GameTextureManager] Background I/O thread started."
);
}
}
}
}
#
endregion
}
}
\ No newline at end of file
Assets/SibylSystem/ResourceManagers/GameTextureManagerRunner.cs
deleted
100644 → 0
View file @
a992169d
using
System.Collections
;
using
UnityEngine
;
/// <summary>
/// 这是一个 MonoBehaviour 帮助器,专为静态的 GameTextureManager 服务。
/// 它的职责是在主线程上执行任务,例如轮询下载队列和启动协程。
/// 这个类的实例由 GameTextureManager 通过 [RuntimeInitializeOnLoadMethod] 自动创建。
/// </summary>
public
class
GameTextureManagerRunner
:
MonoBehaviour
{
void
Update
()
{
// 在主线程的每一帧检查是否有待处理的下载请求
if
(
GameTextureManager
.
HasDownloadRequests
())
{
// 从 GameTextureManager 获取一个请求
var
request
=
GameTextureManager
.
GetNextDownloadRequest
();
// 使用这个 MonoBehaviour 实例来启动下载协程
StartCoroutine
(
GameTextureManager
.
DownloadAndProcessFile
(
request
));
}
}
}
Assets/SibylSystem/ResourceManagers/GameTextureManagerRunner.cs.meta
deleted
100644 → 0
View file @
a992169d
fileFormatVersion: 2
guid: cb7d20dd5a7074bc089a6c75c87e34da
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
Assets/SibylSystem/ResourceManagers/UnityFileDownloader.cs
View file @
3e267a81
...
@@ -15,12 +15,22 @@ public class UnityFileDownloader
...
@@ -15,12 +15,22 @@ public class UnityFileDownloader
Action
<
bool
>
onComplete
,
Action
<
bool
>
onComplete
,
Action
<
float
>
onProgress
=
null
Action
<
float
>
onProgress
=
null
)
)
{
// 确保目录存在
try
{
{
string
directoryPath
=
Path
.
GetDirectoryName
(
filePath
);
string
directoryPath
=
Path
.
GetDirectoryName
(
filePath
);
if
(!
Directory
.
Exists
(
directoryPath
))
if
(!
Directory
.
Exists
(
directoryPath
))
{
{
Directory
.
CreateDirectory
(
directoryPath
);
Directory
.
CreateDirectory
(
directoryPath
);
}
}
}
catch
(
Exception
e
)
{
Debug
.
LogError
(
"Failed to create directory for "
+
filePath
+
". Error: "
+
e
.
Message
);
if
(
onComplete
!=
null
)
onComplete
.
Invoke
(
false
);
yield
break
;
// 提前退出协程
}
string
tempFilePath
=
filePath
+
".tmp"
;
string
tempFilePath
=
filePath
+
".tmp"
;
if
(
File
.
Exists
(
tempFilePath
))
if
(
File
.
Exists
(
tempFilePath
))
...
@@ -28,6 +38,8 @@ public class UnityFileDownloader
...
@@ -28,6 +38,8 @@ public class UnityFileDownloader
File
.
Delete
(
tempFilePath
);
File
.
Delete
(
tempFilePath
);
}
}
Debug
.
Log
(
string
.
Format
(
"Downloading: {0} -> {1}"
,
url
,
filePath
));
using
(
UnityWebRequest
uwr
=
new
UnityWebRequest
(
url
,
UnityWebRequest
.
kHttpVerbGET
))
using
(
UnityWebRequest
uwr
=
new
UnityWebRequest
(
url
,
UnityWebRequest
.
kHttpVerbGET
))
{
{
uwr
.
downloadHandler
=
new
DownloadHandlerFile
(
tempFilePath
);
uwr
.
downloadHandler
=
new
DownloadHandlerFile
(
tempFilePath
);
...
@@ -80,15 +92,15 @@ public class UnityFileDownloader
...
@@ -80,15 +92,15 @@ public class UnityFileDownloader
switch
(
extension
)
switch
(
extension
)
{
{
case
".png"
:
case
".png"
:
return
2
0
;
return
4
0
;
case
".jpg"
:
case
".jpg"
:
return
2
0
;
return
4
0
;
case
".cdb"
:
case
".cdb"
:
return
5
0
;
return
8
0
;
case
".conf"
:
case
".conf"
:
return
2
0
;
return
4
0
;
default
:
default
:
return
2
0
;
return
4
0
;
}
}
}
}
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment