Add Delay node to Visual Scripting
This commit is contained in:
@@ -293,6 +293,21 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
NodeElementArchetype.Factory.Input(1, "Value", true, null, 1),
|
NodeElementArchetype.Factory.Input(1, "Value", true, null, 1),
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
new NodeArchetype
|
||||||
|
{
|
||||||
|
TypeID = 6,
|
||||||
|
Title = "Delay",
|
||||||
|
Description = "Delays the graph execution. If delay is 0 then it will pass though.",
|
||||||
|
Flags = NodeFlags.VisualScriptGraph,
|
||||||
|
Size = new Vector2(150, 40),
|
||||||
|
DefaultValues = new object[] { 1.0f },
|
||||||
|
Elements = new[]
|
||||||
|
{
|
||||||
|
NodeElementArchetype.Factory.Input(0, string.Empty, true, typeof(void), 0),
|
||||||
|
NodeElementArchetype.Factory.Input(1, "Duration", true, typeof(float), 1, 0),
|
||||||
|
NodeElementArchetype.Factory.Output(0, string.Empty, typeof(void), 2, true),
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -677,19 +677,21 @@ namespace FlaxEditor.Surface.Archetypes
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ThisNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch)
|
public ThisNode(uint id, VisjectSurfaceContext context, NodeArchetype nodeArch, GroupArchetype groupArch)
|
||||||
: base(id, context, nodeArch, groupArch)
|
: base(id, context, nodeArch, groupArch)
|
||||||
{}
|
{
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void OnLoaded()
|
public override void OnLoaded()
|
||||||
{
|
{
|
||||||
base.OnLoaded();
|
base.OnLoaded();
|
||||||
var vss = (VisualScriptSurface)this.Context.Surface;
|
|
||||||
var type = TypeUtils.GetType(vss.Script.ScriptTypeName);
|
var surface = (VisualScriptSurface)Context.Surface;
|
||||||
|
var type = TypeUtils.GetType(surface.Script.ScriptTypeName);
|
||||||
var box = (OutputBox)GetBox(0);
|
var box = (OutputBox)GetBox(0);
|
||||||
box.CurrentType = type ? type : new ScriptType(typeof(VisualScript));
|
box.CurrentType = type ? type : new ScriptType(typeof(VisualScript));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AssetReferenceNode : SurfaceNode
|
private class AssetReferenceNode : SurfaceNode
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "Engine/Serialization/JsonWriter.h"
|
#include "Engine/Serialization/JsonWriter.h"
|
||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
#include "Engine/Utilities/StringConverter.h"
|
#include "Engine/Utilities/StringConverter.h"
|
||||||
|
#include "Engine/Threading/MainThreadTask.h"
|
||||||
#include "FlaxEngine.Gen.h"
|
#include "FlaxEngine.Gen.h"
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
@@ -83,6 +84,41 @@ VisualScriptExecutor::VisualScriptExecutor()
|
|||||||
_perGroupProcessCall[17] = (ProcessBoxHandler)&VisualScriptExecutor::ProcessGroupFlow;
|
_perGroupProcessCall[17] = (ProcessBoxHandler)&VisualScriptExecutor::ProcessGroupFlow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VisualScriptExecutor::Invoke(const Guid& scriptId, int32 nodeId, int32 boxId, const Guid& instanceId, Variant& result) const
|
||||||
|
{
|
||||||
|
auto script = Content::Load<VisualScript>(scriptId);
|
||||||
|
if (!script)
|
||||||
|
return;
|
||||||
|
const auto node = script->Graph.GetNode(nodeId);
|
||||||
|
if (!node)
|
||||||
|
return;
|
||||||
|
const auto box = node->GetBox(boxId);
|
||||||
|
if (!box)
|
||||||
|
return;
|
||||||
|
auto instance = Scripting::FindObject<ScriptingObject>(instanceId);
|
||||||
|
|
||||||
|
// Add to the calling stack
|
||||||
|
VisualScripting::ScopeContext scope;
|
||||||
|
auto& stack = ThreadStacks.Get();
|
||||||
|
VisualScripting::StackFrame frame;
|
||||||
|
frame.Script = script;
|
||||||
|
frame.Node = node;
|
||||||
|
frame.Box = box;
|
||||||
|
frame.Instance = instance;
|
||||||
|
frame.PreviousFrame = stack.Stack;
|
||||||
|
frame.Scope = &scope;
|
||||||
|
stack.Stack = &frame;
|
||||||
|
stack.StackFramesCount++;
|
||||||
|
|
||||||
|
// Call per group custom processing event
|
||||||
|
const auto func = VisualScriptingExecutor._perGroupProcessCall[node->GroupID];
|
||||||
|
(VisualScriptingExecutor.*func)(box, node, result);
|
||||||
|
|
||||||
|
// Remove from the calling stack
|
||||||
|
stack.StackFramesCount--;
|
||||||
|
stack.Stack = frame.PreviousFrame;
|
||||||
|
}
|
||||||
|
|
||||||
VisjectExecutor::Value VisualScriptExecutor::eatBox(Node* caller, Box* box)
|
VisjectExecutor::Value VisualScriptExecutor::eatBox(Node* caller, Box* box)
|
||||||
{
|
{
|
||||||
// Check if graph is looped or is too deep
|
// Check if graph is looped or is too deep
|
||||||
@@ -1273,6 +1309,46 @@ void VisualScriptExecutor::ProcessGroupFlow(Box* boxBase, Node* node, Value& val
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
// Delay
|
||||||
|
case 6:
|
||||||
|
{
|
||||||
|
boxBase = node->GetBox(2);
|
||||||
|
if (!boxBase->HasConnection())
|
||||||
|
break;
|
||||||
|
const float duration = (float)tryGetValue(node->GetBox(1), node->Values[0]);
|
||||||
|
if (duration > ZeroTolerance)
|
||||||
|
{
|
||||||
|
class DelayTask : public MainThreadTask
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Guid Script;
|
||||||
|
Guid Instance;
|
||||||
|
int32 Node;
|
||||||
|
int32 Box;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool Run() override
|
||||||
|
{
|
||||||
|
Variant result;
|
||||||
|
VisualScriptingExecutor.Invoke(Script, Node, Box, Instance, result);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const auto& stack = ThreadStacks.Get().Stack;
|
||||||
|
auto task = New<DelayTask>();
|
||||||
|
task->Script = stack->Script->GetID();;
|
||||||
|
task->Instance = stack->Instance->GetID();;
|
||||||
|
task->Node = ((Node*)boxBase->FirstConnection()->Parent)->ID;
|
||||||
|
task->Box = boxBase->FirstConnection()->ID;
|
||||||
|
task->InitialDelay = duration;
|
||||||
|
task->Start();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
eatBox(node, boxBase->FirstConnection());
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,6 +36,8 @@ public:
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
VisualScriptExecutor();
|
VisualScriptExecutor();
|
||||||
|
|
||||||
|
void Invoke(const Guid& scriptId, int32 nodeId, int32 boxId, const Guid& instanceId, Variant& result) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Value eatBox(Node* caller, Box* box) override;
|
Value eatBox(Node* caller, Box* box) override;
|
||||||
Graph* GetCurrentGraph() const override;
|
Graph* GetCurrentGraph() const override;
|
||||||
|
|||||||
@@ -288,7 +288,7 @@ void Engine::OnUpdate()
|
|||||||
// Simulate lags
|
// Simulate lags
|
||||||
//Platform::Sleep(100);
|
//Platform::Sleep(100);
|
||||||
|
|
||||||
MainThreadTask::RunAll();
|
MainThreadTask::RunAll(Time::Update.UnscaledDeltaTime.GetTotalSeconds());
|
||||||
|
|
||||||
// Call event
|
// Call event
|
||||||
Update();
|
Update();
|
||||||
|
|||||||
@@ -1,25 +1,68 @@
|
|||||||
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
// Copyright (c) 2012-2021 Wojciech Figat. All rights reserved.
|
||||||
|
|
||||||
#include "MainThreadTask.h"
|
#include "MainThreadTask.h"
|
||||||
#include "ConcurrentTaskQueue.h"
|
#include "Engine/Platform/CriticalSection.h"
|
||||||
#include "Engine/Profiler/ProfilerCPU.h"
|
#include "Engine/Profiler/ProfilerCPU.h"
|
||||||
|
|
||||||
ConcurrentTaskQueue<MainThreadTask> MainThreadTasks;
|
namespace
|
||||||
|
|
||||||
void MainThreadTask::RunAll()
|
|
||||||
{
|
{
|
||||||
// TODO: use bulk dequeue
|
CriticalSection Locker;
|
||||||
|
Array<MainThreadTask*> Waiting;
|
||||||
|
Array<MainThreadTask*> Queue;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainThreadTask::RunAll(float dt)
|
||||||
|
{
|
||||||
PROFILE_CPU();
|
PROFILE_CPU();
|
||||||
|
Locker.Lock();
|
||||||
MainThreadTask* task;
|
for (int32 i = Waiting.Count() - 1; i >= 0; i--)
|
||||||
while (MainThreadTasks.try_dequeue(task))
|
|
||||||
{
|
{
|
||||||
task->Execute();
|
auto task = Waiting[i];
|
||||||
|
task->InitialDelay -= dt;
|
||||||
|
if (task->InitialDelay < ZeroTolerance)
|
||||||
|
{
|
||||||
|
Waiting.RemoveAt(i);
|
||||||
|
Queue.Add(task);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
for (int32 i = 0; i < Queue.Count(); i++)
|
||||||
|
{
|
||||||
|
Queue[i]->Execute();
|
||||||
|
}
|
||||||
|
Queue.Clear();
|
||||||
|
Locker.Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
String MainThreadTask::ToString() const
|
||||||
|
{
|
||||||
|
return String::Format(TEXT("Main Thread Task ({0})"), ::ToString(GetState()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainThreadTask::Enqueue()
|
void MainThreadTask::Enqueue()
|
||||||
{
|
{
|
||||||
MainThreadTasks.Add(this);
|
Locker.Lock();
|
||||||
|
if (InitialDelay <= ZeroTolerance)
|
||||||
|
Queue.Add(this);
|
||||||
|
else
|
||||||
|
Waiting.Add(this);
|
||||||
|
Locker.Unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainThreadActionTask::Run()
|
||||||
|
{
|
||||||
|
if (_action1.IsBinded())
|
||||||
|
{
|
||||||
|
_action1();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (_action2.IsBinded())
|
||||||
|
{
|
||||||
|
return _action2();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MainThreadActionTask::HasReference(Object* obj) const
|
||||||
|
{
|
||||||
|
return obj == _target;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,36 +24,20 @@
|
|||||||
class FLAXENGINE_API MainThreadTask : public Task
|
class FLAXENGINE_API MainThreadTask : public Task
|
||||||
{
|
{
|
||||||
friend class Engine;
|
friend class Engine;
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="MainThreadTask"/> class.
|
|
||||||
/// </summary>
|
|
||||||
MainThreadTask()
|
|
||||||
: Task()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static void RunAll(float dt);
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Runs all main thread tasks. Called only by the Engine class.
|
/// The initial time delay (in seconds) before task execution. Use 0 to skip this feature.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
static void RunAll();
|
float InitialDelay = 0.0f;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// [Task]
|
// [Task]
|
||||||
String ToString() const override
|
String ToString() const override;
|
||||||
{
|
|
||||||
return String::Format(TEXT("Main Thread Task ({0})"), ::ToString(GetState()));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool HasReference(Object* obj) const override
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
@@ -127,27 +111,10 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
|
|
||||||
// [MainThreadTask]
|
// [MainThreadTask]
|
||||||
bool Run() override
|
bool Run() override;
|
||||||
{
|
|
||||||
if (_action1.IsBinded())
|
|
||||||
{
|
|
||||||
_action1();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_action2.IsBinded())
|
|
||||||
{
|
|
||||||
return _action2();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
// [MainThreadTask]
|
// [MainThreadTask]
|
||||||
bool HasReference(Object* obj) const override
|
bool HasReference(Object* obj) const override;
|
||||||
{
|
|
||||||
return obj == _target;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -108,45 +108,6 @@ Task* Task::ContinueWith(Function<bool()> action, Object* target)
|
|||||||
return ContinueWith(New<ThreadPoolActionTask>(action, target));
|
return ContinueWith(New<ThreadPoolActionTask>(action, target));
|
||||||
}
|
}
|
||||||
|
|
||||||
Task* Task::Delay(int32 milliseconds)
|
|
||||||
{
|
|
||||||
class DelayTask : public ThreadPoolTask
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
|
|
||||||
int32 _milliseconds;
|
|
||||||
DateTime _startTimeUTC;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
DelayTask(int32 milliseconds)
|
|
||||||
: _milliseconds(milliseconds)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
// [ThreadPoolTask]
|
|
||||||
bool Run() override
|
|
||||||
{
|
|
||||||
// Take into account the different between task enqueue (OnStart event) and the actual task execution
|
|
||||||
auto diff = DateTime::NowUTC() - _startTimeUTC;
|
|
||||||
auto ms = Math::Max(0, _milliseconds - (int32)diff.GetTotalMilliseconds());
|
|
||||||
|
|
||||||
Platform::Sleep(ms);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnStart() override
|
|
||||||
{
|
|
||||||
_startTimeUTC = DateTime::NowUTC();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return New<DelayTask>(milliseconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
Task* Task::StartNew(Task* task)
|
Task* Task::StartNew(Task* task)
|
||||||
{
|
{
|
||||||
ASSERT(task);
|
ASSERT(task);
|
||||||
|
|||||||
@@ -45,36 +45,23 @@ protected:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The cancel flag used to indicate that there is request to cancel task operation.
|
/// The cancel flag used to indicate that there is request to cancel task operation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
volatile int64 _cancelFlag;
|
volatile int64 _cancelFlag = 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current task state.
|
/// The current task state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
volatile TaskState _state;
|
volatile TaskState _state = TaskState::Created;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The task to start after finish.
|
/// The task to start after finish.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
Task* _continueWith;
|
Task* _continueWith = nullptr;
|
||||||
|
|
||||||
protected:
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="Task"/> class.
|
|
||||||
/// </summary>
|
|
||||||
Task()
|
|
||||||
: _cancelFlag(0)
|
|
||||||
, _state(TaskState::Created)
|
|
||||||
, _continueWith(nullptr)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets work state
|
/// Gets the task state.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>State</returns>
|
|
||||||
FORCE_INLINE TaskState GetState() const
|
FORCE_INLINE TaskState GetState() const
|
||||||
{
|
{
|
||||||
return static_cast<TaskState>(Platform::AtomicRead((int64 volatile*)&_state));
|
return static_cast<TaskState>(Platform::AtomicRead((int64 volatile*)&_state));
|
||||||
@@ -93,7 +80,6 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the task to start after this one.
|
/// Gets the task to start after this one.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>The next task.</returns>
|
|
||||||
FORCE_INLINE Task* GetContinueWithTask() const
|
FORCE_INLINE Task* GetContinueWithTask() const
|
||||||
{
|
{
|
||||||
return _continueWith;
|
return _continueWith;
|
||||||
@@ -102,45 +88,40 @@ public:
|
|||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if operation failed
|
/// Checks if operation failed.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>True if operation failed, otherwise false</returns>
|
|
||||||
FORCE_INLINE bool IsFailed() const
|
FORCE_INLINE bool IsFailed() const
|
||||||
{
|
{
|
||||||
return GetState() == TaskState::Failed;
|
return GetState() == TaskState::Failed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if operation has been canceled
|
/// Checks if operation has been canceled.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>True if operation has been canceled, otherwise false</returns>
|
|
||||||
FORCE_INLINE bool IsCanceled() const
|
FORCE_INLINE bool IsCanceled() const
|
||||||
{
|
{
|
||||||
return GetState() == TaskState::Canceled;
|
return GetState() == TaskState::Canceled;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if operation has been queued
|
/// Checks if operation has been queued.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>True if operation has been queued, otherwise false</returns>
|
|
||||||
FORCE_INLINE bool IsQueued() const
|
FORCE_INLINE bool IsQueued() const
|
||||||
{
|
{
|
||||||
return GetState() == TaskState::Queued;
|
return GetState() == TaskState::Queued;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if operation is running
|
/// Checks if operation is running.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>True if operation is running, otherwise false</returns>
|
|
||||||
FORCE_INLINE bool IsRunning() const
|
FORCE_INLINE bool IsRunning() const
|
||||||
{
|
{
|
||||||
return GetState() == TaskState::Running;
|
return GetState() == TaskState::Running;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if operation has been finished
|
/// Checks if operation has been finished.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>True if operation has been finished, otherwise false</returns>
|
|
||||||
FORCE_INLINE bool IsFinished() const
|
FORCE_INLINE bool IsFinished() const
|
||||||
{
|
{
|
||||||
return GetState() == TaskState::Finished;
|
return GetState() == TaskState::Finished;
|
||||||
@@ -149,7 +130,6 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Checks if operation has been ended (via cancel, fail or finish).
|
/// Checks if operation has been ended (via cancel, fail or finish).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>True if operation has been ended, otherwise false</returns>
|
|
||||||
bool IsEnded() const
|
bool IsEnded() const
|
||||||
{
|
{
|
||||||
auto state = GetState();
|
auto state = GetState();
|
||||||
@@ -159,7 +139,6 @@ public:
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns true if task has been requested to cancel it's operation.
|
/// Returns true if task has been requested to cancel it's operation.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <returns>True if task has been canceled and should stop it's work without calling child task start.</returns>
|
|
||||||
FORCE_INLINE bool IsCancelRequested()
|
FORCE_INLINE bool IsCancelRequested()
|
||||||
{
|
{
|
||||||
return Platform::AtomicRead(&_cancelFlag) != 0;
|
return Platform::AtomicRead(&_cancelFlag) != 0;
|
||||||
@@ -244,25 +223,6 @@ public:
|
|||||||
/// <returns>Enqueued task.</returns>
|
/// <returns>Enqueued task.</returns>
|
||||||
Task* ContinueWith(Function<bool()> action, Object* target = nullptr);
|
Task* ContinueWith(Function<bool()> action, Object* target = nullptr);
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a task that completes after a specified time interval (not started).
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="delay">The time span to wait before completing the returned task.</param>
|
|
||||||
/// <returns>A task that represents the time delay (not started).</returns>
|
|
||||||
FORCE_INLINE static Task* Delay(const TimeSpan& delay)
|
|
||||||
{
|
|
||||||
return Delay(static_cast<int32>(delay.GetTotalMilliseconds()));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Creates a task that completes after a specified time interval (not started).
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="milliseconds">The amount of milliseconds to wait before completing the returned task.</param>
|
|
||||||
/// <returns>A task that represents the time delay (not started).</returns>
|
|
||||||
static Task* Delay(int32 milliseconds);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
Reference in New Issue
Block a user