From b5509fa521cb03171e459289e2361f4ec3e63144 Mon Sep 17 00:00:00 2001 From: lL1l1 <82986251+lL1l1@users.noreply.github.com> Date: Fri, 20 Dec 2024 17:55:24 -0800 Subject: [PATCH] Add a test task with some other debug stuff --- lua/sim/tasks/TestTask.lua | 105 ++++++++++++++++++ .../units/components/DebugUnitComponent.lua | 89 +++++++++++++++ lua/system/repr.lua | 15 ++- 3 files changed, 206 insertions(+), 3 deletions(-) create mode 100644 lua/sim/tasks/TestTask.lua diff --git a/lua/sim/tasks/TestTask.lua b/lua/sim/tasks/TestTask.lua new file mode 100644 index 0000000000..9e1a4117f2 --- /dev/null +++ b/lua/sim/tasks/TestTask.lua @@ -0,0 +1,105 @@ + +local ScriptTask = import("/lua/sim/scripttask.lua").ScriptTask +local TASKSTATUS = import("/lua/sim/scripttask.lua").TASKSTATUS +local AIRESULT = import("/lua/sim/scripttask.lua").AIRESULT + +-- You can issue this task by using: +-- IssueCommand("UNITCOMMAND_Script", { TaskName = "TestTask", Wait = Random(4)*7 }, false) +-- IssueUnitCommand(GetSelectedUnits(), "UNITCOMMAND_Script", { TaskName = "TestTask", Wait = Random(4)*7 }, false) +-- import('/lua/ui/game/commandmode.lua').StartCommandMode('order', { name = "RULEUCC_Script", TaskName = "TestTask" }) -- Note: `UserScriptCommand` overwrites the LuaParams table, so Wait can't be used. +-- or Sim-Side: +-- IssueScript(SelectedUnit(), { TaskName = "TestTask", Wait = Random(4)*7 }) + +---@class TestTask : ScriptTask +---@field CommandData { TaskName: "TestTask", Wait: number, tailCall?: true } # LuaParams table from the user side. This table is shared by all units ordered the task from one command. +---@field Wait number\ +---@field tailCall? true +---@field unitId EntityId # self:GetUnit():GetEntityId() +TestTask = Class(ScriptTask) { + + --- Called immediately when task is created + --- Initialize lua param wait times + ---@param self TestTask + ---@param commandData { TaskName: TestTask, Wait: number } # LuaParams table from the user side. This table is shared by all units ordered the task from one command. + OnCreate = function (self, commandData) + ScriptTask.OnCreate(self, commandData) + LOG(('task %s for unit %s started at tick %d, waiting for %d ticks (until tick %d)'):format( + tostring(self) + , tostring(self.unitId) + , GetGameTick() + , (commandData.Wait or 5) + , GetGameTick() + (commandData.Wait or 5) + )) + self.Wait = commandData.Wait or 5 + self.unitId = self:GetUnit():GetEntityId() + LOG(repr(commandData)) + -- LOG(repr(self, {meta = true})) + + -- self:GetUnit():SetBusy(true) + -- self:GetUnit():SetBlockCommandQueue(true) + + -- if self.Wait >= 2 then + -- IssueScript({self:GetUnit()}, { TaskName = 'TestTask', Wait = self.Wait - 1 }) + -- end + + end, + + --- Called by the engine every tick. Function must return a value in TaskStatus + ---@param self TestTask + ---@return ScriptTaskStatus + TaskTick = function(self) + -- "tail call" example: this isn't a true tail call because the queue isn't guaranteed to be empty, + -- so execution may not go to the next issued command unless the command queue is cleared first + + -- if not self.CommandData.tailCall then + -- -- IssueScript({ self:GetUnit() }, { TaskName = "TestTask", Wait = self.Wait, tailCall = true }) + -- self.CommandData.tailCall = true + + -- LOG(repr(self, {meta = true})) + + -- -- ForkThread(function(u) + -- -- while not IsDestroyed(u) do + -- -- u:DebugPrintCurrentStates() + -- -- WaitTicks(1) + -- -- end + -- -- end, self:GetUnit()) + + -- return TASKSTATUS.Done + -- end + + local wait = self.Wait + + if wait == TASKSTATUS.Done then + self:GetUnit():DebugToggleTrackingStateChanges() + + -- if GetGameTick() > self.delaytick then + -- LOG(('task %s for unit %s ended at tick %d with an actual delay'):format(tostring(self), tostring(self.unitId), GetGameTick())) + -- end + + LOG(('task %s for unit %s ended at tick %d'):format(tostring(self), tostring(self.unitId), GetGameTick())) + + return wait + elseif wait == TASKSTATUS.Delay then + self.Wait = TASKSTATUS.Done + self.delaytick = GetGameTick() + -- LOG(('task %s delayed at tick %d'):format(tostring(self), GetGameTick())) + + return wait + else + self.Wait = TASKSTATUS.Done + -- LOG(('task %s waited at tick %d until %d'):format(tostring(self), GetGameTick(), GetGameTick() + wait - 1)) + return wait + end + end, + + --- Called by the engine when the task is destroyed. This could be it naturally going away after completion or because it was cancelled by another task. + ---@param self TestTask + OnDestroy = function(self) + LOG(('task %s destroyed at tick %d'):format(tostring(self), GetGameTick())) + + -- self:GetUnit():SetBusy(false) + -- self:GetUnit():SetBlockCommandQueue(false) + + self:SetAIResult(AIRESULT.Success) + end, +} diff --git a/lua/sim/units/components/DebugUnitComponent.lua b/lua/sim/units/components/DebugUnitComponent.lua index 226fecddec..438b2af2fb 100644 --- a/lua/sim/units/components/DebugUnitComponent.lua +++ b/lua/sim/units/components/DebugUnitComponent.lua @@ -22,6 +22,67 @@ local DebugComponent = import("/lua/shared/components/DebugComponent.lua").DebugComponent +---@type UnitState[] +local possibleUnitStates = { + "Immobile", + "Moving", + "Attacking", + "Guarding", + "Building", + "Upgrading", + "WaitingForTransport", + "TransportLoading", + "TransportUnloading", + "MovingDown", + "MovingUp", + "Patrolling", + "Busy", + "Attached", + "BeingReclaimed", + "Repairing", + "Diving", + "Surfacing", + "Teleporting", + "Ferrying", + "WaitForFerry", + "AssistMoving", + "PathFinding", + "ProblemGettingToGoal", + "NeedToTerminateTask", + "Capturing", + "BeingCaptured", + "Reclaiming", + "AssistingCommander", + "Refueling", + "GuardBusy", + "ForceSpeedThrough", + "UnSelectable", + "DoNotTarget", + "LandingOnPlatform", + "CannotFindPlaceToLand", + "BeingUpgraded", + "Enhancing", + "BeingBuilt", + "NoReclaim", + "NoCost", + "BlockCommandQueue", + "MakingAttackRun", + "HoldingPattern", + "SiloBuildingAmmo", +} + +---@param unit Unit +---@return UnitState[] currentStates # Can be empty +local function GetStatesOfUnit(unit) + local currentStates = {} + for _, possibleState in possibleUnitStates do + if unit:IsUnitState(possibleState) then + table.insert(currentStates, possibleState) + end + end + return currentStates +end + ---@class DebugUnitComponent : DebugComponent DebugUnitComponent = Class(DebugComponent) { @@ -118,4 +179,32 @@ DebugUnitComponent = Class(DebugComponent) { local blueprint = self.Blueprint DrawCircle(self:GetPosition(), math.max(blueprint.SizeX, blueprint.SizeY, blueprint.SizeZ), color) end, + + ---@param self DebugUnitComponent | Unit + DebugPrintCurrentStates = function(self) + self:DebugLog(string.format("States at tick %d: %s", GetGameTick(), table.concat(GetStatesOfUnit(self), ', '))) + end, + + ---@param self DebugUnitComponent | Unit + DebugToggleTrackingStateChanges = function(self) + if not self.StateChangeTracker then + self.StateChangeTracker = self.Trash:Add(ForkThread(function() + local oldStatesHashed = {} + while true do + local newStates = GetStatesOfUnit(self) + local newStatesHashed = table.hash(GetStatesOfUnit(self)) + for _, state in possibleUnitStates do + if newStatesHashed[state] ~= oldStatesHashed[state] then + self:DebugLog(string.format("New states at tick %d: %s", GetGameTick(), table.concat(newStates, ', '))) + end + end + oldStatesHashed = newStatesHashed + WaitTicks(1) + end + end)) + else + KillThread(self.StateChangeTracker) + self.StateChangeTracker = nil + end + end, } diff --git a/lua/system/repr.lua b/lua/system/repr.lua index a9c7a91216..dc332f9ab0 100644 --- a/lua/system/repr.lua +++ b/lua/system/repr.lua @@ -182,7 +182,12 @@ function Inspector:getId(v) if not id then local tv = type(v) id = (ids[tv] or 0) + 1 - ids[v], ids[tv] = id, id + ids[tv] = id + if tv == "function" then + local info = debug.getinfo(v, "S") + id = fmt("%s %s(%d)", id, DiskToLocal(string.sub(info.source, 2)), info.linedefined) + end + ids[v] = id end return tostring(id) end @@ -223,7 +228,11 @@ function Inspector:putValue(v) puts(buf, "]") end puts(buf, ' = ') - self:putValue(t[k]) + if k == "__index" and tostring(t[k]) == tostring(t) then + puts(buf, string.format("{...} -- %s (%g bytes)", tostring(t), debug.allocatedsize(t))) + else + self:putValue(t[k]) + end end end @@ -249,7 +258,7 @@ function Inspector:putValue(v) end else - puts(buf, fmt('<%s %d>', tv, self:getId(v))) + puts(buf, fmt('<%s %s>', tv, self:getId(v))) end end