Jump to content

[SOLVED] Hook or callback for interruption of action queue actions


stuck1a

Recommended Posts

Hey there.

I'm just struggling a bit with my "construction site tile". I use tryBuild() of a derviced ISBaseObject to place it as special tile object at the very beginning of the build process. Of course, it shall disappear whenever any action of the action queue becomes interrupted however.

Unfortunately, I could not find a way to transfer appropriate callbacks, so I've decived to derive all TimedAction which might occur and add an additional call for the tile removal check in their stop() functions. Not elegant, but workes.

Bad luck - the faceDirection function is no TA on its own, so I've tried to hook into TimedActionQueue:tick() with no luck because of the static nature and lack of polymorphic.

 

So for now I've set an event listener to work around the problem by calling a derived variant of queue:tick(). It works, but as you can imagine, I'm not very happy with this solution because of the high performance impact such a listener comes with.

 

Surely I just overlooked the obvious solution, I guess a more elegant solution can be implemented with waitToStart() or the ISQueueActionsAction class, but I really can't figure it out right now.

If somehow possible, I'd like to avoid replacing the whole vanilla queue class for best possible compatibility with future updates.

 

 

Here the merged code for a better understanding of what I'm trying to achieve:

--- Removes the construction site tile object linked to the active action item
--- @param isoTile IsoObject construction site tile pointer
local function removeConstructionSite(isoTile)
  local square = isoTile:getSquare()
  -- there might be several construction sites on the square, so remove only the assigned one
  local specialTiles = square:getSpecialObjects()
  for i=0, specialTiles:size()-1 do
    if specialTiles:get(i) == isoTile then
      square:transmitRemoveItemFromSquare(isoTile)
      square:RemoveTileObject(isoTile)
      isoTile = nil
      return
    end
  end
end



require 'TimedActions/ISBaseTimedAction'
---@class ISExtBuildAction : ISBuildAction
ISExtBuildAction = ISBuildAction:derive('ISExtBuildAction')
function ISExtBuildAction:new(character, item, x, y, z, north, spriteName, time, tool1, tool2, isoTile)
  local o = ISBuildAction.new(self, character, item, x, y, z, north, spriteName, time)
  setmetatable(o, self)
  self.__index = self
  -- [...] (shortened)
  o.isoTile = isoTile
  return o
end

function ISExtBuildAction:perform()
  -- [...] (shortened)
  if self.isoTile ~= nil then removeConstructionSite(self.isoTile) end
  ISBuildAction.perform(self)
end

function ISExtBuildAction:stop()
  ISBuildAction.stop(self)
  if self.isoTile ~= nil then removeConstructionSite(self.isoTile) end
end



-- DERVICED VARIANTS OF ALL POSSIBLY USED TA's
---@class ISExtInventoryTransferAction : ISInventoryTransferAction
ISExtInventoryTransferAction = ISInventoryTransferAction:derive('ISExtInventoryTransferAction')
function ISExtInventoryTransferAction:new(character, item, srcContainer, destContainer, isoTile)
  local o = ISInventoryTransferAction:new(character, item, srcContainer, destContainer)
  setmetatable(o, self)
  self.__index = self
  o.isoTile = isoTile
  return o
end
function ISExtInventoryTransferAction:stop()
  ISInventoryTransferAction.stop(self)
  if self.isoTile ~= nil then removeConstructionSite(self.isoTile) end
end

-- and so on....





-- NOT VERY NICE, BUT WORKS FOR NOW...
---@class ISExtTimedActionQueue : ISTimedActionQueue
ISExtTimedActionQueue = ISTimedActionQueue:derive('ISExtTimedActionQueue')

function ISExtTimedActionQueue:clearQueue() ISTimedActionQueue.clearQueue(self) end
function ISExtTimedActionQueue:resetQueue() ISTimedActionQueue.resetQueue(self) end

function ISExtTimedActionQueue:new(character)
  local o = ISTimedActionQueue:new(character)
  setmetatable(o, self)
  self.__index = self
  return o
end

function ISExtTimedActionQueue.getTimedActionQueue(character)
  local queue = ISExtTimedActionQueue.queues[character]
  if queue == nil then queue = ISExtTimedActionQueue:new(character) end
  return queue
end

function ISExtTimedActionQueue.add(action)
  if action.ignoreAction then return end
  if instanceof(action.character, 'IsoGameCharacter') and action.character:isAsleep() then return end
  local queue = ISExtTimedActionQueue.getTimedActionQueue(action.character)
  local current = queue.queue[1]
  if current and (current.Type == 'ISQueueActionsAction') and current.isAddingActions then
    table.insert(queue.queue, current.indexToAdd, action)
    current.indexToAdd = current.indexToAdd + 1
    return queue
  end
  queue:addToQueue(action)
  return queue
end

function ISExtTimedActionQueue.queueActions(character, addActionsFunction, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)
  local action = ISQueueActionsAction:new(character, addActionsFunction, arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10)
  return ISExtTimedActionQueue.add(action)
end

function ISExtTimedActionQueue.hasAction(action)
  if action == nil then return false end
  local queue = ISExtTimedActionQueue.queues[action.character]
  if queue == nil then return false end
  return queue:indexOf(action) ~= -1
end

function ISExtTimedActionQueue.clear(character)
  character:StopAllActionQueue()
  local queue = ISExtTimedActionQueue.getTimedActionQueue(character)
  queue:clearQueue()
  return queue
end

function ISExtTimedActionQueue:tick()
  local action = self.queue[1]
  if action == nil then
    self:clearQueue()
    return
  end
  if not action.character:getCharacterActions():contains(action.action) then
    if action.isoTile ~= nil then removeConstructionSite(action.isoTile) end
    self:resetQueue()
    return
  end
end

function ISExtTimedActionQueue.onTick()
  for _,queue in pairs(ISExtTimedActionQueue.queues) do queue:tick() end
end

Events.OnRenderTick.Add(ISExtTimedActionQueue.onTick)

 

 

 

Edited by stuck1a
marked as solved
Link to comment
Share on other sites

Well, forget about that...

 

While searching the Java classes for any custom event system I've totally overseen LuaEventManager::AddEvent()

I already was surprised that it wouldn't exist, but lo and behold, there it is.

And I really was about to use IsoPlayer:setVariable() to work around the RenderTick-Event :lol:

 

Well that makes most part of the posted stuff unnecessary.

 

 

Just for the sake of completeness:

local function TestEventListener()
  print('TestEvent fired')
end
LuaEventManager.AddEvent('TestEvent')
Events.TestEvent.Add(TestEventListener)

 

Shame on me

Edited by stuck1a
Link to comment
Share on other sites

  • stuck1a changed the title to [SOLVED] Hook or callback for interruption of action queue actions

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...