Performance Concern Finding way to improve

Hi, I have 10k Vector2 (array) object points in the state. For each 30 tick, I get player position and send near object points. But calculation slows down and causes a delay in the game.

How can I improve that? No need to worry real-time calculation (broadcasting after 2s 3s okay) I just don’t want to cause main-thread delay.

if (tick % tickrate == 0) { // This helps a lot but each tickrate frame my game delayed
    Object.values(state.presences).forEach((p: nkruntime.Presence) => {
      const nearPearls = state.pearls.filter((pearl) => {
        return Math.hypot(state.positions[p.sessionId][0] - pearl[0], state.positions[p.sessionId][1] - pearl[1]) < 100;
      }); // Need to calculate near objects. <<<<<<<< Any idea how to improve that without decreasing object count
      dispatcher.broadcastMessage(OPCODE.ObjectPosition, JSON.stringify(nearPearls), [p]);
    });
  }

@emircanerkul There are a lot of different ways to solve this problem. You have N number of clients moving through the game world with K number of nearby points, and want each client to have a representation of its own and each other client’s nearby points. Is this correct?

Do you want a client or server authoritative game? This affects how we would proceed.

Yes, you’re correct. Also, It will be a server authoritative game.

Have you considered representing your game world as a grid? If you have one, you can perform a breadth-first search from each player (capped to a certain distance) on your authoritative server.

Each point within a certain number of tiles in the grid near the player would be classified as “nearby”.

1 Like

No, It should be fluent as much as possible. My game is 3D but I only work with 2D due to no need z-axis (no jump or fly). With the GRID-based game style, it wouldn’t fluent as I want. Objects should be able to move along the diagonal vector.

I don’t mean that the game needs to be experienced by the user as a grid. I am suggesting you use a grid “under-the-hood” and keep it in memory as a reference for your calculations.

Oh, I understand. But graph-like implementation might be hard for me. I can use caching/preventing broadcast & calculation easily to optimize for non-moving objects. Are there any other suggestions?

Also, I wonder if is there any easy solution/implementation?

Like:

  • Multithreading
  • Workers
  • GPU port for vectorial calculations

I also my other concern is using walletupdate in my matchLoop. I assume it will reach db and may cause performance issues. As i see nk.walletUpdate is not Promise.

Multithreading isn’t an option in the Typescript runtime but you could do it in the GoLang runtime. But that won’t change the fact that unnecessary/inefficient work is being done, even if it isn’t blocking the match loop.

Here are a few other suggestions:

(1) I don’t see why Object.values is necessary.
(2) Instead of iterating through all the presences in a loop, you could trigger only calculate nearby objects when a presence sends a move message.
(3) Instead of iterating through all the pearls, the presence could send a list of candidate pearls that have been collated on the client and then verified by the server.

1 Like
  1. In TS I cant iterate objects. Firstly I need to convert the array. (I can cache and reuse array versions of presences)
  2. Client only sends target location that wants to arrive. All workload on the server, like moving the object.
  3. I don’t want to give all pearl locations to the client. If I do like that client able to see. Only nearby pearls are able to be seen by the client.

I think we’ve discussed a few different approaches but it’s not an exhaustive list. Ultimately it’s up to you what tradeoffs you want to make and I think we’ve covered enough options to give you a good starting point.