• Advertisement
Sign in to follow this  

C# To Callback or not to callback

Recommended Posts

I've got a problem and I'm not happy with the solution I found, looking for input.

Commands, which serve as passable functions are stored into a queue that gets pulled from on regular intervals. Then they are stored in an EnquedCommand object and placed into a different queue. EnquedCommand contains some info such as where the command is being run from. The second queue is also pulled from on regular intervals. The objects that submit the commands and each Queue are kept separate so they have no easy means of communication. This has worked fine so far.

The problem is I now have a command that is supposed to have the original object that enqued it do something when that command is run in the final queue. But it has no easy means of knowing when that happens.

The solution I found is to embed a callback parameter into EnquedCommand and have that passed through the queues so that the callback is called when the command is run. What I don't like about the solution is that this requires a fair bit of refactoring and, so far, this is the only command that needs one. Seems like overkill.

Are there any other solutions anyone can think of?

Share this post

Link to post
Share on other sites

callback seems fine for this.

or just in the command that needs it, have an additional member variable such as m_command_has_executed with a get_has_command_executed() member function.  Have the original object that created the command maintain a reference to the command.  On the next tick when the object runs its update() method, have it check the last_enqueued_command->get_has_command_executed() to see if it already ran.  but don't see how that is really any much better than a callback function.  just another way.

Share this post

Link to post
Share on other sites

Seems like there are some other potential concerns, such as object lifetimes. Some languages and tools are better suited at this than others, but there are important details like making sure the objects involved are all still valid when commands are run.

I've worked with container-style systems where objects in the container can have their function called at specific future points in time, such as before/after processing, before/after rendering, before/after physics. It is more special purpose than you described, but has the benefit of letting the container verify the object is still alive before calling the function.

I've also seen many event bus systems allow for delayed events to be broadcast. A system can register an event listener and fire a timed event.  If the target object is still alive the object's listener can respond, if the object has died it will have been de-registered as a listener so no problems from running a callback on dead objects.

For the specific problem you're facing a message bus sounds ideal.  The original object can indicate it needs an event with a specific unique ID.  The system can listen for the event, and if the unique ID matches it can do the work it had delayed. The system may need other protections, such as killing off long-overdue tasks, but the message bus pattern solves all kinds of inter-object communications issues.

Share this post

Link to post
Share on other sites
On 12/24/2017 at 9:10 AM, Munchkin9 said:

The solution I found is to embed a callback parameter into EnquedCommand and have that passed through the queues so that the callback is called when the command is run. What I don't like about the solution is that this requires a fair bit of refactoring

Commands are functions, right?  If they already perform work then why does anything need to be refactored?  Perform the callback within the normal work of the command's function, or wrap the command with a command which calls the original command THEN the callback, if that makes more sense.  Imagine this pattern, but adapted to whatever additional complexities you require (IPC, RPC, etc).

Action WrapAction(Action command, Action callback)
  return () =>

If you're dealing with IPC then you will definitely need some way of handling responses and completion which can deal with the callback.  It's not overkill.  If you're NOT dealing with IPC then do you really need all those intermediate objects and queues?

Edited by Nypyren

Share this post

Link to post
Share on other sites

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

