 and welcome to yet another episode of the scalable multiplayer game design live stream with red hat here. Today I'm joined by Roddy Kiley, whose name I think I pronounced correctly today. Yes, indeed. Yes. Michael Clayton. And man, we're still not getting the audio from you. And Jared Sprague. Sprague. Hello. Sprague, like Clayton. Okay. That's not where I was expecting that one to go, but sure. So while Michael unfortunately is fighting with his audio, last, do you does anybody remember what we talked about last time? I think we, we had, I thought we did do the config stuff, but I guess we didn't. So what did we do last time? I think I spent a lot of time talking about networking updates, I'm pretty sure. Oh, yeah. And we briefly mentioned the config stuff. Okay, but we did a great job on that, but we didn't, we didn't dig in because Jared wasn't here. So Jared, you had said that you were willing to sacrifice yourself to the demo gods to show some of the config stuff. Sure. Why don't you take over and maybe share your screen and get after some of that? Sure. Yeah, I won't, I won't take up too much time with that. I will share some stuff. Yeah. So let me share my screen here. Oh, host disabled. Oh, of course. Why, why would it be any other way? Security share screen should be available now. Got it. And I probably need to share my entire desktop because I got terminal and browser. So I see it. All right, everyone see. Okay. So let me get started here. So I'll turn off the, let me make my browser a bit bigger, except wide screen makes everything look small, but I'll make it bigger. All right. So let me just show, let me just explain a little bit. So before we, before I did that, I added an enhancement to the game server that allows us to put config variables into a config file, which changed often, you know, because before that, we had some values hardcoded in the code, which would mean if you wanted to change some things, you actually had to like change it in the source code and then do a rebuild of the C++ server, which is a lot. Yeah, it's a lot, especially when you're just trying to debug stuff, right? And you want to like change values and see it immediately show up. So that's what I tackled and using YAML. So I found a library for C++ called CPP YAML, which was really, really easy, a great library. And that's, and I kind of did a refactoring of the code. So like, we had a bunch of the config stuff in, in the, like the main launcher file, which I moved into, I can all can kind of consolidate into a config class, which includes, and so now the variables that you want to use to change the way the game behaves can be done through these different methods. So you can either, you can still put it in a command line, you can put in a command line argument. And the ones that were hardcoded before I extracted out. So they could either be a command line argument or put into, or put into values in the config file. And then if you leave them out, they all have defaults. And here's the listed defaults here. So let me show a quick example of that. So here's the, here's the screen, but here's, here's the game server. So actually, here's the config file. So we got the broker URI endpoint, the sleep cycle, which is really the game tick, like the milliseconds to how often the game loop runs. And then the, the queues for the broker queues that they go into. So the game in queue and the event queue event out. And then the force multiplier. So we don't have a lot of variables yet, but this will get a lot bigger as the game grows, like potentially anything that can change, you know, like number of bots we want to put in or like, you know, what, but so many things. And then, then you can change how the game behaves by just changing some files in the file. So right now, this is the default every two milliseconds. So if I run the server right now, well, first of all, you can see there's hardly any command line arguments because it's pulling it before this was a really long command to start the game server. But now it's just running every two seconds. I go over to the client. And if I try to move, it's going to move very slowly because it's like every two seconds, it moves just a little bit. Yeah. I'm like, okay, that's not very good because so slow. So to fix that, now, instead of doing a rebuild of the code, now I have to do is like coming to this config file and be like, okay, let's make the force multiplier like 100,000 and make the server tick 50 milliseconds and see what that does. Now run it again and refresh the client. And now it's like, whoa, boom. Now it like moves right away. And you can see how smooth it is because it's a 50 millisecond server stick and positions are lurked between ticks. So it looks really smooth. And the force multiplier seems to be, and well, I guess that's the whole demo pretty much just by changing the values in the config file and refreshing the client, you get immediate results of testing stuff out. So that's it really. Very cool. Yeah. That's really makes life easier. Yeah. And so one of the things that we had sort of realized was, we can, so actually if you want to show your screen again, since you have it up, if you start the game or if you like restart the server and then join with one browser tab or just refresh or whatever and then join in the other browser, everybody starts at zero, which definitely doesn't work. Like now the players are quite literally on top of each other. And in some cases, you can see them. Yeah. Now you actually ended up with a third one. Yeah, I ended up with a third one somewhere. So yeah, this is bad, right? So we need to sort of somewhat randomize the player position. And there's no way to quit the game right now. So like if you just close one of your browsers, the server has no time out and the client is just like, okay, later. And like nothing actually happens. So I did some hacking around to try and fix some of these things. Also, the way that we're applying forces to the spacecraft, like when you press the left or the right arrow, it simply moves left and right. You can't actually rotate the ship. And so I tried to figure out with Box2D how to do some of those things. Do you want to, do you have a demo to show? I certainly don't have a good demo to show, but I will do my best to make something work here. Yeah, we can. Welcome. You have made it. All right. Can you all see my tiny little text here? Yes. Okay. Yes. Make my text a little bigger. So what do we want to start with? So one of the interesting things was, oh, we'll start with the quit button because that's like the easiest thing. And so because we're using Phaser, we have a bunch of scenes. And then we start with this initial like preload scene. And so what I did was I just took the font awesome, like X circle, PNG, and just downloaded that to make it a sprite. And so then we preload it. And then when the main scene is opened, we add that X in the upper right hand corner. I was trying to figure out how to actually make the button pressing do starting a scene. And so I found some random post on Stack Overflow that was like, oh, it's actually the scene property of the scene. Let's start the scene. I don't know whatever. You can read the post in there by looking at the link in the code. But that gives you a button that actually does the thing. And so if I npm start here, it'll open, of course, the wrong browser. But here's the browser. And you see this little X button. I don't have a server or anything running right now. So there's no player to come up. But if I click the X, what it's going to do is send a leave message and then switch to like a quit scene, which right now is empty and does nothing. But here's where we could put credits or whatever. One of the things that we're trying to figure out how to do is make it so that when you close the browser tab, that it does the same thing, like sends an actual leave message to the server. But that was one of the sort of minimal things that I worked on. So we actually, we have a quit button now. This is awesome. I'll just say like, can you talk a little bit like one thing I'm really curious about is, how did you figure out the right format of the message to send to remove the player? Yeah, it wasn't, it didn't take a whole lot to figure out. So in the code, we already have the proto buffs that define the message types that we send. And so we already have this security command buffer. And when you send a security command buffer message, there's two types. There's a join type and a leave type. And so we were already consuming a join message somewhere. In the AMQP client, probably. Oh yeah, right. So if we look at the AMQP game client, we were already consuming the join message. So let me look through here. So on a game event message, we have this callback. And then if there's a message body, we decode an event game buffer. And then we look at the event type. And then we already had this like security game event buffer type. And we already had a way to send the join message to construct it as a join. So here's the security command buffer that is type one, which is join. So to do the leave, I was just like, oh, okay, well, that's type two. So I just copy pasta the join into this leave function. And we should probably actually implement a send join function if we wanted to be super pedantic. But it's the same exact thing. It's the same exact thing, just type two. So we send our UUID and type two. And the server is like, cool, I got a leave message. I'm going to delete your player entity. So that's all the server needs to know like about a player is it's UUID. Today. Okay, I mean, we probably want to implement some kind of stronger authentication. Yes. Yeah, so that you can't like hack your way into deleting deleting other players, which reminds me so a million a million years ago. Go ahead, Derek. Could be a fun game in its own right. But also funny thing a million years ago, I used to be a bulletin board kid. And so there was a local bulletin board that was based on the galactic comm software. I don't know had 12 lines or something like that. And there was a chat room. And there was a text based brawl game, where it was like an old Western like you could have a shotgun or a revolver like stick dynamite or whatever. And so when you would play this game, and this was in the days of like 2400 and 9600 broad modems. And a lot of people use this modem connection software called telemate. And so when people were playing the chat game, the brawl chat game, if somebody grabbed the stick of dynamite and lit it, it would explode within a certain period of time. And so the goal was you would you would hang on to the dynamite as long as possible and then throw it. And so what people figured out is that if you private chat joined with somebody, and then fired off a telemate macro that sent a bunch of backspace characters, you could basically flood the other person's modem and like it would disconnect. And so you would you would private chat somebody who grabbed the dynamite and then like and then backspace flood them and then boot them off the server and then the dynamite would blow up in their hands. Anyway, that's I don't know why this that came to my mind when we're talking about this join and leave command. But yeah, anyway, oh, because you could just like randomly, you know, delete other players security. Yeah, so we'll have to come up with some mechanism of, you know, like something you haven't something you know that, you know, only you can delete yourself your session or whatever. But yeah, that it was really it's what it was way simpler than it might have seemed because it was just changing the type of an existing message. I mean, that kind of thing is has not changed, right? Like games still have that today. Like not like just weird stuff that you can do like that. Oh, yeah, like flooding. Especially multiplayer games are yeah. People are always looking for stuff. Yeah. Yeah. So that that's the leave. So that's that's pretty trivial. And then before we move to the next. Yeah, yeah, go for it, Michael. Are other players you use these available? Like, yes, they have to be because we need to know which player comes in and then what happened to that player? Like, what is their current position? What is their rotation? And so on and so forth. And so if we look at the actual main scene and we look at the game loop, well, actually, no, we'll start here. So when a message comes in from the game server, we decode the message as something. And so if it's a player did something that comes in as a entity game event buffer, which has like a position and a rotation and a whatever. So when we look at process entity game event, all we do is we check if we already knew about that player. If we didn't know about them, we initialize them again using the UID. Otherwise, we just update the player array from the UID. And then in the game scene on every tick, what we do is we just iterate over all the players that we know about. And then we update their state, either we initialize them if we didn't have a sprite for them already. Or we just update whatever their sprite was. And what you can see here is I added this to destroy thing. So when we have the leave message, or I should say, when we receive a leave message, so we process the security game event. If we look at the process, the security game event, if it was a leave message, we do a player destroy. All player destroy does is... It's going to remove them from their array of players probably. It marks them for deletion. Yeah. Oh, right, of course. So here's the player destroy function. And so all we do is we mark them as to destroy true. And then in the game loop, if we encounter a player with to destroy is true, we reap the player by using phasers destroy method on the physics group for that particular player's object. And then we delete them from the list of players that we know about. Because if we didn't do this, then we accidentally reinitialized them on the next go around because it's like, oh, we found a player that we don't have a sprite for. Yeah. That's not what you want to do. So yeah, that takes care of effectively nuking the player. So I think, Michael, that answers your question about, do we know everybody's UID? Yeah, it makes me wonder if a really simple solution to the security problem would be you have one UID like this one that's just for identifying players, tying them to their sprites, and everyone receives those. And then there's a secondary security UID that's only issued to the player that it belongs to. And that's what you use to leave. And so then... Yeah, we could probably generate some five or six digit token that gets sent to the client once the player joins. Like, hey, we're acknowledging your join. This is your special token that you need to remove yourself later or whatever. I mean, heck, you could just use JWTs, right? Jason Web tokens. Well, that's actually what I want to do for... Well, if you think back to the early days of the stream when I showed some of the chat lobby stuff using Red Hat Single Sign-On. And so we were already using JWTs for that. And so my thought was that when the player goes from the game lobby into the game client, that we would use their JWT to basically identify who they are. And so you would send the JWT to the server when you're joining. The server would validate your JWT against Red Hat Single Sign-On. And so then when you send a leave message, it would be the same thing. Like, does this JWT match who you are logged in as? And if it does, okay, cool, we'll delete you. We'll leave you. Yeah, man, Michael, I don't know why Zoom is bad about gain, but unfortunately... I believe my level is a little better now. It's better. Just scream. And so you can see here, I started to try and add some text, but I couldn't figure out the next step to actually put text on the player in Phaser. But yeah, anyway, anybody have other questions about the client? Okay, we'll switch to some of the server changes that I made. Server changes. So what you saw when Jared was playing with his character, you press the up button, the thing moves up, you press the right button, it moves directly to the right. There's no rotation. And in a space game, normally you would rotate, and then your thrust is applied in the direction that your spacecraft is traveling. So there's a whole bunch of things that I had to do to make that work. And so if I look at some of the changes here... Oh, this is only going to be the changes. I want to compare the active file against... Oh God, what did I just do? Okay, that did nothing. I want to look at like many of the changes, but that might be... Oh, wait, let's see if I do this. And yeah, there we go, updated. Ha-ha! Okay, cool. So what you can see here are a bunch of... What? No. I want to... That's not fun. I want to change... Compare this one. There we go. Okay, cool. So the way that we had it before... And again, we're using Box2D for the physics engine under the cover. So firstly, our player was a shape of a circle, which like... I mean, the spaceship is kind of like a cigar shape. It's not really a circle. We were using a specific circle shape. We were applying force directly to the center of the object. And so left just moved you to the left and right moved you to the right. So what we need to do is we need something that's like cigar shaped that has the appropriate mass and that we apply force in the correct ways. And so one of the things I did was I changed it to be a box. We had talked on the stream previously, I think maybe two episodes ago. We were going to have a ship that was about 300 meters long. And I arbitrarily guessed that 60 meters wide. And so when you use set as box with Box2D, you actually are using the half values. And so if the size we wanted was... Oh, sorry, I did that totally. I lied. It's 150 meters long and 20 meters wide. So I took half of that as 10 and 75. Note that Box2D uses metric units by default. It's actually unitless by default, but it tells you to think about things in metric units. And so it's like kilograms, meters, seconds, that kind of stuff. So this is a cigar that is 20 wide and 150 long. The way that Box2D calculates the mass of an object is rather bizarre. You don't actually set the mass. You set the density and then it uses the area of the object and the density to calculate the mass. So I just did some simple backwards math and I said, well, we had decided that we wanted the spaceship to have a mass of 20,000 kilograms, which who knows if that's a reasonable number or whatever. But to go backwards into a mass of 20,000 kilograms, it was basically 20 times 150, 20,000 divided by 20 times 150, which gives you six and two thirds as the density. So this is the density. And when the fixture gets rolled up into the body, so Box2D uses this concept of you have a body that's made up of multiple fixtures that can be attached to each other in different ways. When it rolls up the density of the fixture and the shape of this particular fixture, which there's only one fixture right now, you get a mass of 20,000 units, which are kilograms. So then we had to figure out how we were going to handle the forces. And so I found another SACO exchange post that talked about how to move a Box2D object in the direction that it's facing. And so if you think about the ship, if it's facing up and you apply thrust, it should go up. But if it's facing at an angle, and you apply thrust, it shouldn't go up. It should go in this direction, like the direction that it's facing. And so the way that you do that is somewhat stupidly, and obviously in hindsight, using trigonometry. And so you take the angle of the object from zero, and you apply the cosine times the thrust value, and that gives you the x vector of the thrust, and then you take the sine of it to get the y vector of the thrust. And so that gives you how much force is being applied in the appropriate vector. And then we multiply that by our force multiplier, because that is what we're trying to figure out. Like, oh, what should the starting thrust be? It's a config object, whatever. And then we can just apply that force to the center of the object. Like, we theoretically should apply it to the end of the object, but it kind of doesn't matter, like, because it's a single object right now, whether you apply the force at the center or at the end, it's still gonna theoretically achieve the same goal. Maybe it wouldn't, but whatever. We'll go with it for now. And then turning left or right should really be applying a torque to the body. And this is, I think this is not the way we want to do this. I think we actually need to apply a force to the end of the ship. Or we have to figure out, theoretically, where the rotational thrusters are. I think that's correct, yeah. And that'll change over time, too, as the pod picks up. Yeah, yeah, yeah. So this works very badly right now, only in the sense that it's way slower than the thrust, which I don't understand why. My assumption is that the torque, wherever the torque is being applied to the body, it's like, you ever try to open a door from the hinge? It's really hard, it doesn't work. But you try to open the door from the end, it's like zoom, it just opens up. And so I think this applied torque, I have to look at the definition of where that's actually being done. But this does actually work. There was a backwards thing in the game client that I just fixed on my end. So we were like, I would press right, and the ship would go forwards. And it's like, that's the X and the Y or the backwards. So if I try and do... Oh, and then the last thing was, how do we get the player to not start at zero all the time? And so we have this creation thing where when a new player comes in, we add their pod. And so we create a Box2D entity. So we have regular server entities that have their own metadata. And then we have Box2D entities that are attached to them. So we have our pod, which then has a Box2D pod that's associated with it. And all I did was I used the random that came into C++11. But it's actually not particularly random. Like I think it's the same random number every time, whatever. So we need this to be a little more random. But it does work. The second player is not in the same position as the first player. It probably needs to be seeded or something of that nature. Yeah, but then if you seed it, like you'll still get the same order of random numbers. So like we need better... Normally we read the current system time or something like that. Yeah, we need some more randomness variation there. But we do legitimately get players that end up in different positions. And like I added a whole bunch of more barfy log messages about, hey, look, this is what the actual mass is. Here's the inertia and so on and so forth. So if I debug the server... And I'm just going to run it log level one because we don't really care about the log messages. And if I then... Oh gosh. Oh, sorry, my keyboard went to sleep. And now it has to reconnect to my laptop. There we go. Okay, game server is running. Where's the good browser tab? Let's do this. All right, so do local hosts 3000. And what we see is our player starts over there. And if I press the right arrow and hold it down, it's going to take forever, but you can see it's rotating. You see it rotating? Yeah. Not straight. And now if I press up, it should go in the direction that it's pointing, but it's going backwards. So that's sort of bad. So there's some number problems here. But if I keep pressing right and up, it should sort of go in a circle-ish. And it's kind of doing that, but not really. So clearly it's doing more or less something in the general vicinity of what it should be doing. It's totally doing it wrong. Yeah. But this is prototyping. So it looks like we've got some digits backwards. And so one of the challenges I was having was like, I was talking, we were talking about this before the stream. If I come into the server and I set a breakpoint on, oh gosh, come on. If I set a breakpoint in the update and the force calculation stuff, so we'll set the breakpoint here. So here's a breakpoint. If I go into the debug console, we've got our... Yeah. So all we have is a this. And it's like, I'm bad with trying to debug C++. So we've got this body, which is the thing that we applied the torque to. But so I can do something like this.mpb2 body. And that'll give me the right object, but I can't actually use any of the functions. That exists because I'm in weird C++ debug LAN and it's not a REPL or whatever. So it's like, well, how do I actually get the angle of the thing? If it's not like... So if it's not one of the variable objects on the thing, then I actually have to go and look at the definition of this function to figure out how to do the thing. I don't know. I'm not good at debugging C++. But anyway, I did a thing. Yeah. That's awesome. There's a bunch of stuff you covered. I have a few questions. So... Yeah. Ooh, sexual. The... Oh, yes. So first one, with the picking a random... Okay. Picking a random position. Yes. Keep it from... Keep it from hitting the same person out. But there's always a chance that you will have... If it's just random, like that you will end up getting a spawn point on top of another player. Yep. Yeah. So is there a distance function where you can be like, am I too close to another player? Just like an... And if so, let me pick another point to... Yes, but no. And so right now, this function... And, Rod, you might understand more. This function only takes a UUID as an input. But what we could do is in the... Sorry, I have to find... Handle, join, security, command, executed event, and then game buffer and queue. I got to find... So basically like in the place where we call add pod... Oh, I could have just done that like this. Sorry. I'm not the C++ genius here. A entity, add pod, go to references. Yeah. If you look at the structure of A entity, which is the abstract entity class, it keeps track in a list of all the pods. The whole class keeps track? Yeah, that's right. Because it's basically a parent... Yep. Yeah, there's a static member. In the parent class, which keeps track of all the instances of entities as they're added. So if you look at a entity.h, line 68, or in the vicinity anyway, scroll up a little bit, there you go. So there's a list of pods there that's private, right? So like we could add a function to the parent class that loops through the list of instances of entities, in this case pods, and grabs their location and calculates distances. Based on that, right? Yes. Well... Maybe we can ensure there's no overlap. Yeah, it would be a little bit more... Not to like, I guess I am totally nitpicking, to nitpick a little bit. It's a little more complicated than that because what we would do is we would look at the list. And so the first player can be random. The second player, we would then apply some kind of distribution function to basically like equidistance new players from all other players kind of thing. So instead of trying to be random, like we would be more mathematical about it, if that makes any sense? You could do that, but I would vote for just keeping it simple. All players start at a random position and you just generate a random position, make sure it's not too close to anybody. Yeah. If it is too close, you just run... Generate a new random position. Yeah, and that's exactly what we do as Orbeo. Like I say, the function for that, it's that's the algorithm we use pretty much to pick a random position and we have a minimum distance that if you're below that, it picks another random position. And if it tries that... And then we have... The only other thing is we have like a retry limit so it doesn't get into an infinite loop. Yeah, and that's... If it tries like 10 times, it'll just go with the last one. I don't think... So while what I described sounds complicated, it's probably been solved like a million times and there's probably just a straight up mathematical theorem that says, here's how to equally distribute something in a 2D, whatever. And I'm sure there's probably already an example, C++ implementation. So I don't think it's going to be that hard to do because a lot of these path walking type things are well known. So then the question is, is that a good gameplay thing to do? Like what do you think, Eric? If you're going to start a game and you're jumping in as a new player, do you like the idea of knowing exactly where you might land? Because it'd be equally distributed or would you prefer a randomized distribution? Well, you know... So a couple of things, equidistant doesn't mean the same every time. It just means that whatever the distance value is, that's my guarantee from every other player. So we could randomize the distance within some window. And so you know you're going to be at least this far away from another player kind of thing. I think I would probably prefer... Actually, I don't know that we can say until we can actually shoot each other because there could be reasons why one would be better than the other. That just leads us into a strategic discussion, but we have no real meaningful gameplay. Characteristics yet. So I don't know that we can make a decision. I think at this point in the game design process, any algorithm is as good as any other. Yeah, I think I would say that... With this decision depends a lot on how the game is going to start. Because if all the players start, like if an instance starts and you have 12 players or whatever, start all simultaneously, I would say you would want to have equidistance spawn rate. If this is more of an ongoing thing where players are joining and leaving and joining and leaving all the time, players are going to be moving around. It's impossible to have equidistant because as soon as someone joins, they're going to start moving and there's going to be clusters of players fighting each other. In that case, just having a minimum spawn distance, I think makes more sense. Just don't spawn too close. Spawn them too close to somebody else. You're never going to have equidistant because as soon as players join, they're going to start moving closer to other players. And so there's no concept of equidistant space between them. No, there absolutely is a concept of equidistant. It's mathematical. No, there is a concept, but let's say... Okay, so if you jumped into a server where all the players were really close together at the moment you jumped in, equidistant would put you really close to all the other players. If you jumped into a server that was sparse and all the players were really far apart, then you'd end up really far apart from everybody else. Oh, yeah. I would say I would not want to spawn like into a cluster of people fighting. I definitely would not want to be doing that in the game. So you're saying equidistant, meaning... Eric, you're saying equidistant as in you assign... You find the distances between each player to each other player and take the mean of that and make that the distance that the new player... I didn't understand if all the players are close together, then the new player would spawn. Well, so if all the players are close together, then you being equally distant from every player means you're likely to be close to all of them. Like, in theory, you could be equally distant to all of them and very far away. So that gets us into the minimum distance thing. So I guess you're right. It doesn't guarantee that you're close to them just because they're close. But anyway, I think we're kind of spiraling out into a weird discussion. It's kind of relevant to the design, though, because I'm still not sure is this game going to have a discrete beginning and end where 12 people start, play for 15 minutes, and then the game ends and then an excellent starts? Or is it going to be like an always-on kind of people joining and leaving or joining and leaving all the time? I don't think we're at that point yet either. Okay, because that would... Like, we don't know. One could be more fun than the other or whatever. So I think I don't think... Like I said before, any distribution mechanism at this point is equally viable and has to be evaluated as fun or not fun to stick with something that Derek says a lot. Yeah, I think that's fair. So it's certainly the easiest one to implement, which is the one that's on the screen right now. Yeah, this is the simplest one that we could possibly implement, which is like just do it random and if they end up on top of each other, so be it. You know, we can get better later. So one thing I noticed too in your demo is it looked like it spawned a player like up, like off to the side, like where the random position was. Well, yeah, that's just because I don't understand how your camera stuff was working. And so all... Go ahead. Yeah, I would say that's a client improvement we can make, which is basically the camera, the player who, like the first player who's playing is always in the center. But the other players, it'll look like they're off to the side. The camera should ideally be centered on the player. Exactly, exactly. Right, right. So yes, I would agree with you that this is an artifact of the way the camera centering is implemented. And that's really easy to do in Phaser, like we can easily... Yeah. It's built into the library. So we can put that as a list of a client enhancement for post stream. Yeah. Man, I had other questions too. Was it about rotation? Oh, yes, it was about rotation. Yeah, so you must be synchronizing the rotation between the server and the client. Yeah, so if we look at the protobuf for Box2D, so in the protobuf for Box2D, the current angle of the player object is defined. And if we look at the definition in Box2D's documentation, this number is in radians. Gotcha. That was my next question. Perfect. And so it so happens that Phaser has a set angle and a set rotation. And so all I do is I take the player body angle, which came in when the update came in via the AMQP message. And then I just set the rotation to the player body angle. Awesome. So it synchronized to whatever the number is. I don't know if we're synchronized correctly. So like it does rotate as you saw, but is up on the nose of the ship, really up on the cigar of the Box2D object on the server. And I don't actually know the answer to that right now. Yeah, but you're definitely, yeah, but I don't think that answers my question, which is like how you're sending the angle to the client so it knows to turn. Yeah, that one was actually pretty simple. Cool. Cool. Good stuff. Yes. Cool to see the ship turning now. Now it'll be like, I mean, we needed to do that for adding mouse and touch controls. Absolutely. The ship can rotate based on wherever your pointer is to face it. I know we can sync that angle. Yeah, that'll be a lot better than an arrow key. I don't know, man. I like the retro arrow key style. Yeah. It's like old school star control. You just have to train your brain to know when your ship is pointing down and I want to go forward, I still have to push the up arrow and not the down arrow. Well, but I mean, that's like, that should be sort of emergently obvious. Like up is forward thrust, down is backwards thrust. I think it is, but like people, I'm sure some people, like a lot of people would get turned around. Maybe. Definitely could happen. Have any of you tried flying? Instead of the sprite? Yeah. Take in. That's always, we could try having the sprite fixed to the screen. So when you press up, you always go this way. And when you rotate your ship on your view, it just rotates the world under it. That's right. The camera rotates. Yeah. Yeah. That's a more concise way of saying it. Thank you. Maybe. Yeah. But I think it will be a lot more intuitive when we use pointer controls and you just have a forward thrust and a backward thrust. Yeah, something like that. Roddy, what were you going to say about flying? Oh, have you ever tried to fly radio control aircraft? No. Yeah, that exact problem, right? You take it off and it's flying this way and then when it turns around it's coming toward you, right? Yes. So all your controls on the sticks are opposite? Yes. Same thing with the remote control car. I always used to crash my RC cars all the time because it would be coming back at me and I'd want to go left and I'd go right and I'd just drive it under some car on the street and destroy it. That's a perfect example. Exactly what I was saying. Yeah. But in a top down, so I never had that problem when I was racing at the RC car track because you're standing on the platform above and looking down and so your left is always left from that perspective. Like, yeah, it's coming at you but like it's coming at you from under and so it's just it's intuitively left is left kind of thing. So I don't know. Well, again, this is one of those like game design things. We'll have to try it and see. Anyway, I think all that goes away when we switch to using pointer controls. Yeah, yeah. Where was the code that you had up earlier that had the sign and cosine for? Oh, that was in the server. I was looking at the repo trying to find it. Oh, it's in the branch called pod density mass and it's in B2D pod CPP lines 99 to 102. There we go. Sad RC car stories. Yes, Chris, we all have them. Me too. I always bumble through trig on games. It's kind of like I feel like it kind of works like this and it's not quite right and just substitute. Kind of work on it until it works. Eventually it works. Yeah, my guess with this one is that it's probably like a down is up and up is down kind of thing. So they're both they're both being multiplied by the X component. Yeah, that sounds like it could be a problem. Yeah, the Y thrust is sign and cosine makes sense. I think that seems right. But the thrust dot Y is the sign of the angle times the move dot X. Should that be move dot Y? I don't know if Eric is having connectivity problems. No, I hope not. It was me last time. But I'm optional. Eric's not easy. A little freezy for everyone else. Yeah. Okay. Not trust me. Eric, did you catch that question? My machine is having a bit of a meltdown. I don't know if I'm back yet. Yeah, I think so. Yeah, my load average was like 30. That'll do it. Yeah. What was the question about? So the second line there thrust dot Y. You just switched to me a little bit. I was asking about the- I just reversed them. Okay. It was the multiplication component on the second line that was the AB2vecmove dot X. It's dot X. Yes. And so the reason, yes, it's intentional. So if you think about what comes in from the client, right, the way that the client sets direction is if left is down, it sends negative one. If right is down, it sends one. If you're pressing up, it sends negative one. So you're only- Oh, this is what's backwards. Yeah, this is actually backwards. Why would down be positive X? No, it's- When you're pressing the down key, shouldn't it be negative? Well, I mean, like, slow down. I mean, that works. Like when in the client that I have anyway, like, I did have to- I thought that too, like original one. Origin's top left, right? In Phaser? Yeah. I think that's right. Well, but this is in Phaser. This is Fox2D. I mean, right. Yeah, but this is getting, this is what's getting sent, right? Yeah. But the- I mean, the way that the client sets direction the way it has been sent, like you push the down arrow. Right. But we changed from apply force to center to apply thrust with sine and cosine. If you change stuff on the center again, this could be backwards. And as you saw, it was backwards. Yeah. So it's either we have to change this, but to me, this seems backwards. Like if the button press is implying thrust, then up should be more thrust and down should be backwardsy or whatever. So if I change this to one and then change this to negative one, what I should get now if I rerun the server- That's the X. That's the X, right? This behavior. Yeah. Yes. Yeah. See how that, yeah. I mean, just- I don't know what I changed and why it's rebuilding, but anyway. So that's there. So if I refresh this, and if I press the up button, it moves to the right, which is fine. What that means is that the rotation of the actual box 2D object, zero is to the right kind of thing. Like the coordinate system is the problem, if that makes any sense. Does that make any sense? So we applied thrust and it's moving to the right. The sprite is pointing up, but if we're applying thrusts using this formula and there's no rotation right now on the object, then that means the thrust is being applied in the direction of zero. So if zero is to the right- Oh, I see what you're saying. Zero being like the radian angle of zero. Yeah. So it's basically our sprite isn't aligned with the coordinate system of box 2D. So either we have to change the sprite default or, yeah, man, it's right. I keep getting this framing error. Like after the server runs for a little bit- So I wonder was that a new thing? Because I don't remember seeing- I get that. I've always gotten that right. I always get that. Ever since I started using the server- It runs for a while and then it just dies with that. And I think that's when this happens. Well, that would happen because it would clear up the resources after the connection drops, right? Right. But the weird thing is that it's saying it didn't receive any data within the GTL, but how is that possible? The server's constantly sending data. That's correct. So unless this is the client- Well, what's 1088.01? 1088 is the- That's my laptop, isn't it? The client or the server. Are you running the client containerized? Because I think 1088 is the problem on submit. Right. But one is my laptop. So it could be the game server or the game client. Okay. And according to this, we didn't get disconnected. So my guess is it's the server, but it's hard to know because it doesn't log new connections, which is somewhat annoying. I mean, I'll have a fail like that when it's just running in the background and the client's not even connected. Because I remember in the beginning- Well, when the client's not connected, the server isn't sending messages. Okay. Say it again, Roddy. I was saying in the beginning, I remember there was an issue on the stomp side where there was no heartbeat on the link, right? And when there was no heartbeat- Right. But that was different though, because it would just time out. But this is an actual framing problem from a name QP point of view. So it's like some packets go awry somewhere, which doesn't make any sense given that it's TCP based, right? Well, the framing error, I think, is the server's reporting that the connection to the broker was severed in a weird way. And that's why it's a framing error, because it's clearly saying like- Yeah, in this case- We didn't get any data. Yeah, this message is likely the client side, right? So because the server is clearly spewing out data nonstop because it's all the physics updates, right? And but the client hasn't sent anything back because had we not touched the ship that time for 60 seconds? The client. So which client is this referring to? The one on the browser. So 60,000 milliseconds is 60 seconds, isn't it? That's right. So I'm saying is I think we were packing about 60 seconds since we started the move of the ship. Oh, I see. I think I see what you're saying. Yeah, yeah. Yeah, yeah. In which case then something terminates abnormally. So it shouldn't have timed out though it did. And then an abnormal termination happens according to the server. But why would the server care about of the random client that gets- Because there's an exception that's not being handled coming through from Proton. That's my guess personally. There's an error message that's bubbling up. Oh, right. I mean, don't say unexpected error. Right. However, it says exception has occurred. And then it's a second patient fault, right? So an exception- But it's weird that it occurs here. I guess this is just where the program is at the time that it happens. Right. And if you look in- It doesn't mean it actually happened in there. It doesn't mean that that's the cause. So either way it sounds like- It looks like- I need to reproduce and fix. Yeah. Because the other thing is if you kill off the broker, for example, the server goes down, which is pretty silly, right? But it's just a case of- Yeah. Where the disconnection is not being handled properly. Got it. Yeah. So within- Yeah. So this was the thread that was paused on the exception. But it doesn't- It doesn't- It's not clear to me from this like, you know, where it actually is. Yeah. So it's a segmentation fault. So maybe something happened and exit was called. Because I noticed in the proton handling code, if there's an on error handler called at the moment, on transport error called, then exit one is called. So when exit one is called, that thread immediately exits. And so all the stuff that's defined in main, all the instances become invalid. So if another thread is still trying to run with that data, it's going to be crap. It's going to be- Got it. It's going to make it something bad happen. Yeah. So it looks like we need to figure out how to orient how the sprite should be oriented within the box2d world. I wish the box- I wish the documentation for any of these things was better. Like, it's not clear. Box2d to just set the angle of vector. I can't find- I see get angle, but I can't find a way to just like give it a vector. What are you trying to change on the box2d object? If we had a thrust vector that was just like x is zero and y is one. So it's always assumed to be straight up and multiply that by the force constant. And then we rotate it by the same angle that the ship's already rotated by. Then we rotate what? The force vector. Because you're doing a manual rotation right now using trig. I feel like that should be in a vector library. No, no, no. It's not a- So the trig is applying the force along the direction that the object is pointing. Because you assume that if you have an object that's shaped like a cigar, the motors at the back or the thrusters at the back. So if the thing is pointed this way, you can't apply a force in the up one direction. That's why you've got to apply the force along. Yeah, but there is no- You have to do the math on rotating. Like you can't- That's what you're doing. You're doing the math on rotating it now. You can probably read the rotation and get the vector directly from box2d and not have to do the trigonometry yourself. Exactly. I don't see how you cannot do the trigonometry. You have to calculate the force along the direction that the object is pointing. I don't understand how- So you're going to be able to retrieve the direction and then still calculate the force and apply it in the direction that you've retrieved. Yeah. It's just a simplification. There's a getAngle function that you're calling that gives you the radians that the body is rotated. What I'm saying is you can have a vector and you can call a function called setRotation on that vector that will rotate it. So if it's pointed at 0, 1, you can rotate it at 45 degrees or high radiation. Yeah, I don't think that part is the case, but I think you might be able to simplify the getAngle. You don't think that box2d has that function? No, because a vector is not an object that- a vector is not an object that box2d cares to manipulate. A vector is an object that box2d uses to manipulate other objects. So you have to apply force using a vector that's already in the correct orientation. If you need to get the vector into the correct orientation, you're doing math, which we're already doing. Well, if that's the case with the tools we're using, that's fine, but what I'm saying is it seems reasonable to expect a vector library to have a function for setting the angle of the vector. Right, but it's not a vector library. It's a physics simulation library. So you can retrieve the rotation and you can apply forces, but when you apply forces and torques, it results in new vectors and new rotations. You don't set them directly because that's a kinematic way of thinking, right? So it's either- it's one of two things, right? You can physically simulate it using, you know, forces and torques, which is just a rotational force, or you can kinematically animate it to set the rotation, but essentially at which point you turn the physics simulation off to do that manually yourself. So it's two different ways. Yeah, so here's the vector. It's a physical simulation. If you say, I want to apply a force in this direction, and you created that direction using a vector manipulation function. I don't- But that's- that's literally what- So again, like- That's what you're doing manually. I think there should be a function to do that for you, so we don't have to do- It doesn't- Right, so I think we're talking the past itself a little bit, right? So, in the case of we want to apply a force in the direction that the cylindrical pod is pointing, right? So the thruster's down here on the bottom. The pod's pointing this way. We want to apply a force this way, and we want it to move like this, right? And so the question is, what is the angle? If you look at this triangle, what is this angle right here in this little- If you look at this as a straight line, what's this angle? You need a vector that goes this way so that you apply the force at this vector, and it nicely moves straight ahead. Like that's the question being answered by the cosine and sine method, right? Along with the get angle. Yeah, so to simplify it, essentially, the Box2D library has no vector math to manipulate vectors as objects, and so it expects you to do that. So if we want to bring in another vector math library to do what you're suggesting, we could do that, but we've already done what we need to do with the sine and the cosine, which is the vector math. Well, I thought we were working on that because it wasn't working properly. It was sending the ship to the side. No, it's not that it's not working. So you have potentially misinterpreted the symptom of the problem, and the actual problem is like, is zero this way or is zero this way in the Box2D coordinate system from a radiance perspective? It appears that zero is not in the up direction, but phasor zero is in the up direction. So we just have to figure out which up is up in which system and then start with them pointed in the same direction. I couldn't care less if up was this way. I just need to know which way it is in both coordinate systems because we have two different coordinate systems that are potentially not behaving the same. Like they could be rotated by 90 degrees. They could be out by 180 degrees. It appears that they're rotated by 90 degrees. So it wasn't the force that was the problem. It was the forces being applied directly, but the way that it moves in the coordinate system wasn't what we expected. So that means that the actual rotation of the thing is here, so we just need to change where the phasor sprite is pointed when it starts, if that makes any sense. Yeah, that makes sense. Or we need to change the starting rotation of the pod when we initialize it. Also could not care less. Rady, you're probably the Box2D guru. Should we change the phasor sprite or should we change the pod initialization? The math here is correct, then we should change the phasor sprite because the display should reflect the simulation, not the other way around. I like that idea. Do we want the ship's starting point over to this side though? It seems like we do want it pointed up, right? Does it really matter? Not necessarily. What is up in space, really? I know the enemy's gate is down. Yeah. How do we convert radians to degrees? Math, unless you have a library. Kidding, really? All the math? One radian is 57.29 degrees. That is a stupid-ass number that does not help me at all. Well, because the problem is that we're 90 degrees out, like almost exactly. If you want to convert to degrees, the instant answer there has the formula. Yeah, it's 180 divided by pi times the radian. Right. But the challenge here is that we need to rotate. Oh, I can do this. Hang on. Does phasor have a get rotation? No, the body already has an angle. All right. Hang on a second. I need to hack on some stuff here real quick. Basically, I'm going to just add an extra rotation to the object, and that'll fix all our problems. Here we go. I want a break point here. All right. So we have player sprite angle. Angle is zero. Okay, so. Oh, does the body have the right angle? Sometimes I get confused about whether phasor sinks the sprite and the body. I think if you set the body, it copies it to the sprite, but not the other way around or something like that. Anyway, that's fine. And there is a piece. So does the sprite have a body? The sprite, the physics group? I don't know. But anyway, so we need to rotate this 90 degrees and the angle is zero. So if we do player sprite set angle to player sprite. Oops, that's fine. Player sprite angle plus 90. What do we get? Oh, I have to play it. Didn't actually do anything. So in the Box2D library, there is a B2 math header that does have a B2 rotation struct where you can construct it via the angle and radians. And then after that, you can take back out the X and Y axes based on that. I don't actually know what you just said. Later, there may be a simplification on the sine and cosine part in the server code, essentially what I said. So now I'm just basically adding 90 degrees of rotation in actual degrees, not radians, to whatever it already has. And we'll see if it starts in the right place. Are you running? I guess you are running. And so now if I hit up, why is it not doing anything? So is it paused? Yeah. Zoom. Yay, turn. Oh yeah, look at the turn. Turn so fast. Someday it'll finish turning. Doesn't really look like it's moving in the direction of the thrust though. It does. Yeah, I guess it is kind of going down. If I turn it more, right, now I'll apply more force. Is it going in the, yeah, yeah, that's a spaceship flying right there. Look at that. That's some amazing stuff. I did it. So if you can turn back to the left now, try turning back to the left. Someday, maybe. Oh, now I'm going backwards. I think there's still some things swapped, some values swapped. Somewhere. It appears that the torque is not being correctly negated because both left and right turn me in the same direction. You know, there's some, yeah. Just, I think this can be. So, yeah. Yeah. Torque applied, config, why? So this, I mean, this should be a negative number. Uh-oh. There he goes. Goodbye. Physics simulation is killing his laptop. Mm-hmm. Screen's moving here. I think I'm back. My machine. Yeah, correct. Definitely. That's correct. My mouse. The. Realize it again. Am I back? Yes. Yeah. So there's some issue with the torque. It does not appear to be applying torque in the opposite direction. I don't know why. Yeah. Because we are. We're sending negative and positive. So I don't think it's a swap issue. So somehow we're not getting a negative number. Or I thought I had changed that to not be divided by two. Yeah. I mean, I can. Try, I would try to log it, but my machine is so like dying. Yeah. I would just, I think we're just going to make it worse. It's good to see the demo of like turning and moving and applying the force in the direction is pointed, pointed. That's cool already. Like, I think this kind of thing gets just be moved. You'll better figure it out after just setting great points and. And tweaking stuff. Yeah. So I think the next, let's see. I did, I did left and it said. The pod updated event and consume update. Apply forces. Stop the server here. Current angle. Yeah. Like what might be handy here is like a. A local display from the server of just the box 2D simulation and show the vectors on the body and the shapes as far as box 2D is concerned. And then you could compare the client against what box 2D thinks because often they're not necessarily one in the same, right? So I say, say that again. So like, if you look at the way some of the stuff that we looked at before for box 2D shows the simulation, it's literally just shapes, right? It's just lines, boxes, circles, and then their corresponding vectors, right? Um, so like you can have your graphical display of your client and you can have your box 2D display of what it thinks is the state of the world and all the shapes it's simulating and you can allow us like, hey, over here, these vectors are not pointing in the right directions that the way we're looking at them over over here so you can see that there's a disconnect and it helps you identify what the problem might be. Shouldn't that be in a client though? Sure. Sure, otherwise we're basically building another client. But it depends on which way it's quicker to do it, right? Like you already have the simulation data on the server side. So it may be very quick to do, but at the same time, yes, I agree. And having it in the client and being able to hit a little button and say, let's see the physics simulation, that would be ideal. But wouldn't, I mean, wouldn't it be faster to display information that's already there? Oh, it's already there in the server. The client, then it would be to build a new client of the server? Not necessarily. You could, you could have it the bug mode where you had it built directly and just directly use some box 2D. Like there's a, there's a box 2D draw the bug example that you could probably integrate and just run it with like a header, like a server with an option to for the display. In the long-term though, thinking it through, that's not going to work because of course, we're going to containerize it and we want it as less surface area as possible, right? From a pod main, from a container point of view, we won't need any of that stuff. But it might be a short. Yeah, the challenge we have, it's funny. It's like Phaser actually already does some of that, except that we're not using Phaser for physics. That's right. Because the physics actually happens. So we end up not, that's right. Right. So we end up not being able to, to use a bunch of that. So we have to. That is the trade-off. Yeah. But the other thing is that like box 2D wouldn't be able to display the thing that we're doing because that just comes in as numbers. Like how would, how would we display the torque that we're applying? You can draw a vector that's pointing in a certain direction and on a certain point on the body that's being simulated from the box 2D point of view. Because like you've got your, you've got your polygon. Yeah. And clearly it's being applied somewhere on that polygon, right? So there's a point where that gets applied and then there's a value. So you could draw the length of your vector as the value and the magnitude, right? Yeah. I know that makes sense. I'm trying to figure out how you would. See if I can get a good. I'm just trying to figure out how you would do that on the client side. Because the math and the calculations are being done on the server side. So you'd have to send those back to the client. Yeah. That's right. So on the client side. Then you don't necessarily have the information you need to do that. That's correct. So like when, when a real, when, when real people that build real video games for real living for their real families to put real food on their table, what are they, do they actually build like an extra game server client to show that stuff? Like if you're building, you know, the next shooter game, like what, how do they debug stuff? Well, sometimes you do have to build in another, but it's essentially a client, but you don't care about everything. But in this case, it's not really a client because we just said the client is not receiving all the information from box to D. It's just receiving what it needs to know, right? So you could simply write something that talks to box to D and displays everything it knows about. But that is an extra add-on to server, which is essentially something that's only for debug purposes. But yes, people do spend quite a bit of time writing their own debug tools, typically when creating games. So there often is a lot of custom work to create tools to help you build the game. And certainly if you're doing it from scratch, like often you don't have a choice, right? Like when we did Gigglewater back in 2011, and we had a physically simulated two-dimensional rig of a body, the color, I just wrote the tools to display the body. And I wrote a little GUI on the side to be able to, in real time, manipulate the joint data and to be able to tweak it because there was no way to know like what was going to feel good when you had your phone in your hand and you're reading data from the accelerometer and you're feeding data into your physics model. And at the end of the day, you wanted it to feel good and play good. Like there's no correct definition of what feels good and plays good, right? Yeah, let's see. Torque applied. Well, it says it applied a negative torque. So I don't know why it didn't rotate the right way. Is it, let's see, you're sending a two degrees now, right? So it doesn't send any, so it sends a negative number or it sends negative one or positive one for either the up-down or the left-right. And so the Y is the turning. And so we have a negative one for Y. We multiply by the first multiplier. We divide by two. And then that's the torque that we're applying to the body. But it didn't appear that it was rotating it the correct direction. So let me try something different here. There's definitely something weird is going on with the physics, basically. So if I press left, I mean, it's slowly, slowly, slowly spinning to the left. If I press right, I think it just takes forever in a day for the new, because it's basically overcoming the inertia. Yeah, it's finally starting to turn right. So that was a wild goose chase. That's pretty typical in physics engines, right? And a lot of games kind of fake their values to get around to those things, but they produce wonky results. Yeah, so part of the challenge that I was trying to figure out was basically so apply torque, if we go back to the box to the reference, apply torque affects the angular velocity without affecting the linear velocity of the center of mass. And so I really don't think apply torque is the thing we want to be using. We really do want to be applying a force. But the challenge is we have to calculate the point at which to apply the force. But this point is the documentation doesn't make sense to me. It says the world position of the point of the application. But the world position, meaning the position in the actual game world or the position on the actual object. And so you can do stuff like get a local point relative to the body's origin given a world point. So like I just I couldn't figure out like what series of stupid math I had to do to figure out like where the end of the spaceship is. Right, because there's a series of transformations to get to the stream. And that gets us back to the debug thing where it's like, when you're when you're debugging, you can't actually use this function. So then I had to like go and look at like the box to the source code. In like body and then like figure out like, you know, get get position and like look at the function. Like, oh, it's returning this value. So I have to like then go back to the debugger and see what that value was. You know what I mean? I still couldn't figure out like what I actually had to do. Yeah. And so this is a common problem with a lot of game development rate is like if you're looking at a simulation, which parts need to be simulated and which parts need to be faked. And for most things, including flight sims, they're actually faked because writing a series of control programs for thrusters and simulating those thrusters in addition is going to be very complicated and time consuming versus just saying, we're just going to apply a rotation and then recalculate physics afterwards. And so for our particular circumstance, we may want to avoid as much, you know, physics type work, right? Allow that to inform and be applied on top of what's currently happening. But when we're talking about rotating the ship or doing movement or things like that, we may want to skip the physics simulation itself. Because there's a lot of things involved in flight simulator mechanics when you're even looking on a 2D playing field of thrusters, right? Like you don't want to apply maximum force immediately. That's not going to actually get the desired result that a user is, you know, expecting. So your thrusters going to have to ramp over time. You're going to have to modulate that. You're going to have to automatically, you know, handle edge cases about rotation or movement where the user is kind of out of control of the ship, right? Like those are all things to consider. And we can just kind of throw them out the window if we just fake it. I think that would change a lot. Faking it would require build changes. Well, no, it wouldn't. I mean, faking it would just require designing the faker math. And so which is easier, like figuring out where to apply the force on the body. Or writing fake math to figure out how quickly to turn the body based on the fact that the player is pressing the thrust, the turn button. I think that math is pretty simple, like fake math. Like simple, simple equation. You think it's simpler than figuring out like functions that already exist in the physics simulation library? Like it's literally just a matter of figuring out like which three functions to use to get the number of where to apply the force that we've already done the ship math on. Yeah. I mean, the math for rotating stuff is pretty relatively simple. And that's not the issue there, right? It's reusing the box 2D force and all this other stuff, right? It adds a lot more complications. It makes things a lot harder to control. And we can do it, right? We can write code that handles thruster simulation and knows how to ramp each one up and which one to fire when based on user input. But I don't know that we need to. Eric, can you explain again why the apply a torque function isn't appropriate here? Like why do you need to apply it to a specific point on the ship? So I, because I don't know the answer, it seems wrong based on the way that it's working. And so given the fact that it's not behaving in a way that's expected, well, it already appears to be wrong. So I think trying to do the right thing, which is what a thruster would actually do, which is, you know, apply force to a point on the thing seems like the logical thing to do. The only reason I did apply torque was because it was a proof of concept. Like, okay, this will make it turn great success. Like not the right thing to do the right thing to do is apply force. The question is how do we calculate the, you know, this is a documentation problem. Like I've spent more time trying to figure out as a person who doesn't know how to debug C++ what world point means, then like probably it would take Roddy like 10 minutes to actually figure it out since he's worked with this before, you know what I'm saying? Like anytime I do something, it's going to take 15 times longer than it would take somebody that actually knows what they're doing because I'm learning it while I'm figuring it out. Yeah, exactly. Yeah. And in this case, like I think you're actually right on if you're wanting to simulate the whole thing, which normally like I don't write when I write game engine stuff, I do not physics simulate everything. I don't physics simulate movement. I only physics simulate portions of it that need to, you know, seem realistic or interact realistically that are too hard to, you know, write a ton of math for. So in this case, like I'd just be, you know, setting a transform, right? On that, on that rigid body multiple times a frame based on how the rotation should be and then relying on the physics engine just to do collision calculations instead of full movement. But if you want to do full movement, I would say torque is correct. And the way you should be applying it is you should be calculating the distance like rotation wise that's needed, like however many, you know, radians or whatever, and then multiplying that by the torque that you need. And then you should be interpolating that. You should be slurping that essentially between zero torque, maximum torque, and then lowest amount of torque as it's getting to the destination point. If that makes sense. So your torque shouldn't be constant. It should be interpolated between a, you know, smooth ramp from starting to maximum to ending so that you don't overshoot your destination. You have combined many, many, many design tropes into that description. And so in that, if we were actually doing a simulation, you know, if we were using like real rocket thrusters, they would come on fairly close to instantly and you would inevitably end up overshooting because you have inertia and so on and so forth. And so what you're describing is, is gamey, fake physics, even in what sounded like an attempt to describe real physics. Like, well, that's kind of what it is, right? You're simulating things, right? So you're kind of into that rabbit hole of how much do you have to simulate to get this to play nicely, right? And my answer to that almost always is don't because it's a lot of work and it's very time consuming. Unless you're getting a lot of gain from it, there's not necessarily a reason when you could just go in and just set the transform on the body of your frame. I'm super confused because you're talking about designing fake physics being less time consuming than applying a force using the simulation engine that already knows how to do all that. Yes, because it's literally three lines of code versus like... It's the same three lines of code no matter what you're doing. The problem is when you start getting into simulating physics, you have to write additional code to make things behave how a player would expect. It's why if you stick like, you know, a firecracker on, you know, a little paper box or something like that, right? It's not going to be a control mechanism. Yeah, I think the words that you're using to describe what you're trying to say imply to me the exact opposite of what I think you're trying to imply. We're not writing anything to simulate physics. Box2D already does that. So like quite literally, it's the player hit the button. We've already decided via some fake back of the envelope math like what the force should be. So just apply the force to the right place on the cylinder and it's going to rotate and it'll keep rotating until they press the other button to make it stop rotating. Can I take a shot? That seems very, very... Yeah, go for it, Michael. I think my take on what Derek was saying is that using the physics simulation, he wasn't saying that's hard, that's easy, but then making it playable on top of that is hard. Yes. And it is easy. If you want to get to a playable state, it's easier to skip the physics engine for the things that you can skip it for. And just apply a transform directly. And an example that I've done is gravity seems like a fun game mechanic. But it's actually not fun and most games have really, really slow gravity. And if you see a game that actually applies real gravity, it looks fake because it's so unnatural. Like things just go, bam, they hit the ground so hard and so fast. Or if it's a space game, you get sucked into the black hole way faster than you want to. And so it just feels better in the game to use a basic acceleration, like a much slower acceleration toward a point than true gravity. Yeah, there's a ton of examples like that where real physics would not make for fun, like a fun play experience. And I mean, even the games that we've written are like the flying games that we've written, like Tracer and Zorbio, there's zero physics in either of those games. It's all done just by vector math. And the vector math is pretty simple. You're going to move forward this many, like if you're pressing forward or left or right, you're going to just use the vector to turn it one way or the other, just basically simulating movement. But the thing that it gives you is total control of how you would want your user experience to be without having to work around all the physics, the rigidness of true physics. Right. The question that I'm talking about here is why does applying torque not make easy turning? And why doesn't it feel right in the game? And the answer to that is because you have to do math in between to make that apply in the way you think it would work. Like there's a gap between what you would expect to see in the game versus how physics actually work. And so you have to write the code to do that translation for the user. No, I think it's actually that applied torque doesn't do in real physics land, what we think it's doing, which is why it behaves weird. It's like opening the door from the hinge versus opening the door from the doorknob. Like apply torque is opening the door from the hinge and apply force is opening the door from the doorknob, but we don't actually know where the doorknob is to apply the force. Yeah. And you do need to multiply by inertia to make that make sense, right? Like I think that's something that was missing from your code is multiplying the angular velocity by the inertia to get closer to like what you would expect it to act like. If you say so, I feel like we've spent more time debating on why apply torque is is or is not the right thing to do versus like we could have written the three lines of code that actually did the right thing or whatever. We can write a fake physics engine, but which one of the five of us is going to do that and by when? Oh, it's not a big it's not a physics would you rather would you rather have something that's like accurately simulated and not as much fun and finished or something that's like theoretically amazingly fun, but never actually gets done. Well, no, it's not it's not writing. I don't think we're talking about writing a physics engine. It's like writing your your gameplay to kind of feel like you're in space, but it's not like true physics or like it could be as simple as you know, you putting your putting your velocity is a function of the direction that you place times the speed like you know, like whatever that speed is the direction is you start going in that direction like there's a super simple mathematical equation, but it's not physics. It's just movement. Yeah, I mean, it's it's the difference between needing to write. We're just talking about here Eric is if you're applying the torque, right, you have to calculate your current angle or your desired angle and get the rotation from that multiplied by the inertia, right, with against the velocity and then apply that torque and then assumably, right, you might have to tweak that a little bit by getting something closer to what a user would expect versus if you're not doing the physics thing, right, all you're doing is using the set transform. That's one line of code. Like whatever the angle is that you want to rotate the ship to at that particular frame, you just set transform and there's no physics happening. That's all we're talking about is the difference between those two. And when you're talking about like writing code and making it work, does that make sense? Right. But you it does, but you're leaving out the part where you figure out where you want the ship to end up, which is code also and or math. And so again, this is all we have to do that either way. I'm more than happy to make it do whatever you want it to do, but somebody's got to write that. Yeah, make sense. It's gonna be Yeah, that's the question to write. Whoever's doing that, whoever's doing the work gets to decide. I think that's a fair statement. Yeah. And so right now, like I'm the one who's been doing most of the work for this stuff. So if I, you know, I, I don't know how to do any of what you just described, but I can read documentation. And this is documented. So like, I can make something that's not fun and doesn't play well, but works. And to be fair, in most doesn't actually write code, not quite there, right? It mostly works like it's most of the way to where you need it to be. But there's some discrepancy involved in what's happening that makes it not quite right at the moment. Yeah. Right. And I mean, I can apply torque. Well, again, now, now we're back in a circle to, I don't think apply torque is the right tool to be using for the job. I think we should be applying the force at the end of the unit, right, which brings us back to, you know, I just didn't get enough time to debug how to actually calculate where the I think that's the answer right there. You didn't have enough time to debug the problem. So we don't know what the answer is based on the current structure and design of what you've implemented. Right. So maybe with five minutes or maybe two hours, who knows, you'd be able to identify or I would be able to identify how to fix it to do to act as we expect and would be correct according to like what we're visually seeing. Right. But at the end of the day, that might not still be fun. That's a completely independent question from making it work relatively correctly. Right. Yeah. So true. And so I think Derek's point was spot on in that like physically simulating stuff does take some effort. And is not necessarily doesn't directly equate to any fun factor. Right. But I also agree with Eric in that we're saying the code we have here that he wrote is pretty close to working. And with a little bit of extra effort could be physically accurate, if not necessarily fun. And I think the small window of taking what we have and making it work is the next step. Yep. Totally. Yeah. Like I can think of it as another example. Like there's of a really good example. I can think of a mixture of real physics and fake physics. Making for a really fun game experience is this sailing game that I'm playing like where it's a first person game where you're on on a boat. Right. And there's a really cool physics simulation with the waves and like the boat and the boat has mass and stuff and it moves, you know, it stops slowly and stuff. But if you drop the sails and you're against the wind, the boat's still going to move forward because it wouldn't be fun if the boat just sat there. Like in real physics, like that boat wouldn't move would do nothing. But in a game, you're going to drop the sails you want to the player is going to want to like start to move. So that's like, so they have to fake that. Right. That's obviously a game mechanic. They faked around the real physics engine where anytime your sails are down, you're moving forward. Doesn't matter what way of the wind is coming. Like, and so that's, that's just an example of like, you know, fake physics, making for a fun experience. Yeah, you're talking about like CFDs here. CFDs. Yeah. Yeah. So it's fuzzy because it's been a long time since I've watched the presentation, but I'm pretty sure they actually do very little physics and it's actually a bunch of really cool immersion tricks. Like, essentially, they're just calculating like an average vector based on the wave input, right? And that's just a sine wave. They don't even like use the actual geometry. So like what's going on is just like an approximation of it where they do the physics. Yeah, when they do the physics calculation is like only for collisions pretty much. And then a couple of places to like derive a reasonable ish number to put into the non physics driven simulation. So design and development is always like this really weird mix of like, Oh, God, you know, what is the right approach to this? And there wasn't always a correct answer to it. Yeah, yeah. It's I think it's a great example of showing like both, both, you know, using both fake and in real physics for making a really fun game experience. Like, it's a quite fun game. I like it. But it definitely does have physics though. And that's with collisions, because sometimes if you bump into something the wrong way, the physics engine freaks out and the boat goes flying like 100 feet in the air and spins through the sky. Yeah, yeah. I think like this is a pretty small small problem. We kind of got into more just like your theory and general discussion. But I think for like turning the ship, I think what it comes down to simply is the amount of time and effort expended on the problem. Like Eric has spent the expended a bunch of time on it. And like you might guess, I haven't expended any in this round. And I think a little bit of time and attention to the problem would help solve it. I mean, the hackiest solution would be, let me look at the numbers we had written down. I don't actually remember, Derek, what you like, how fast you said you wanted the ship to basically be able to turn around. And so the hackiest way to do that is to just take that number and then divide by the game tick rate. And then if the thruster's on in whatever direction it is, just move it by that many degrees. And then like there's no inertia. It's just, you know. Yeah. And Box2D does like that set transform function is essentially the way to do that in Box2D, right? You provide the position vector, which is just going to be the same as always, right? And then you just increment the angle by that number every time. And that's in radians. So did we have some rough notes? Refresh my memory. Did we have some rough notes? Because I know Derek, you had some specific ideas laid out in our previous discussion over as to how this works. Did we have rough notes for reference? Um, it did take notes somewhere. Okay. I don't have the rotation number written down or something like that for reference. I mean, even if they're just. So looking at looking at set transform, we're going to have the exact same problem, which is set the position of the origin and rotation position is the world position of the body's local origin. So what is that? It's literally the same problem as the, um, the last problem, which was like figuring out. You just call body, get position, right? Yeah. You don't, you don't even need to calculate it. You just ask the body for its current position because you're not changing its position. You're just changing the angle. Get the world body origin position, set the world position of the body's origin. Okay. So then set transform the position would just be get position, like set it to its own position. Exactly. And the rough number I had was 180 calculated number. Yeah. We had a 180 degrees in four seconds. Okay. I just made a rough note. And what's the, what's the server, the theoretical server tick rate? Because we have the sleep. So should it be influenced by the sleep cycle then? No, because the feel, this is defining the feel, right? The ship should turn 180 degrees in four seconds when you're running the game. So, but how do you know, how do you know how long four seconds is? According to, if we're using the simulation, then you'd say four seconds of simulated time. But what you get as a frame rate, maybe completely independent of what you've calculated underneath the hood. Sorry, I don't really understand the answer. So how, because often it's the case, if you're saying 180 degrees in, sorry, go ahead. So for any given game that actually uses some sort of physics simulation, or whether that's like a box of, I do not use the word box, a collection of formula that you've derived yourself for how you would like the rotation to feel. It's quite often the case that your physics simulation runs at a completely different rate than your display, right? And what you're drawing to the screen and how often you're taking input. Sure. Right. So in this case, let's just say that this is specifically 180 degrees in four seconds of calculated time with regards to either the physics simulation or the non-physics simulation of position and movement. And if you have a client which displays that in 15 frames per second, you're still only getting 60 frames of that rotation in that change from its initial rotation, 280 degrees in the difference. Did I not push those changes? I think they're still on the branch. I had to grab the branch to look. They're not. I thought you had merged it to master. Did I not? I merged the PR. No, that's right. You didn't send PR. So I did the two PRs which were the lead command on the server side and the logging and the UUID update, whatever it was. Yeah. So like I understood what you said this second time around, I still don't understand how I would calculate. What we were talking about the game with, based upon the coordinate systems. I mean, can you base that off? I don't know. The rotation. Can you know how long each server tick is? On the server side, you would, yeah. I mean, technically on the client side, you could perform the client too. Right. The server side is the master. Well, but the server side is what's doing the rotation. Right. So since you know how long each server tick is and 20 times per second and you want to move 180 degrees in four seconds, you know, you can use, that's just algebra. Like figure out what you have enough variables to figure out how much to move it in each tick. And the server can easily inform the client of what the tick rate is. Yeah. Well, the client doesn't care what the tick rate is because the server is what's rotating the object and just telling the client what the new angle is. Yeah. That's fair. Yeah. So that's, that's how I would say doing that. So much math involved in GameDev. There is a lot of math involved in GameDev. It's pretty much unavoidable. Yeah. And I would also say like somehow we managed to spend an hour and a half talking about nothing other than rotating the ship. Which is really fast for GameDev, honestly. Normally that's like a week long discussion. God, no wonder games never get developed. Go ahead, Ron, Jared. Yeah. Okay. I would say as much of this kind of like hard coded values we should put into the config variables as possible. Like four seconds, like turn, turn, I would call that turn rate, right? Let's put turn rate into a variable. We can say like what if we wanted to turn faster? What if we have, yeah, that's fine. I mean, eventually it'll get there. Yeah. So no, I mean, I think we should just start doing that, right? But we should just start doing that as a habit when we're, when we're just putting, we're hacking on the server and we're going to put like a four second turn rate. Like don't hard code it. Just start out with a conveyor variable. It's so easy to do. Just put it in there. Yeah. No, makes sense. Yeah. Well, it's not that easy because you'd have to add it as a command line variable and a config and you have to edit the config instance to actually pull in the value and so on and so forth. So it's definitely, it's not hard, but it's non-trivial. There's a lot of steps. We should try to, maybe we can make that a bit simpler process. It'd be nice if there was some sort of like reflection in C++ or something where you could just add it to a constant, like a struct, constant struct or something. And then it just shows up everywhere else. So we don't have to add these, this set of if statements that we have here. Yeah. I mean, this is more, it's more even than the set of if statements. It's like a bunch of stuff. I know that it's a bunch of plumbing to get the data from the config to where it needs to be, right? Yeah. I mean, there are C++ reflection libraries and headers and stuff you can get out there, although from a native guys point of view, reflection is very faux pas because it's a performance killer, right? But in this case, you know, ultimately, I think when we are more interested in the speed of development rather than the ultimate frames per second. And we're in kind of a weird situation too where honestly, I couldn't give you an answer if it would be faster to write all this code in C++ and then, you know, add client side prediction later. And that'll, you know, we'll just rely on like low latency to the server to keep things functional because this is a demo, or if it would be better to look at something like running JavaScript on the server for only specifically the simulation stuff so we can write code once and then deploy it to both client and server. But I'm thinking honestly, just for demo purposes, we don't need to add that much client prediction, right? It's just, yeah, there's lag, there's latency, right? We're just like, Hey, this is a demo. We didn't write any client side prediction because that would take a month to do. Yeah. Yeah, right. Exactly. Yeah. No, I agree with that. That's really complicated too. Can be building a building a game three hours a week at the time. Yeah. A multiplayer scalable game. Yeah, three hours a week at a time. All right. Anybody got any parting thoughts for the last 40 seconds of today? Oh, geez. Lots of work to do, I think is the parting thought. I think, I think the more we discuss, the more we realize, of course, that there's a lot of work because into these things outside of just our core knowledge area of infrastructure and getting things deployed on OpenShift, but actually building something that's valuable to deploy on OpenShift to begin with is a time consuming task in itself. Absolutely. Well, and we're, and we're like not even remotely close to there, right? That's right. Do not underestimate what it takes to develop a game. Yeah. At least the client server. We can game jam them. Anyone can do it in one weekend. Right. But they don't necessarily do multiplayer games in a weekend. I know. Well, I do. We did. Well, you're special. All right, dudes. Well, thanks for joining today. Oh, man. Has the stream been working the whole time? I hope it has been. Yeah. I've had it up. All right. All right. Cool. Okay. It's the other one. All right. See you next month. Cheers. Bye.