How Do I Get My OpenGL Context In NetworkListener Class?

Using Slick2D and Kryonet:

Lets say a server sends a (TCP) packet to a client with X and Y coordinates. The client receives this packet in the NetworkListener and the goal is to call drawString(“hihi”,x,y) respectively. The issue clearly is: there is not an OpenGL context in this thread to make this function call happen.

For your entertainment, I have tried the following with no success!

public class ClientStart extends StateBasedGame {

    /*  lots of networking code */

    public static void main(String[] args) {
    /*  code */
    }
}
public class NetworkListener extends Listener {
    ClientStart client;  // assume this has been initialized properly to the main class
    
    /*  more missing code */

    public void received(Connection con, Object obj) {

    client.getContainer().getGraphics().drawString("hihi",x,y);  // this fails.

    }
}

How should the client go about ‘finding’ the current GameState (which contains the OpenGL context), or better yet, how should one attack this problem?

Thank you :slight_smile:

I don’t remember much about slick2d from the time I once used it… but if I learned anything from game dev it is that things that are drawn are called in a loop. They are drawn every frame. Since there is no render loop, it gets drawn for one frame then it goes bye bye. Also consider moving on from slick2d to libgdx.

[EDIT] i am not saying to implement a loop in the listener class but you need to do something here

Yeah… I just don’t know what to do ???

I don’t know any opengl, but shouldn’t the rendering (and opengl context) be on the client side?

This is code from the Network Listener on the client side, hence ClientStart class.

I know nothing of Slick2D and little about networking, but this seems a bit of an odd design to me.

In my opinion, your network listener should not be involved in rendering. Instead, I’d be giving your network listener a reference to the class that is directly responsible for rendering and maintaining the context. Your network listener then passes the required information to this class, which in your case is the x and y pos. This other class is then responsible for handling the rendering of the text. So essentially the network listener just feeds information to the right place; it doesn’t make any rendering calls itself.

Given that this is likely occuring in a multi-threaded environment, you may need to think a little about how you will accomplish this. I.e. does the network listener directly set variables on the rendering class? Does it request or queue a job with the rendering class? etc.

This shouldn’t happen in the client class. Graphics should be handled in the graphics classes, networking should be handled in the networking classes. Its as simple as that, there’s no reason for your client to have control over the graphics. Its bad design.

Exactly! I was trying to illustrate the task I was attempting to accomplish, not vouch the technique which I deemed fallible.

Let me rephrase my conflict: I don’t know how to send two integers (of which I received via a Packet in my NetworkListener received() method) to my current State, aka my Graphics rendering section of my code.

Thank you!

Well, that’s just a basic programming issue that I think you need to work out. Maybe pass in your graphics instance? There are so many ways to do this, it has nothing to do with networking or graphics at all.

What I mean is, the client renders what is given to it, so the client technically controls rendering but the server tells the client what to render.

To each his/her own, but I personally like keeping functions in their own classes. In my mind, networking should only do networking. Graphics should only handle graphics. I believe the client should receive packets, decode them and send the information along into the program as needed. If it so happens the graphics class takes some of the data, then the graphics class can process that data. I just think it’s messy to have rendering code everywhere. But some people might not agree!

Edit:
Completely missed what you were saying there Jimmt, sorry. My whole spiel above doesn’t really apply…

Well, just reiterating what I said: hold a reference to your current State in the NetworkListener. Then update the required state/variables within the State when you receive a new message.

In its simplest form, if your NetworkListener had a reference (direct or indirect) to the current state: ‘State state’, and your State had two variables named int x, int y, then instead of calling:

client.getContainer().getGraphics().drawString("hihi",x,y);

in your received() method, you could then do something like:


public void received(things here) {
      state.x = x;
      state.y = y;
}

Your state object then handles rendering as per normal next time through the game loop, but with the updated variables. But as mentioned, you’ll need to be aware of the joys of multi-threading, so just use this as a loose example.

THANK YOU. Sometimes I just stare at code for too long and forget extremely simple things.

Also consider something like a render queue:

In client networking:


public void received(...) {
      RenderObject r = new RenderObject(x, y, /*...*/); //or use a factory, etc.
      client.renderQueue.add(r); //push a new work item on the queue
}

and in the render loop:


for(RenderObject r: renderQueue)
      context.render(r.x, r.y, /*...*/);

This will allow: safe multithreading, multiple things being sent between the theads, etc.
I would use some kind of synchronizedList or an ArrayBlockingQueue (probably the ABQ).
Modify that for loop if you need to remove items while iterating, but remember thread safety!