Sign in to follow this  

  • Advertisement
  • Advertisement
  • Popular Tags

  • Advertisement
  • Popular Now

  • Similar Content

    • By Timothy Sharp
      just to test out my animations, let's say i had a trip animation. How would I code a script to where my character would fall it mud and their clothes would become all muddy? I saw this in a game on Unreal 3 but is this possible with Unity?
    • By Manuel Berger
      Hello fellow devs!
      Once again I started working on an 2D adventure game and right now I'm doing the character-movement/animation. I'm not a big math guy and I was happy about my solution, but soon I realized that it's flawed.
      My player has 5 walking-animations, mirrored for the left side: up, upright, right, downright, down. With the atan2 function I get the angle between player and destination. To get an index from 0 to 4, I divide PI by 5 and see how many times it goes into the player-destination angle.

      In Pseudo-Code:
      angle = atan2(destination.x - player.x, destination.y - player.y) //swapped y and x to get mirrored angle around the y axis
      index = (int) (angle / (PI / 5));
      PlayAnimation(index); //0 = up, 1 = up_right, 2 = right, 3 = down_right, 4 = down

      Besides the fact that when angle is equal to PI it produces an index of 5, this works like a charm. Or at least I thought so at first. When I tested it, I realized that the up and down animation is playing more often than the others, which is pretty logical, since they have double the angle.

      What I'm trying to achieve is something like this, but with equal angles, so that up and down has the same range as all other directions.

      I can't get my head around it. Any suggestions? Is the whole approach doomed?

      Thank you in advance for any input!
    • By Alexander Nazarov
      Hello. I'm newby in Unity and just start learning basics of this engine. I want to create a game like StackJump (links are below). And now I wondering what features do I have to use to create such my game. Should I use Physics engine or I can move objects changing transform manually in Update().
      If I should use Physics can you in several words direct me how can I implement and what I have to use. Just general info, no need for detailed description of developing process.
      Game in PlayMarket
      Video of the game
    • By Dave Haylett
      Hi all. My project is coming along wonderfully, and am starting to consider alpha deployment, and would like your advice.
      My project need access to 10,000 small PNG image files at runtime, each is only a few kilobytes each, which during development I used to load in directly from a fixed path on my HDD whenever one was needed (obviously not a solution for go-live), using something like this:
      img = new WriteableBitmap(new BitmapImage(new Uri(@screenshotsPath + filename)));
      The image would then be blitted onto a buffer screen, etc. etc. At a time, a few dozen would be being used.
      Now I'm thinking about deployment, and also when I produce an update to my app, there could be more images to add to the folders. So I'm considering the best way of a) deploying the images to the user as part of the project, and b) how to most easily handle updates to the app, whereby more images will be added.
      I have just experimented with adding them all as a Resource (!). This inflated the exe from 10mb to 100mb (not a major problem), increased the compile time from 3 secs to 30 secs (annoying), increased RAM usage from 500mb to 1.5gb (not a major problem either), but means that it solves my fixed directory issue, distribution issue, and update issue, simply by having the files all stuck into the executable. Here's the new code I'm using:
      img = BitmapFactory.FromResource("Shots/" + filename);
      The next thing I was going to try was to mark them as Content > Copy if Newer. This would resolve the executable size and RAM usage (and also the directory issue as well), however it seems that I'd need to highlight them all, and move them from Resource to Content. As an up-front job this isn't too bad, but as I add new images to the project, I'll need to go in and do this every time, which gets annoying, as the VS2015 default is Resource. Also, I'm not sure how this would work in terms of updates. Would something like ClickOnce deployment recognise new PNGs and install them to the users?
      I also have 3,000 ZIP files (~500kb each) which also need deploying and updating in the same way. These are currently read directly from my HDD until I can find a permanent solution for adding these to the project as well.
      Can anyone thing of a better way of doing what I'm trying to achieve?
      Thanks for any help folks.
    • By Felis Nigripes
      I'm doing a test quest.
      The player gets a quest from an NPC to bring him fish.

      Once the player picks up the fish, the original NPC gets replaced by a new one with a new conversation trigger. The NPC tells the Player "Well done" and should give 200xp.

      The script tells the xp counter to go up by making a reference to the gameobject that holds the text component
      But it throws this error:

      I'm aware that the error may hide in plain sight. I just have to sort this out, since I'm writing the AI at the same time, and the time it takes to resolve everyone of these errors is tremendous.
      Plus, I think I'll learn something. I've been having trouble with some basic functionalities recently. There might be something wrong with my understanding on how programming works.
      Glad if someone could help (:
      Edit: I'm fully aware that the update function requires an input. I call the function in the editor when the dialogue ends, it still doesn't work.
  • Advertisement