// 1. 비동기 요청
mtd
.
Request
(()
=>
res1
=
Random
.
Range
(
0
,
1000
));
Debug
.
Log
(
res1
);
// 2. await를 통한 대기 - Action
await
mtd
.
RequestAsync
(()
=>
{
res2
=
Random
.
Range
(
0
,
1000
);
});
Debug
.
Log
(
res2
);
// 3. await를 통한 대기 - Func<int>
Task
<
int
>
resultTask
=
mtd
.
RequestAsync
(()
=>
Random
.
Range
(
0
,
1000
));
await
resultTask
;
Debug
.
Log
(
resultTask
.
Result
);
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
https://github.com/PimDeWitte/UnityMainThreadDispatcher
// 날짜 : 2021-06-30 AM 2:56:52
using
UnityEngine
;
using
System
;
using
System.Collections
;
using
System.Collections.Generic
;
using
System.Threading
;
using
System.Threading.Tasks
;
using
MTD
=
MainThreadDispatcher
;
public
class
MainThreadDispatcher
:
MonoBehaviour
/***********************************************************************
* Singleton
***********************************************************************/
#
region
.
private
static
MTD
_instance
;
public
static
MTD
Instance
if
(
_instance
==
null
)
_instance
=
FindObjectOfType
<
MTD
>();
if
(
_instance
==
null
)
GameObject
container
=
new
GameObject
(
$"Main Thread Dispatcher"
);
_instance
=
container
.
AddComponent
<
MTD
>();
return
_instance
;
private
void
Awake
()
if
(
_instance
==
null
)
_instance
=
this
;
transform
.
SetParent
(
null
);
DontDestroyOnLoad
(
this
);
if
(
_instance
!=
this
)
if
(
GetComponents
<
Component
>().
Length
<=
2
)
Destroy
(
gameObject
);
Destroy
(
this
);
#
endregion
private
static
readonly
Queue
<
Action
>
_executionQueue
=
new
Queue
<
Action
>();
private
void
Update
()
lock
(
_executionQueue
)
while
(
_executionQueue
.
Count
>
0
)
_executionQueue
.
Dequeue
().
Invoke
();
/// <summary> 메인 스레드에 작업 요청(코루틴) </summary>
public
void
Request
(
IEnumerator
coroutine
)
lock
(
_executionQueue
)
_executionQueue
.
Enqueue
(()
=>
StartCoroutine
(
coroutine
);
/// <summary> 메인 스레드에 작업 요청(메소드) </summary>
public
void
Request
(
Action
action
)
Request
(
ActionWrapper
(
action
));
/// <summary> 메인 스레드에 작업 요청 및 대기(await) </summary>
public
Task
RequestAsync
(
Action
action
)
var
tcs
=
new
TaskCompletionSource
<
bool
>();
void
WrappedAction
()
action
();
tcs
.
TrySetResult
(
true
);
catch
(
Exception
ex
)
tcs
.
TrySetException
(
ex
);
Request
(
ActionWrapper
(
WrappedAction
));
return
tcs
.
Task
;
/// <summary> 메인 스레드에 작업 요청 및 대기(await) + 값 받아오기 </summary>
public
Task
<
T
>
RequestAsync
<
T
>(
Func
<
T
>
action
)
var
tcs
=
new
TaskCompletionSource
<
T
>();
void
WrappedAction
()
var
result
=
action
();
tcs
.
TrySetResult
(
result
);
catch
(
Exception
ex
)
tcs
.
TrySetException
(
ex
);
Request
(
ActionWrapper
(
WrappedAction
));
return
tcs
.
Task
;
/// <summary> Action을 코루틴으로 래핑 </summary>
private
IEnumerator
ActionWrapper
(
Action
a
)
a
();
yield
return
null
;
메소드로만 사용하던 GetComponent(), Find() 기능들을 필드/프로퍼티 애트리뷰트로 간편하게 사용할 수 있다.
리플렉션과 커스텀 애트리뷰트를 활용하여 제작하였다.
Component를 상속받는 타입의 필드/프로퍼티에 사용할 수 있다.
대상 멤버의 접근지정자에 관계 없이 모두 동작한다.
본 애트리...