Search Unity

Requiring User Input when very Deep inside the Game Process

Discussion in 'General Discussion' started by manutoo, May 18, 2018.

  1. manutoo

    manutoo

    Joined:
    Jul 13, 2010
    Posts:
    524
  2. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    Thats Cpp code, I'll let someone else answer that thats more fit in Cpp land, but it will require you to change your code, plus if you have nested methods calls you need to update them all. If you do all that work maybe its better to migrate the code to Unity
     
  3. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    Also your example was very simple with just a prompt menu. What about more advanced UIs like list of items etc, etc. It will be a major pain exchange data between Cpp and CLR for this
     
  4. manutoo

    manutoo

    Joined:
    Jul 13, 2010
    Posts:
    524
    @AndersMalmgren,
    there won't be any cpp code. I'm porting my engine to C#.
    And UI code isn't a concern here, it's not a part of the Tour engine. Thanks to show that you don't understand what you're talking about...
     
  5. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    Its because you cant explain for S***.

    If you are porting it to C# then F***ing use Unity as its ment to be
     
    xVergilx, MD_Reptile and jasonxtate66 like this.
  6. jasonxtate66

    jasonxtate66

    Joined:
    Nov 21, 2017
    Posts:
    133
    Wow, this guy is a piece of work for a person who is asking for help. I challenge the OP to make a video clearly stating what he is talking about, since no one seems to "understand".
     
  7. jasonxtate66

    jasonxtate66

    Joined:
    Nov 21, 2017
    Posts:
    133
    This should also technically be in the "Scripts" forum... but has become the OP just telling everyone they don't know what they are talking about and that he doesn't want to conform to Unity.
     
  8. manutoo

    manutoo

    Joined:
    Jul 13, 2010
    Posts:
    524
    @AndersMalmgren,
    That's what most people keep saying in this topic, but none has been able to "break" my 50 lines of pseudo-code.
    I guess it's called ideology vs pragmatism... :rolleyes:

    @jasonxtate66,
    there's pseudo-code for the problem & pseudo-code for the solution ; if you have issue understanding, I can't help you. Maybe you should accept there are concepts which are not in grasp of all coders. I don't pretend to understand everything about all code concepts, but at least I understand the ones I put in action... :)

    EDIT:
    and it's not the script forum, as I don't ask for help about implementation of a script, but a more general sharing of experience about this kind of issue.
     
  9. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,853
    The irony is strong in your ideological bent. Pragmatically speaking you should port the code to Unity. And whilst doing it clean up the mess that it obviously is.
     
  10. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    You are more arrogant than ippdev, its an achievement in itself, I give you that

    Code (CSharp):
    1. class CTour
    2. {
    3.  
    4.     //This should be called async, how you do it depends on your infrastructure
    5.     IEnumerator HandleDay()
    6.     {
    7.         //... other stuff comes here...
    8.  
    9.        if (NewWeek())
    10.        {
    11.            yield return FillTournaments();
    12.            yield return CreateTournamentDraws();
    13.        }
    14.  
    15.         //... other stuff comes here...
    16.     }
    17.  
    18.     IEnumerator FillTournaments()
    19.     {
    20.         foreach(var player in m_PlayerSortedByRank)  
    21.             yield return ChooseTournament(player);
    22.      
    23.     }
    24.  
    25.     IEnumerator PickTournament(CPlayer p)
    26.     {
    27.         if (p.IsControllerByUser)
    28.         {
    29.             if (p.SelectedTournament.IsFull)       // this depends of previous player choices
    30.             {
    31.                 var menu = CGui.DisplayMenu("AskUserIfHeWantsToGoToALowerTournament");
    32.                 yield return menu;
    33.  
    34.                 if (menu.Result == EAnswer.e_Yes)
    35.                     yield return EnterTournament(p, p.NewlyChosenTournament);
    36.             }
    37.             else
    38.                 yield return EnterTournament(p, p.SelectedTournament);
    39.         }
    40.         else
    41.         {
    42.             // CPU Player chooses a tournament
    43.         }
    44.     }
    45. }
     
    neginfinity likes this.
  11. manutoo

    manutoo

    Joined:
    Jul 13, 2010
    Posts:
    524
    @AndersMalmgren,
    thanks for showing me your solution in pseudo-code.
    Do you feel it's cleaner & easier to maintain than my ~10-line solution using a sub-thread ?
    If yes, then I guess we'll have to agree to disagree... :)
     
  12. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    Yeah, I think its cleaner, its also none blocking

    edit:My code would be even more clean if I did it from scratch my way, fro example I would not mix NPC and player code in the same method/class and most of the if-blocks would not be needed at this level
     
  13. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,572
    Coroutines in the way previously explained. Make a class that implements menu, provides ienumerator method so it can work as coroutine and yield return it within a call that requires menu response.

    Coroutines in unity technically act like green threads, meaning while coroutine is waiting for user response, the rest of the scene will remain responsive and the engine will keep repainting the viewport. So you'll have non-blocking async call without invoking OS threading primitives.

    Your problem has been solved in 2rd post. You keep refusing to accept the solution, and insist that there's still problem when there is none.

    Nobody has issue understanding your request. However, I'm uncertain if you correctly understood logic behind Coroutine approach.

    At this point I recommend to fork out some cash and hire a freelancer. This is not a difficult problem, and it should've been solved by a day after you posted it. You're likely to have more trouble porting C++ code into C# (due to language differences) than handling user input.
     
    xVergilx likes this.
  14. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,572
    Coroutine approach would be better, because it operates in the same thread. Meaning potentially lower processing overhead and no potential multithreading issues like deadlocks and race conditions.
     
    AndersMalmgren likes this.
  15. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    And please get rid of the hungarian notation etc, its 2018.

    EAnswer.e_Yes, yeah, we know its a enum thank you
     
    xVergilx, Ryiah and neginfinity like this.
  16. manutoo

    manutoo

    Joined:
    Jul 13, 2010
    Posts:
    524
    So let's a do a little recap :
    - starting thousands of coroutines per frame, that's a big no : https://jacksondunstan.com/articles/2981
    - losing system independence in a big data processing engine just for ideology, that's a freaking huge no
    - losing simple return value capability and putting thousand of keywords everywhere, that's a no
    - being unable to write 1 sentence in English without making 1 or even more spelling & grammatical errors, while wanting to school on coding noting convention, that's just plainly ridiculous
    - weighting thousands of coroutine starts vs 1 thread start, that's a total noob alert

    Thanks for your input all, it was likely last time I try to ask for help from unskilled coders who think they own the world... :rolleyes:

    Now let's get back to serious work...

    Mods please close this topic, we're done here (or let them insult me 1 more time, I guess it makes them feel superior, and I'm all for making people happy ! :D ).
     
  17. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    Its only one Coroutine started in my example above. I can somewhat agree on the return values, but its a easy fix by implementing a custom yield instruction like my example with the menu above. It will be nice when we have native support for Task<T>

    edit: Courountes are very valuable when creating semi complex workflows,like example from our game
    Code (CSharp):
    1.     [CreateAssetMenu(menuName = "Tutorial/SprintStep")]
    2.     public class SprintStep : TutorialStep
    3.     {
    4.         [SerializeField]
    5.         private SimpleNetworkedMonoBehavior firearm;
    6.  
    7.         public override IEnumerator Execute()
    8.         {
    9.             ShowPopup(GetLiklyOffHand().transform, string.Format("You can enable sprinting by pressing {0} while moving.", GetCommandCaption(Command.Sprint)));
    10.  
    11.             yield return WaitForSprint();
    12.  
    13.             yield return Execute(new MessageStep { Message = "There are some limitations to sprinting, for example you can not sprint while aiming down sights."});
    14.  
    15.             Spawn(firearm, Transform.position, Transform.rotation);
    16.             yield return Execute(new PreloadWeaponStep{ Attachments = new List<AttachmentTutorialConfig>()});
    17.  
    18.             yield return Execute(new InteractStep());
    19.  
    20.             ShowPopup(GetLiklyOffHand().transform, "Sprint and try to raise the firearm and see what happens.");
    21.  
    22.             yield return WaitForSprint();
    23.         }
    24.  
    25.         private IEnumerator WaitForSprint()
    26.         {
    27.             float time = 0;
    28.  
    29.             while (time < 3)
    30.             {
    31.                 if (NVRPlayer.Instance.Sprinting)
    32.                     time += Time.deltaTime;
    33.              
    34.                 yield return null;
    35.             }
    36.         }
    37.     }
     
    Last edited: May 21, 2018
  18. jasonxtate66

    jasonxtate66

    Joined:
    Nov 21, 2017
    Posts:
    133
    Your sentences in English have punctual and grammatical errors. You never answered my challenge of explaining your issue in a video... surely you have a head set and the ability to screen capture?
     
  19. manutoo

    manutoo

    Joined:
    Jul 13, 2010
    Posts:
    524
    @AndersMalmgren,
    no, each "yield return <function>" starts a coroutine => https://forum.unity.com/threads/dif...rator-and-yield-return-startcoroutine.432571/ .

    And I like coroutine, and I used them in a similar way than you exposed ; in that case, it's super clean and produces an easy to follow code flow ; I just don't think they are convenient to solve my present issue, even if they can technically work (if you have noticed, your pseudo-code is the 1st one where I didn't say it was losing functionality or have any misunderstanding).

    @jasonxtate66,
    you're one train late, AndersMalmgren already provided a decent answer... :)
     
  20. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    I'm sceptical, no official reply from Unity in that thread, if I did the underlying code for that I would check if the value is a Enumerator and then just yield the reuslt of it to the same started coroutine. Even if they do a new coroutine for each yielded enumerator you would have to go extreme with yielding enumertors before it would become a problem. If you want to sub optimize you can do

    Code (CSharp):
    1. foreach(var result in FillTournaments())
    2.    yield return result;
     
  21. N1warhead

    N1warhead

    Joined:
    Mar 12, 2014
    Posts:
    3,884
    Why do you people even keep responding?
    After giving my, what I thought was an at least somewhat informative post, I was ignored.

    There's no way this person has been coding over 20 years, because if they did, they could be creative and solve the issue...

    Personally I think the whole idea of this is more retarded than bashing a 2000 year old redwood tree with a hammer to cut it down in a week. It just doesn't make sense. Person really just needs to either stop, take the advice given from people who've been using Unity for a lot longer than they have, or at actually re-create the game from scratch - which would be a lot faster than fighting a light saber with a sword (Literally from scratch), not a single line of code from your C++ Project.

    Seriously, why would you in your right mind go through all this trouble, to port what is probably a game not worth porting from the start? It makes absolutely no sense. An old game, if it didn't bring in over a hundred grand, is it really worth the 'Porting' to make it work, which if it did, what game is it so I can look it up? Otherwise just remake the game from scratch, ignoring anything you've ever made for it, simply because you'll get stuck in this trap again of wanting to brute force old workflows into Unity, which just ain't going to work.

    But too each their own I guess.
     
    xVergilx and RockoDyne like this.
  22. JohnnyA

    JohnnyA

    Joined:
    Apr 9, 2010
    Posts:
    5,041
    frosted and N1warhead like this.
  23. manutoo

    manutoo

    Joined:
    Jul 13, 2010
    Posts:
    524
    JohnnyA likes this.
  24. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,853
    Says the arrogant developer who demanded i post proof via screenshots of something i only peripherally commented on or be pegged as a liar. The lesson you should have learned from our exchange is that arrogance and accusatory implication can lead to you getting smacked back in a counter punch. In your arrogance you deem your self to have done nothing wrong. For the sake of the forum don't start crap with me. Carry on.
     
  25. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    Nah that was you reading my post wrong and thought I ment that
     
  26. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,572
    Then do not yield return in situation where you don't need async behavior, and profile actual code to see if this is a problem.
    ------------

    Anyway, can someone like @zombiegorilla or @hippocoder shut this thing down?

    The thread has too much ego and not enough actual problem solving.
     
  27. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    If you manuelly execute the inner enumerator and forwarding each element to the outer enumerator there is no way unity can try to create a second coroutine since they will just be treated as standard coroutine yield instructions.

    Though I still doubt unity would create a separate coroutine call, you will however get some overhead because .NET will offcourse create a second enumerator. But if you need to execute several hundred or thousands of enumerators in one frame you are doing something wrong
     
  28. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,572
    The ability to have nested yield calls has been silently introduced around version 5.4, based on this unanswered question:
    https://answers.unity.com/questions/1274692/nested-coroutine-handling.html
    And previously it required direct StartCoroutine call.

    Whether this result in actual coroutine or something more complex would require investigating (I mean, coroutines themselves are some IEnumerator stack somewhere)

    But indeed, having thousands of IEnumerators would mean something is horribly wrong and earlier pseudocode example (both yours and mine) shouldn't produe this amount of them, and indeed you can unroll enumerator yourself.

    Either way it would be great if people in general dialed their egos down.
     
  29. manutoo

    manutoo

    Joined:
    Jul 13, 2010
    Posts:
    524
    I just thought a probable checkmate point in favor of the sub-thread, in addition of the previously exposed points : I'll be able to easily display an animation when the Tour processing takes a few seconds, making the game feels more responsive to the user.

    @AndersMalmgren,
    my Tour engine processes thousands of players ; this would lead to tens, if not hundreds (or maybe even millions?) of function calls that would be flagged as enumerator with your solution.

    Or I should put the enumerator only where they are needed. Which doesn't sound like rapid & easy development to me...
     
  30. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    My guess is that the performance loss they see is from actually creating the enumerator which is a pretty complex state machine. And it does not start a second coroutine but execute them on the same. Just me guessing and yeah, if you see performance impact from this you are doing something wrong, take my example with

    yield return SomemethodOne();
    yield return SomemethodTwo();

    This will create one enumerator in the frame one, then it will itterate those than when the are done it will create the new enumerator possibly many, many frames later
     
  31. ippdev

    ippdev

    Joined:
    Feb 7, 2010
    Posts:
    3,853
    Fair enuff.
     
    AndersMalmgren likes this.
  32. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,194
    Years of experience can work against you. If you've always solved a problem one way and it's always worked for you it may lead you to always approach it that way even if it isn't necessarily the best way. My thoughts immediately went to Chris Sawyer who developed RollerCoaster Tycoon using almost pure assembly.

    http://www.chrissawyergames.com/faq3.htm
     
    Doug_B likes this.
  33. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    Why process thousands of players in UI?
     
  34. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,572
    You wanted to use subthreads a while ago. So apparently millions of OS thread is not a problem, but coroutines are a "no-no"? Threads aren't free.

    Yes you should. See KISS and YAGNI principles. Also see premature optimization.

    Your solution definitely doesn't need to spawn new menu for every player every frame (nobody is going to deal with thousands of confirmation dialogs per second). If it needs to do that, you have a problem. There will be one spot that requires calling GUI and wait.

    Also, with new details you added it starts to sound like you're mixing client and server code and are trying to do something like writing a server for thousands of clients in unity.

    In which case there's a poor separation of user side and server side code going on somewhere.

    I mean, if you are writing client list monitor that displays player status, then you won't be confirming a thing in it, and the whole system will be simply either polling remote data in a loop, or waiting for remote events.

    Either way.

    Not enough data provided, details vague and change with every post, advised to hire a full time programmer to deal with this stuff.
     
  35. Ryiah

    Ryiah

    Joined:
    Oct 11, 2012
    Posts:
    21,194
    His previous engine may have had a UI system similar to that of OnGUI where you needed to reissue the commands every single frame.
     
  36. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    If he failed to communicate that then his communication skills are worse than I first anticipated :)
     
  37. manutoo

    manutoo

    Joined:
    Jul 13, 2010
    Posts:
    524
    My Tour engine processes thousands of tennis players in a tennis tour, which has nothing to do with UI ! It's in the pseudo-code.

    How the UI works in itself is irrelevant to the issue.

    My solution requires only 1 thread to process the Tour, whatever the number of players it handles.
     
  38. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    This has officially become the funniest coding thread I've ever seen.
     
    xVergilx and RockoDyne like this.
  39. neginfinity

    neginfinity

    Joined:
    Jan 27, 2013
    Posts:
    13,572
    One extra thread is worse than zero extra threads.

    You should work on your communication skills. It is not in the pseudocode in your first post, so you're the one who failed to communicate the problem properly.

    If you're working with large dataset that requires multiple confirmation, one dialog per data item, you'll end with worker queue that would handle the confirmations for individual items.

    The thing is, I'd still do this in a coroutine and not in a separate thread, due to guarantees provided by a coroutine. Separate thread would be subject to standard multithreading issues, which you'd need to handle. Coroutine is guaranteed to happen in the same thread, and handles waiting for user input gracefully.

    Code (csharp):
    1.  
    2. while(!workQueue.empty()){
    3.      var workElement = workQueue.popElement();
    4.      if (workElement.needsAction()){
    5.           var dialog = new GUIDialog();
    6.           yield return dialog.execute();
    7.           if (dialog.result){
    8.               ...//stuff
    9.           }
    10.      }
    11. }
    12.  
    By the way, there's a problem with your threaded solution:
    Code (csharp):
    1.  
    2.  void RequestUserInput()
    3.     {
    4.         CGui.OpenMenu("HeyUserTellMeWhatYouWantToDo");
    5.  
    6.        while (!GotUserInput())
    7.        {
    8.            m_State = EState.e_RequireUserInput;
    9.  
    10.            while (m_State != EState.e_Processing)
    11.            {
    12.                // Do nothing, just waiting...
    13.            }
    14.        }
    15.     }
    16.  
    ^^^ This stuff will busy-wait. "Do nothing" part will overload one CPU core to 100%, and if you're on a mobile, it'll drain battery power doing nothing useful. This will be an extra CPU load in addition to the one already added by the engine.

    So, yeah, fairly bad choice, in my opinion.
     
    Last edited: May 21, 2018
    xVergilx and AndersMalmgren like this.
  40. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    Like I said earlier your design is flawed because you run NPCs through the same code flow as the one and only player
     
  41. frosted

    frosted

    Joined:
    Jan 17, 2014
    Posts:
    4,044
    He discovered waithandle on page one.

    PS - @manutoo - despite you being unable to explain problem properly or understand responses, your games look solid. Positive and very positive reviews for both titles. Hat tip.
     
  42. manutoo

    manutoo

    Joined:
    Jul 13, 2010
    Posts:
    524
    The point of the thread waiting was to show how to synchronize the sub-thread, not how the exact implementation would be. That's the point of pseudo-code, and for me it's fairly obvious. I'm sorry it's not for some other coders here.

    @AndersMalmgren,
    If you could show in pseudo-code how you would have done that keeping the same functionality, I'd be interested to see the result.
     
  43. AndersMalmgren

    AndersMalmgren

    Joined:
    Aug 31, 2014
    Posts:
    5,358
    I'm sadly occupied writing my own game, but good luck to you!