Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use of startLuaCoroutine #11

Open
mmann78 opened this issue Jan 4, 2022 · 3 comments
Open

Use of startLuaCoroutine #11

mmann78 opened this issue Jan 4, 2022 · 3 comments

Comments

@mmann78
Copy link

mmann78 commented Jan 4, 2022

How/Why/When does TTSCarcassonne use startLuaCoroutine? The TTS documentation states how to use it, but not why. It seems to be some sort of "threading", but I haven't wrapped by head around the "threading model". Since Carcassonne is turn based, are there real advantages to using it? Can player 2 start placing a tile while player 1's animation/scoring is still being computed? Are there people that play "speed Carcassonne" and can't wait that additional second for animation to complete? Would the GUI "lock up" if doing computationally intensive stuff?
I can certainly see some potential with the AI (or computation of "complex" stats/scores), but I'm not sure how "shared variables" would work between the "threads".
The "coroutines" to start the game make some sense, but why have something to compute the sheep scoring (scoreFlockCoroutine) and not "all" scoring?

@DinnerBuffet
Copy link
Owner

DinnerBuffet commented Jan 5, 2022

So first just a quick explanation of coroutines in Lua as I understand them. They are not multi-threading. Everything runs on a single thread. When a coroutine starts, no other code can execute until the coroutine yields, at which point other code can run. Coroutines simply provide a convenient mechanism to execute code that isn't expected to finish "instantly". With that in mind, I use coroutines for the following things in Carcassonne:

  • Computationally expensive tasks - especially AI move calculations. If I were to do this without a coroutine, the entire game would freeze for several seconds while the move is calculated. Instead it calculates as much as possible before a set amount of time has passed, then it pauses to allow the game to draw a frame (in reality this does not keep the game at 60FPS as the comment implies but it's good enough), then continues and repeats until the calculation is done.
  • When I'm creating too many objects - ie when I create hint markers. Similar to the above, if I created all of the markers at once the whole game would freeze until they finished. Also, it sort of unintentionally creates a cool animated rolling affect as the markers are created.
  • For time-sensitive tasks - ie when we're setting up the game. There is no TTS event that tells us when objects have finished moving to a location. Originally I used this to allow the tile decks to travel to a certain location one at a time so they could stack up. This was before TTS added the ability to insert objects into a container with code and might no longer be necessary. However, it also prevents too many objects from being created at once like above.
  • To animate movement - I think this is only done for the wheel of fortune when the pig moves. If you use coroutine.yield(0), the coroutine will continue on the very next frame. This is very convenient to update the position of something each frame to make it look animated. Linear interpolation is also used to make it look really smooth.
  • I don't remember why it was used here, but it's probably one of the above reasons

The rest of the mod makes liberal use of Timers (ie). These could, in theory, be replaced by a coroutine but timers work well enough and are easier to understand.

I also created a simple mod to demonstrate how coroutines can be used here.

Hope this info is helpful!

By the way, there's some legacy code here that should be removed. The comments should explain why it was added. It's only used by the sheep coroutine now and can be replaced with the lua default.

@mmann78
Copy link
Author

mmann78 commented Feb 21, 2022

This was all very helpful, but the question that arises is "Am I only allowed to do ~16ms of processing (time in between frames at 60 FPS) before I have to yield? I'm certainly not measuring the processing time of routines, but the AI is certainly an example of something that would probably take more than 16ms to complete. I presume remaining judicious about where to add yields to the various AI loops will keep the graphics from lagging.

Side note: I have cleaned up the sheep coroutines that used the "home grown" routine handling.

I'd also request that you email me privately (email address is in the commits of my forked repo). I have some "offline" questions I'd to ask.

@mmann78 mmann78 closed this as completed Feb 21, 2022
@mmann78 mmann78 reopened this Feb 21, 2022
@DinnerBuffet
Copy link
Owner

This was all very helpful, but the question that arises is "Am I only allowed to do ~16ms of processing (time in between frames at 60 FPS) before I have to yield? I'm certainly not measuring the processing time of routines, but the AI is certainly an example of something that would probably take more than 16ms to complete. I presume remaining judicious about where to add yields to the various AI loops will keep the graphics from lagging.

You can certainly block the whole game from doing anything until you finish the calculation, but that will cause a very ugly freeze. Nothing is stopping you from doing that, though. What I came up with is certainly not perfect. It doesn't take into account anything else TTS is doing so it won't guarantee a consistent framerate. You can even see the framerate noticeably drop, but there is a tradeoff between that and AI taking a very long time to calculate. I decided not to put too much effort into trying to make it perfect since players are essentially just waiting there for the AI to calculate anyway. I played around with different values and this is what I felt gave the best user experience.

I'd also request that you email me privately (email address is in the commits of my forked repo). I have some "offline" questions I'd to ask.

Sorry I can't find it. You can add me here if you wish to chat: https://steamcommunity.com/profiles/76561197962338210

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants