Update to Gamecraft 2020.06.11.18.50

Removed some inputs from FakeInput
This commit is contained in:
Norbi Peti 2020-06-12 17:27:36 +02:00
parent 3dcce18ceb
commit 62318b0843
11 changed files with 52 additions and 76 deletions

View file

@ -20,7 +20,7 @@ namespace GamecraftModdingAPI.Blocks
if (!entitiesDB.Exists<MachineGraphConnectionsEntityStruct>(target))
return false;
var connections = entitiesDB.QueryEntity<MachineGraphConnectionsEntityStruct>(target);
for (int i = connections.connections.Length - 1; i >= 0; i--)
for (int i = connections.connections.Count<MachineConnectionStruct>() - 1; i >= 0; i--)
_connectionFactory.RemoveConnection(connections, i, entitiesDB);
_entityFunctions.RemoveEntity<BlockEntityDescriptor>(target);
return true;

View file

@ -44,7 +44,7 @@ namespace GamecraftModdingAPI.Blocks
public bool SetSignal(uint signalID, float signal, bool input = true)
{
var array = GetSignalStruct(signalID, out uint index, input);
if (array != null) array[index].valueAsFloat = signal;
if (array.count > 0) array[index].valueAsFloat = signal;
return false;
}
@ -57,7 +57,7 @@ namespace GamecraftModdingAPI.Blocks
public float AddSignal(uint signalID, float signal, bool clamp = true, bool input = true)
{
var array = GetSignalStruct(signalID, out uint index, input);
if (array != null)
if (array.count > 0)
{
ref var channelData = ref array[index];
channelData.valueAsFloat += signal;
@ -88,7 +88,7 @@ namespace GamecraftModdingAPI.Blocks
public float GetSignal(uint signalID, bool input = true)
{
var array = GetSignalStruct(signalID, out uint index, input);
return array?[index].valueAsFloat ?? 0f;
return array.count > 0 ? array[index].valueAsFloat : 0f;
}
public uint[] GetSignalIDs(EGID blockID, bool input = true)
@ -136,8 +136,8 @@ namespace GamecraftModdingAPI.Blocks
public ref WireEntityStruct MatchPortToWire(EGID portID, EGID blockID, out bool exists)
{
ref PortEntityStruct port = ref entitiesDB.QueryEntity<PortEntityStruct>(portID);
WireEntityStruct[] wires = entitiesDB.QueryEntities<WireEntityStruct>(NamedExclusiveGroup<WiresGroup>.Group).ToFastAccess(out uint count);
for (uint i = 0; i < count; i++)
var wires = entitiesDB.QueryEntities<WireEntityStruct>(NamedExclusiveGroup<WiresGroup>.Group);
for (uint i = 0; i < wires.count; i++)
{
if ((wires[i].destinationPortUsage == port.usage && wires[i].destinationBlockEGID == blockID)
|| (wires[i].sourcePortUsage == port.usage && wires[i].sourceBlockEGID == blockID))
@ -154,8 +154,8 @@ namespace GamecraftModdingAPI.Blocks
public ref ChannelDataStruct GetChannelDataStruct(EGID portID, out bool exists)
{
ref PortEntityStruct port = ref entitiesDB.QueryEntity<PortEntityStruct>(portID);
ChannelDataStruct[] channels = entitiesDB.QueryEntities<ChannelDataStruct>(NamedExclusiveGroup<ChannelDataGroup>.Group).ToFastAccess(out uint count);
if (port.firstChannelIndexCachedInSim < count)
var channels = entitiesDB.QueryEntities<ChannelDataStruct>(NamedExclusiveGroup<ChannelDataGroup>.Group);
if (port.firstChannelIndexCachedInSim < channels.count)
{
exists = true;
return ref channels[port.firstChannelIndexCachedInSim];
@ -183,7 +183,7 @@ namespace GamecraftModdingAPI.Blocks
return res;
}
private ChannelDataStruct[] GetSignalStruct(uint signalID, out uint index, bool input = true)
private EntityCollection<ChannelDataStruct> GetSignalStruct(uint signalID, out uint index, bool input = true)
{
ExclusiveGroup group = input
? NamedExclusiveGroup<InputPortsGroup>.Group
@ -191,14 +191,13 @@ namespace GamecraftModdingAPI.Blocks
if (entitiesDB.Exists<PortEntityStruct>(signalID, group))
{
index = entitiesDB.QueryEntity<PortEntityStruct>(signalID, group).anyChannelIndex;
ChannelDataStruct[] channelData = entitiesDB
.QueryEntities<ChannelDataStruct>(NamedExclusiveGroup<ChannelDataGroup>.Group)
.ToFastAccess(out uint _);
var channelData =
entitiesDB.QueryEntities<ChannelDataStruct>(NamedExclusiveGroup<ChannelDataGroup>.Group);
return channelData;
}
index = 0;
return null;
return default; //count: 0
}
}
}

View file

@ -1,5 +1,4 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
@ -9,9 +8,6 @@ using HarmonyLib;
using Svelto.Context;
using Svelto.ECS;
using RobocraftX;
using RobocraftX.Multiplayer;
using RobocraftX.StateSync;
using Unity.Entities;
using GamecraftModdingAPI.Utility;
@ -27,7 +23,7 @@ namespace GamecraftModdingAPI.Commands
//[HarmonyPatch("Compose", new Type[] { typeof(UnityContext<FullGameCompositionRoot>), typeof(EnginesRoot), typeof(World), typeof(Action), typeof(MultiplayerInitParameters), typeof(StateSyncRegistrationHelper)})]
static class CommandPatch
{
public static void Postfix(object contextHolder, EnginesRoot enginesRoot, World physicsWorld, Action reloadGame, MultiplayerInitParameters multiplayerParameters, ref StateSyncRegistrationHelper stateSyncReg)
public static void Postfix(EnginesRoot enginesRoot)
{
// When a game is loaded, register the command engines
CommandManager.RegisterEngines(enginesRoot);

View file

@ -327,10 +327,6 @@
<HintPath>..\ref\Gamecraft_Data\Managed\Blocks.HUDFeedbackBlocks.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Blocks.HUDFeedbackBlocks.dll</HintPath>
</Reference>
<Reference Include="ChannelsCommon">
<HintPath>..\ref\Gamecraft_Data\Managed\ChannelsCommon.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\ChannelsCommon.dll</HintPath>
</Reference>
<Reference Include="ClusterToWireConversion.Mock">
<HintPath>..\ref\Gamecraft_Data\Managed\ClusterToWireConversion.Mock.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\ClusterToWireConversion.Mock.dll</HintPath>
@ -643,14 +639,6 @@
<HintPath>..\ref\Gamecraft_Data\Managed\Svelto.Common_3.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Svelto.Common_3.dll</HintPath>
</Reference>
<Reference Include="Svelto.ECS.Debugger">
<HintPath>..\ref\Gamecraft_Data\Managed\Svelto.ECS.Debugger.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Svelto.ECS.Debugger.dll</HintPath>
</Reference>
<Reference Include="Svelto.ECS.Debugger.Internal">
<HintPath>..\ref\Gamecraft_Data\Managed\Svelto.ECS.Debugger.Internal.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Svelto.ECS.Debugger.Internal.dll</HintPath>
</Reference>
<Reference Include="Svelto.ECS">
<HintPath>..\ref\Gamecraft_Data\Managed\Svelto.ECS.dll</HintPath>
<HintPath>..\..\ref\Gamecraft_Data\Managed\Svelto.ECS.dll</HintPath>

View file

@ -17,7 +17,7 @@ namespace GamecraftModdingAPI.Input
/// </summary>
/// <param name="input">The custom input.</param>
/// <param name="playerID">The player. Omit this to use the local player.</param>
public static void CustomInput(InputEntityStruct input, uint playerID = uint.MaxValue)
public static void CustomInput(LocalInputEntityStruct input, uint playerID = uint.MaxValue)
{
if (playerID == uint.MaxValue)
{
@ -26,7 +26,7 @@ namespace GamecraftModdingAPI.Input
inputEngine.SendCustomInput(input, playerID);
}
public static InputEntityStruct GetInput(uint playerID = uint.MaxValue)
public static LocalInputEntityStruct GetInput(uint playerID = uint.MaxValue)
{
if (playerID == uint.MaxValue)
{
@ -42,9 +42,7 @@ namespace GamecraftModdingAPI.Input
/// </summary>
/// <param name="playerID">The player. Omit this to use the local player.</param>
/// <param name="hotbar">Select the hotbar slot by number.</param>
/// <param name="hotbarHand">Select the hotbar hand.</param>
/// <param name="commandLine">Toggle the command line?</param>
/// <param name="inventory">Open inventory?</param>
/// <param name="escape">Open escape menu?</param>
/// <param name="enter">Page return?</param>
/// <param name="debug">Toggle debug display?</param>
@ -55,13 +53,13 @@ namespace GamecraftModdingAPI.Input
/// <param name="hotbarPage">Select the hotbar page by number?</param>
/// <param name="quickSave">Quicksave?</param>
/// <param name="paste">Paste?</param>
public static void GuiInput(uint playerID = uint.MaxValue, int hotbar = -1, bool hotbarHand = false, bool commandLine = false, bool inventory = false, bool escape = false, bool enter = false, bool debug = false, bool next = false, bool previous = false, bool tab = false, bool colour = false, int hotbarPage = -1, bool quickSave = false, bool paste = false)
public static void GuiInput(uint playerID = uint.MaxValue, int hotbar = -1, bool commandLine = false, bool escape = false, bool enter = false, bool debug = false, bool next = false, bool previous = false, bool tab = false, bool colour = false, int hotbarPage = -1, bool quickSave = false, bool paste = false)
{
if (playerID == uint.MaxValue)
{
playerID = inputEngine.GetLocalPlayerID();
}
ref InputEntityStruct currentInput = ref inputEngine.GetInputRef(playerID);
ref LocalInputEntityStruct currentInput = ref inputEngine.GetInputRef(playerID);
//Utility.Logging.CommandLog($"Current sim frame {currentInput.frame}");
// set inputs
switch(hotbar)
@ -76,19 +74,15 @@ namespace GamecraftModdingAPI.Input
case 7: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Hotbar_7; break;
case 8: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Hotbar_8; break;
case 9: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Hotbar_9; break;
case 10: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Hotbar_Hand; break;
default: break;
}
if (hotbarHand) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Hotbar_Hand;
if (commandLine) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.ToggleCommandLine;
if (inventory) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Inventory;
if (escape) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Escape;
if (enter) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Return;
if (debug) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.ToggleDebugDisplay;
if (next) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.SelectNext;
if (previous) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.SelectPrev;
if (tab) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Tab;
if (colour) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.Hotbar_Colour;
switch (hotbarPage)
{
case 1: currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.HotbarPage1; break;
@ -107,16 +101,16 @@ namespace GamecraftModdingAPI.Input
if (paste) currentInput.guiMask |= RobocraftX.Common.Input.GuiInput.PasteSelection;
}
public static void ActionInput(uint playerID = uint.MaxValue, bool toggleMode = false, bool forward = false, bool backward = false, bool up = false, bool down = false, bool left = false, bool right = false, bool sprint = false, bool toggleFly = false, bool alt = false, bool primary = false, bool secondary = false, bool tertiary = false, bool primaryRelease = false, bool primaryHeld = false, bool secondaryHeld = false, bool toggleUnitGrid = false, bool ctrl = false, bool toggleColourMode = false, bool scaleBlockUp = false, bool scaleBlockDown = false, bool rotateBlockClockwise = false, bool rotateBlockCounterclockwise = false, bool cutSelection = false, bool copySelection = false, bool deleteSelection = false)
public static void ActionInput(uint playerID = uint.MaxValue, bool toggleMode = false, bool forward = false, bool backward = false, bool up = false, bool down = false, bool left = false, bool right = false, bool sprint = false, bool toggleFly = false, bool alt = false, bool primary = false, bool secondary = false, bool tertiary = false, bool primaryHeld = false, bool secondaryHeld = false, bool toggleUnitGrid = false, bool ctrl = false, bool toggleColourMode = false, bool scaleBlockUp = false, bool scaleBlockDown = false, bool rotateBlockClockwise = false, bool rotateBlockCounterclockwise = false, bool cutSelection = false, bool copySelection = false, bool deleteSelection = false)
{
if (playerID == uint.MaxValue)
{
playerID = inputEngine.GetLocalPlayerID();
}
ref InputEntityStruct currentInput = ref inputEngine.GetInputRef(playerID);
ref LocalInputEntityStruct currentInput = ref inputEngine.GetInputRef(playerID);
//Utility.Logging.CommandLog($"Current sim frame {currentInput.frame}");
// set inputs
if (toggleMode) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.ToggleSimulation;
if (toggleMode) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.ToggleTimeRunningMode;
if (forward) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.Forward;
if (backward) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.Backward;
if (up) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.Up;
@ -129,7 +123,6 @@ namespace GamecraftModdingAPI.Input
if (primary) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.PrimaryAction;
if (secondary) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.SecondaryAction;
if (tertiary) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.TertiaryAction;
if (primaryRelease) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.PrimaryActionRelease;
if (primaryHeld) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.PrimaryActionHeld;
if (secondaryHeld) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.SecondaryActionHeld;
if (toggleUnitGrid) currentInput.actionMask |= RobocraftX.Common.Input.ActionInput.ToggleUnitGrid;

View file

@ -29,32 +29,32 @@ namespace GamecraftModdingAPI.Input
IsReady = true;
}
public bool SendCustomInput(InputEntityStruct input, uint playerID, bool remote = false)
public bool SendCustomInput(LocalInputEntityStruct input, uint playerID, bool remote = false)
{
EGID egid = new EGID(playerID, remote ? InputExclusiveGroups.RemotePlayers : InputExclusiveGroups.LocalPlayers);
if (entitiesDB.Exists<InputEntityStruct>(egid))
if (entitiesDB.Exists<LocalInputEntityStruct>(egid))
{
ref InputEntityStruct ies = ref entitiesDB.QueryEntity<InputEntityStruct>(egid);
ref LocalInputEntityStruct ies = ref entitiesDB.QueryEntity<LocalInputEntityStruct>(egid);
ies = input;
return true;
}
else return false;
}
public InputEntityStruct GetInput(uint playerID, bool remote = false)
public LocalInputEntityStruct GetInput(uint playerID, bool remote = false)
{
EGID egid = new EGID(playerID, remote ? InputExclusiveGroups.RemotePlayers : InputExclusiveGroups.LocalPlayers);
if (entitiesDB.Exists<InputEntityStruct>(egid))
if (entitiesDB.Exists<LocalInputEntityStruct>(egid))
{
return entitiesDB.QueryEntity<InputEntityStruct>(egid);
return entitiesDB.QueryEntity<LocalInputEntityStruct>(egid);
}
else return default(InputEntityStruct);
else return default(LocalInputEntityStruct);
}
public ref InputEntityStruct GetInputRef(uint playerID, bool remote = false)
public ref LocalInputEntityStruct GetInputRef(uint playerID, bool remote = false)
{
EGID egid = new EGID(playerID, remote ? InputExclusiveGroups.RemotePlayers : InputExclusiveGroups.LocalPlayers);
return ref entitiesDB.QueryEntity<InputEntityStruct>(egid);
return ref entitiesDB.QueryEntity<LocalInputEntityStruct>(egid);
}
public uint GetLocalPlayerID()

View file

@ -36,9 +36,9 @@ namespace GamecraftModdingAPI.Inventory
public bool SelectBlock(int block, uint playerID, bool cubeSelectedByPick = false)
{
InputEntityStruct[] inputs = entitiesDB.QueryEntities<InputEntityStruct>(InputExclusiveGroups.LocalPlayers).ToFastAccess(out uint count);
if (count == 0) return false;
for (int i = 0; i < count; i++)
var inputs = entitiesDB.QueryEntities<LocalInputEntityStruct>(InputExclusiveGroups.LocalPlayers);
if (inputs.count == 0) return false;
for (int i = 0; i < inputs.count; i++)
{
if (inputs[i].ID.entityID == playerID) {
inputs[i].cubeSelectedByPick = cubeSelectedByPick;

View file

@ -17,7 +17,7 @@ namespace GamecraftModdingAPI.Inventory
public static BlockIDs EquippedPartID { get => (BlockIDs)selectedBlockInt; }
private static MethodInfo PatchedMethod { get; } = AccessTools.Method(AccessTools.TypeByName("RobocraftX.GUI.Hotbar.HotbarSlotSelectionHandlerEngine"), "HandleEquippedCubeChanged", parameters: new Type[] { typeof(uint), typeof(int), typeof(ExclusiveGroupStruct) });
private static MethodInfo PatchedMethod { get; } = AccessTools.Method(AccessTools.TypeByName("RobocraftX.GUI.Hotbar.HotbarSlotSelectionHandlerEngine"), "ActivateSlotForCube", parameters: new Type[] { typeof(uint), typeof(int), typeof(ExclusiveGroupStruct) });
public static void Prefix(uint playerID, int selectedDBPartID, ExclusiveGroupStruct groupID)
{

View file

@ -46,8 +46,8 @@ namespace GamecraftModdingAPI.Players
public uint GetLocalPlayer()
{
if (!isReady) return uint.MaxValue;
PlayerIDStruct[] localPlayers = entitiesDB.QueryEntities<PlayerIDStruct>(PlayersExclusiveGroups.LocalPlayers).ToFastAccess(out uint count);
if (count > 0)
var localPlayers = entitiesDB.QueryEntities<PlayerIDStruct>(PlayersExclusiveGroups.LocalPlayers);
if (localPlayers.count > 0)
{
return localPlayers[0].ID.entityID;
}
@ -57,8 +57,8 @@ namespace GamecraftModdingAPI.Players
public uint GetRemotePlayer()
{
if (!isReady) return uint.MaxValue;
PlayerIDStruct[] localPlayers = entitiesDB.QueryEntities<PlayerIDStruct>(PlayersExclusiveGroups.RemotePlayers).ToFastAccess(out uint count);
if (count > 0)
var localPlayers = entitiesDB.QueryEntities<PlayerIDStruct>(PlayersExclusiveGroups.RemotePlayers);
if (localPlayers.count > 0)
{
return localPlayers[0].ID.entityID;
}
@ -83,8 +83,8 @@ namespace GamecraftModdingAPI.Players
public bool SetLocation(uint playerId, float3 location, bool exitSeat = true)
{
ExclusiveGroup[] characterGroups = CharacterExclusiveGroups.AllCharacters;
for (int i = 0; i < characterGroups.Length; i++)
var characterGroups = CharacterExclusiveGroups.AllCharacters;
for (int i = 0; i < characterGroups.count; i++)
{
EGID egid = new EGID(playerId, characterGroups[i]);
if (entitiesDB.Exists<RigidBodyEntityStruct>(egid))
@ -328,7 +328,7 @@ namespace GamecraftModdingAPI.Players
public bool IsDead(uint playerId)
{
return entitiesDB.Exists<RigidBodyEntityStruct>(playerId, CharacterExclusiveGroups.DeadGroup);
return entitiesDB.Exists<RigidBodyEntityStruct>(playerId, CharacterExclusiveGroups.DeadCharacters);
}
public int GetSelectedBlock(uint playerId)
@ -362,8 +362,8 @@ namespace GamecraftModdingAPI.Players
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public ref T GetCharacterStruct<T>(uint playerId, out bool exists) where T : unmanaged, IEntityComponent
{
ExclusiveGroup[] characterGroups = CharacterExclusiveGroups.AllCharacters;
for (int i = 0; i < characterGroups.Length; i++)
var characterGroups = CharacterExclusiveGroups.AllCharacters;
for (int i = 0; i < characterGroups.count; i++)
{
EGID egid = new EGID(playerId, characterGroups[i]);
if (entitiesDB.Exists<T>(egid))
@ -381,8 +381,8 @@ namespace GamecraftModdingAPI.Players
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool GetPlayerStruct<T>(uint playerId, out T s) where T : unmanaged, IEntityComponent
{
ExclusiveGroup[] playerGroups = PlayersExclusiveGroups.AllPlayers;
for (int i = 0; i < playerGroups.Length; i++)
var playerGroups = PlayersExclusiveGroups.AllPlayers;
for (int i = 0; i < playerGroups.count; i++)
{
EGID egid = new EGID(playerId, playerGroups[i]);
if (entitiesDB.Exists<T>(egid))
@ -394,7 +394,7 @@ namespace GamecraftModdingAPI.Players
s = default;
return false;
}
public EGID? GetThingLookedAt(uint playerId, float maxDistance = -1f)
{
if (!entitiesDB.TryQueryMappedEntities<CharacterCameraRayCastEntityStruct>(
@ -402,7 +402,8 @@ namespace GamecraftModdingAPI.Players
return null;
mapper.TryGetEntity(playerId, out CharacterCameraRayCastEntityStruct rayCast);
float distance = maxDistance < 0
? GhostBlockUtils.GetBuildInteractionDistance(entitiesDB, rayCast)
? GhostBlockUtils.GetBuildInteractionDistance(entitiesDB, rayCast,
GhostBlockUtils.GhostCastMethod.GhostCastProportionalToBlockSize)
: maxDistance;
if (rayCast.hit && rayCast.distance <= distance)
return rayCast.hitEgid;

View file

@ -308,15 +308,14 @@ namespace GamecraftModdingAPI.Tests
[HarmonyPatch]
public class MinimumSpecsPatch
{
public static bool Prefix(ref bool __result)
public static bool Prefix()
{
__result = true;
return false;
}
public static MethodInfo TargetMethod()
{
return ((Func<bool>)MinimumSpecsCheck.CheckRequirementsMet).Method;
return ((Action) MinimumSpecsCheck.CheckRequirementsMet).Method;
}
}
}

View file

@ -31,14 +31,14 @@ namespace GamecraftModdingAPI.Utility
public Task WaitForSubmission()
{
var task = new TaskCompletionSource<object>();
WaitForSubmissionInternal(_efu, _efa, entitiesDB, task).RunOn(ExtraLean.EveryFrameStepRunner);
WaitForSubmissionInternal(_efu, _efa, entitiesDB, task).RunOn(ExtraLean.EveryFrameStepRunner_TimeStopped);
return task.Task;
}
public Task WaitForNextFrame()
{
var task = new TaskCompletionSource<object>();
WaitForNextFrameInternal(task).RunOn(ExtraLean.EveryFrameStepRunner);
WaitForNextFrameInternal(task).RunOn(ExtraLean.EveryFrameStepRunner_TimeStopped);
return task.Task;
}