Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Making task callbacks serializable

Discussion in 'Scripting' started by Sendatsu_Yoshimitsu, Jan 6, 2019.

  1. Sendatsu_Yoshimitsu

    Sendatsu_Yoshimitsu

    Joined:
    May 19, 2014
    Posts:
    691
    I'm working on a really simple task scheduler for a base-building game, where both player commands and independent behavior are implemented as tasks which individual AI agents prioritize based on urgency, a distance heuristic, and whatever I come up with to calculate each agent's individual suitability for that task.

    At its core, this seems really straightforward: there's a global TaskManager that can provide a List<Task> of every Task that needs to be executed, and has methods for AI to request a specific task, report an ongoing task as complete, or report it as failed.

    Since a wide variety of unrelated entities and logic can register tasks, I've handled reporting each task's success/failure by having anything that adds a new task to the schedule also register a delegate callback that gets invoked when the agent fails or finishes its task. This works perfectly well for one-time testing but I'd like to make Tasks serializable, so agents retain their current task(s) between sessions.

    The way I'm handling this right now is by giving all the methods that classes need to schedule tasks in an interface which includes some int GetID() which returns a serialized GUID that each class generates when it's first instantiated. Thus, when a task succeeds/fails, the manager simply iterates through every ITask interface it can see, finds one with the right ID, and hands it the Task along with a bool indicating whether it succeed or failed.

    That works, but it has a few drawbacks: the big one is that I'm doing tons of iteration, every time a task changes hands I'm iterating through hundreds or potentially thousands of objects to check who was using that task, and assigning a consistent ID to tons of potentially unrelated classes feels dangerously close to an antipattern. Are there obvious improvements I can be making, or a completely different pattern I should be implementing task management with? Or is this one of those cases where the current solution is clumsy but acceptable, and I shouldn't be wasting time trying to over-optimize it?
     
  2. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,514
    This is what hashtables/dictionaries are for.

    Don't stick them in an indexed collection, stick them in a look-up table that lets you look things up by guid. This creates an O(1) lookup cost.

    If for whatever reason you can't create a hashtable of them. There are of course other ways to index your tasks so that you have a quick look-up. But without knowing a more detailed idea of your system, picking one isn't obvious.
     
  3. Sendatsu_Yoshimitsu

    Sendatsu_Yoshimitsu

    Joined:
    May 19, 2014
    Posts:
    691
    Ohh derp, that's a much cleaner solution... the total range of index-able agents won't change during gameplay, either, so it's a one-time cost.

    Thank you very much for the suggestion! I feel kind of dumb for getting stuck on the list notion. ^^
     
    Last edited: Jan 6, 2019