haxball / haxball-issues

113 stars 42 forks source link

onplayerballTOUCH event request #1784

Open kingjasko opened 1 year ago

kingjasko commented 1 year ago

Real soccer is one of the most popular maps in haxball, we have a decent bot/referee system in place already, but it's not the most accurate due to having a hard time determining who touched the ball last, best we can do is check if a player is within x pixels from the ball, if we try to make it more accurate, the bot will not detect a touch at all and if we try to make it more reliable, it might detect a touch that wasn't a touch.

Considering we already have the onplayerballkick event, why cant we also get onplayerballtouch in the future?

https://i.imgur.com/hKBwsCN.mp4 here's a clear example of a mistake happening, clearly ants touched the ball last, but the bot still detects it like he either didn't touch it or that the other player touched it last

wxyz-abcd commented 1 year ago

In the meantime, you can use my API that also has onCollisionDiscVsDisc, onCollisionDiscVsSegment and onCollisionDiscVsPlane callbacks that gets the job done. :)

kingjasko commented 1 year ago

In the meantime, you can use my API that also has onCollisionDiscVsDisc, onCollisionDiscVsSegment and onCollisionDiscVsPlane callbacks that gets the job done. :)

what method did you use for calculating that?

wxyz-abcd commented 1 year ago

basro already calculates all collisions. why would i calculate anything again? i found where it happens in the code and created some callbacks there. :)

kingjasko commented 1 year ago

apparently the real soccer code is using the same collisions calculation as basro for determining last touch, but we're still encountering many instances of mistakes, here's another one from yesterday https://i.imgur.com/YEKFeky.mp4 as well as the one i sent initially https://i.imgur.com/hKBwsCN.mp4

here's the snippet of the code : https://prnt.sc/OHD8GZ-7bEAp

wxyz-abcd commented 1 year ago

The code seems to be correct, except that it could be optimized a lot. This code is probably running inside onGameTick, is it not? Also running it in each tick is also a burden to the CPU, especially after basro already did the same thing. maybe not a lot but still. just saying. :)

I just re-checked basro's engine code. First onGameTick callback runs. Then the players that can kick the ball discs, kick the ball discs. (The distance threshold value there is 4 units.) Then comes all the collision checks. The collision checks also alter both the discs' position and speed. But I haven't found any evidence that the code you pasted should fail at any circumstance, except that basro uses direct comparison and not adding 0.01 to distance while calculating, and it is in fact normally a better to do thing; but here, maybe unnecessary.

The real problem with basro's API is that he is not using the extrapolated version of the room state that he calculates and sends to the renderer object. Instead, he ("probably", because I didn't check that.) uses the original room state object that is stored to also track the synchronization status of players. That was the most important point, and probably the real reason of what you are experiencing; because I experienced the same thing when I started this API, 5 months ago. What you are seeing in the canvas is the extrapolated state of the game, not the actual one. Even if you set the extrapolation to 0 or -100, it still extrapolates to some extent. I hope this cleared your mind now, and I hope I expressed clear enough why you should use my API instead. :)

In fact, on second thought; you might still have problems even with my API, because of the way that extrapolation works. basro's code first copies the original state and runs the physics engine for several times on that copied state object. How many times it will run (as far as I understood the engine codes) depends on the performance of the computer, because there is only a timer control there. Therefore, the simulation will run for different number of cycles at different times or on different computers, and that is because synchronization is done only by a timestamp-difference-to-frame-number-difference conversion mechanism. So, let's say your host room is at frame 100 at a given time. it will extrapolate the room state (usually around 7 times with an extrapolation setting of '0') and render the game using the 7-times-extrapolated state (The 107th frame). My API instantly stores this extrapolated state as soon as it is calculated so that you can get and use it directly whenever you want. The problem is that the 107th frame is not a real frame, but an extrapolated frame. It is extrapolated using the current input values of the players. If one input changes at 101th frame, the previously-calculated 107th frame will not be valid any more. But you used that value already in the previous frame. BUT this happens very rarely, and probably not a very big issue, because there is often not a very huge difference between those coordinates, unless some discs have big speed values, and also it usually happens in the middle, say 103th or 104th frame so the frame difference usually is not that high, and hence neither the difference.

In summary, it would be great to get the "real" position/speed values of discs, and basro in fact sends them, but they are not what we see in the canvas... If you want to get exactly what you see in the canvas, you will have to use my API. (or implement it yourself, if you can) Even that might sometimes not work 100% correct, but it's the best we can do under these circumstances. :)

P.S. On third thought; as you said, basro's API also has an onPlayerBallKick callback. If it always works correctly, then maybe his API is using the extrapolated state only when basro needs it, and not when we need it. :)