Game Development Community

Where is the break point between Client and Server?

by Demolishun · in Torque Game Engine · 11/28/2004 (8:15 pm) · 21 replies

This question is really bugging me. I have read through several posts and the chapters that cover this in "3D Game Programming All In One". When does the program decide that it is a client or server (or both) and where does the code, variables, etc go to be on the client or server? So far I cannot tell. One thing I want to do is to make additional variables for the "player" object. I know datablocks are on the server and transferred to the client. However, these variables will be specific to each "player". If I add a variable in script to like this:

...
%player.someval = 10;
...

Where is this located, on the server or client? How do I make sure it is on the server or client? For HUD display vs attribute for example.

Thanks,
Frank

About the author

I love programming, I love programming things that go click, whirr, boom. For organized T3D Links visit: http://demolishun.com/?page_id=67

Page «Previous 1 2
#1
11/28/2004 (8:23 pm)
Basically, how its broken down is this:

stuff for the GUI/HUDs- on client

Everything else- on Server

If the script under Client in the folder heirarchy then the client knows about it, if its under Server then the server knows about it... Both are there because someone can run as either a client or server.

HUD and other information is transmitted w/ msgtoclient (the call is something like that).
#2
11/29/2004 (8:29 am)
There also seems to be a data folder with the client and server folders. Is this folder client or server side? Or both?

I was thinking of adding db support and would like to keep models etc in a embedded db client side to cut down on server/client communication and to speed up loading times (cut filesystem overhead)

If there's also a way to cache or keep a local (client side) copy of datablocks etc (with version checking of course) I'd like to do that to cut back on server/client communication once again.

Anyone got any clues?

Oh, and that book is great. I'm glad I bought it.
Probably cut down the time needed to get to know Torque by months!
#3
11/30/2004 (7:28 pm)
Stephen,
Thanks for the reply, but I am not sure it answers my question. Here are some more concise questions:
At what point in execution does the server realize it is a server and the client it is a client or both? What function causes the engine to say hey, I have to rely on this server over the internet rather than the server in myself? If I write code server side in script and only execute that code from server script I can assume it is server side only? I am trying to understand the logical seperation and how it compares to the obvious physical directory situation.

Rakessh,
That book certainly does rock! I thought at first it was a help another dude in the community out and it will be a great resource kind of purchase. I found the explanations for what code does are extremely enlightening. It says not just how, but why. Many resources show how, but not all say why.

Thanks,
Frank
#4
12/03/2004 (4:29 am)
@Frank: First up, ignore the directories. You could rearrange all the files into a directory called "half-life" but it wouldn't mean anything to the engine. It's what happens when you generate an object and where the script-callbacks come from that matters.

The TGE does not distinguish between server and client in the scripts, full stop. Remember that, no server-side or client-side script code. It does maintain discreet structures in C++ and places objects in a server or client bucket appropriately though but within the scripts, there's not a distinction. For instance, if you create a variable in the "server" code, you can read this directly in the "client" code. WTF you might say! Well this is something to be careful of because as soon as a client connects via the network (assuming it uses the same code) and obviously not from the same process, it has its own script-state and knows nothing of the variable in question. Variables like this need to be passed via RPC or via C++ objects. Treat the local-client as if it were a remote one so that the same script-code works for both.

Assuming you have a server and client running in the same executable and a remote client, what happens is this:

App starts the server which basically listens on ports for clients to connect. App starts client which essentially connects to the server (running in the same executable), known as a local client. When a local-client connects this way, it doesn't use the network but takes advantage of a few shortcuts such as passing data directly through memory.

This, of course, wouldn't happen for a remote client via the network and running in another process. The thing to remember about the server+client that's running in the same process is that they both share the same script state.

Let's talk about the life of an object and one of its callback functions "onAdd". This function is executed client-side only. We start the server and create an object called ObjA. The server initialises this and goes into its C++ onAdd function. It checks to see if the object is a server-object (or client e.g. ghost object) and it finds that it's a server object so it doesn't call its "onAdd" function. We then connect (in the same executable) our local client which gets a ghost copy of ObjA. When the ghost copy gets to the client, the client initialises it and hey presto, calls its C++ onAdd function that does the same check but this time finds that it is a ghost (client) object so it does indeed call the script "onAdd" function. From the scripts, you generated an object server-side which only really means you created an object in an executable with a server running which added it to its database and began ghosting it to all clients. We could then say that the "onAdd" is a client-side function but this is implicit because there's no explicit reason why it's not a server-side call, it's just that it's only called from a client and therefore it'll be a ghost object.

When our remote client connects to the server, it also gets the ghost ObjA and the same client-side process takes place.

The difference between the remote client and the local one is that the local client shares the same script state but the remote one is completely seperate. There's no explicit difference in the scripts, it's just having a knowledge of what calls what and what does what.

Confusing? This is probably not the most concise description of the networking but it's all I've got the time for now (I'm at work) ;)

- Melv.
#5
12/03/2004 (5:07 am)
Melv,

Thank you for that great description. I have gotten just far enough into Torque to finally understand what you said. For everyone, it is a slow process to figure out what is happening in the engine, but if you keep at it, it will slowly start to make sense. Oh, and be sure to keep reading the forum, even stuff that doesn't apply to your game will end up helping you.

Thanks.
#6
12/05/2004 (1:01 pm)
Melv,
This made more sense than anything else I have seen. I will have to experiment a bit to see this in action.

Thanks,
Frank
#7
12/05/2004 (1:15 pm)
Guys,

It can be confusing at first. I recommend that you stick to using a seperate server and client so you don't get the "mindlock" of what's the server and what's the client although this can generate debugging/editing fun. hen you're comfortable with what code is redundant on the remote client e.g. server doesn't start, no server mission-load etc, then start messing with them both in the same executable. It also stops you making accidental shortcuts like using a common variable and it forces you to do it the correct way. If you manage to get something from the server, you've done it correct. If you manage to get something from the server using a local client, there's still the possibility that you may not be doing it correctly.

Ever wonder why you can find objects by name using the local client? You try doing that as a remote client! I am of course referring to the C++ side of things but this equally goes for the script stuff.

Don't exclusively develop a project with a local client, remote clients are the ultimate test.

It would be wonderful to have seperate script state machines for server and client but it's not there yet so you need to be careful as there really isn't a distinction.

Don't get hung up on what's "server" and what's "client", just figure out what calls which function and you'll be fine. :)

- Melv.
#8
12/07/2004 (1:44 pm)
Your posts are super informative Melv. Thanks for taking the time to write them. If you've got more time, I've got some questions:

1. Is running a dedicated server and then connecting to it with a client on the same machine a true test of what it would be like for a remote client? Or do you physically need two machines on a network to simulate this environment? When you say "local client", you mean client and server in the same executable right?

2. If I'm experiencing certain behaviour when I run my game with a single executable (combined server/client), which I consider the correct behaviour. And then I run it with a split server/client and I get different behaviour, what is most likely the culprit? What exactly do local clients know that remote clients do not? What can local clients do that remote clients cannot? In both script and C++.

I love these forums. I wouldn't be able to do anything without them. Thanks all,
Vijay
#9
12/07/2004 (1:55 pm)
Also, I'm looking at the GameBase::scriptOnAdd() function, and it looks like it only gets called on server objects (if !isGhost()), which is the opposite of the example you gave above. Would this function have to be overridden to get onAdd to get called for a client-side object?
#10
12/07/2004 (3:24 pm)
@Vijay: I can answer the second one:

2) If you are getting different behaviour on a dedicated arrangement then you get on a co-executable arrangement, your issue is almost certainly due "poor" (and I use that term loosely, and not intended to be an insult) techniques in your scripts, and possibly code.

In a co-executable (server and client running in same process), you can get away with a lot of things that aren't totally correct, like accessing the server's copy of objects, instead of requesting changes of the server's objects, etc. While when it comes right down to it it doesn't much matter in a single player game, if you are just using a co-executable for dev purposes and plan on eventually using a dedicated environment for future development/release, you are setting yourself up for some very difficult issues.

For example, a script run on a client should -only- ever access the ghosted object that came from the server, never the object directly as it resides on the server. In a co-executable setup, you can however see those objects very easily, and it can be transparent to the developer/script writer that you are doing things you shouldn't. Developing in a dedicated environment from the start simply won't allow you to do things like I mentioned above, because the objects aren't there in the first place. Instead, you have to send the server a request (commandToServer ) with your local ghost ID of the object, the server then resolves that ghost object to the real object in the server environment, processes the change as appropriate, and then the underlying net code automatically sends the updates as appropriate to other clients that have the object scoped.

Another "poor" technique that happens in a co-located environment is dependence on being able to grab an object's datablock from any context (specifically, client side scripts). In the dedicated environment, TGE is much more strict about how you can reference the datablock of an object, to enforce authoritative control of the object (I assume). Specifically, %objectID.getDataBlock().getName(); works fine and dandy in a client script in a co-executable environment, but does not work in a dedicated environment.

I'm by no means a TGE guru, but our project went dedicated environment from the beginning, and it's forced us to be very cognizant of how the relationship between client/server works, and has by example helped show us how to avoid a majority of the possible client hacks and cheats a player could use if you don't do strict server authoritative object control. These lessons would have been totally lost on us had we spent several months working in a co-executable environment, and then tried to port our code to a dedicated setup.
#11
12/07/2004 (6:04 pm)
Thanks for the explanations Stephen. I've been spending a lot of time looking through code for the answers to my problems. What you're saying leads me to believe that the solution may be in the scripts. I'll switch my attention over to them for a while.
#12
12/07/2004 (6:35 pm)
(Just read your other post, trying to think what could be causing it)--well, unless you are doing something really funky, I don't think scripts would cause this type of behaviour, especially since most, if not all, of what you're doing is engine driven.

You've had lag issues before with something pretty much totally unrelated, so all I can really think of is either some unusual hardware/network configuration, or possibly you're missing something related to setting the control object back and forth (although I have no idea what).

I still tend to fall back on issues with interpolating your ticks...I know that the advCamera resource did little to no self-interpolation, since it was designed to be tied to the player for most of it's operations, and therefore didn't need separate interpolation.

Sorry I can't help more :(
#13
12/07/2004 (7:05 pm)
Thanks for keeping on this Stephen. My other lag issues were related to trying to do stuff with the RTS engine. I've since fallen back to the FPS engine, and I'm pulling in the components I need from the RTS engine, so that fixed that problem.

As far as interpolation, when my version of the advanced camera is not tracking a player, it does its own interpolation, which works fine. When it's tracking a player, it relies on the player interpolation. In this case, the camera still looks pretty smooth, it's just the player that jumps around. Which is strange, because technically the camera should be jumping around with the player. That may be a clue that I need to think about more.

Don't be sorry, you're actually helping a lot. Just bouncing ideas is very useful.
#14
12/07/2004 (8:58 pm)
Are you sure it's tracking the renderTransform, _and_ that it's not storing old data from previous ticks?
#15
12/07/2004 (10:01 pm)
I am sure it's tracking the render transform. But it does look like it's hopping back to old tick data. What could cause it to store old data from previous ticks?
#16
12/08/2004 (9:04 am)
Well, it might be getting the position of the object before the object has been updated... really that's a question best answered by some close reading of the code. :)
#17
12/08/2004 (9:27 am)
If I call ProcessAfter(thePlayerObject) from my camera object initially during setup, then it should be getting processed after the player, right? Is there anything else I need to do to ensure that the position of the player is being updated before I grab it?

Thanks.
#18
12/08/2004 (9:29 am)
This kind of relates to another question I had. In the Player's ProcessTick, if the Player has a controlObject (vehicle), then Player calls the controlObject's ProcessTick explicitly from within the Player's own ProcessTick. Won't the vehicle's ProcessTick get called in its own good time? And doesn't this mean that the vehicle is doing a ProcessTick twice for every tick?
#19
12/08/2004 (9:42 am)
Thanks for the tips Melv.
I have 2 machines here and right now I am working through the exercises in "3D Game Programming All In One". The book seems to be following a strict seperation of client and server in the scripts. It does use the proper communication functions between the two even in the early examples.

I think as I develop my own programs I will run a server on one machine and a client on the other. I also have the benefit of one machine being Windows and the other being Linux. I will get cross platform testing to boot.

One thing I thought of while reading through these posts is the client that is in the same executable as the server could be used as a admin for the games. The client could detect if it is in the same program and give the user more options automagically. This could be very usefull for games that require a dungeon master of sorts.

Thanks,
Frank
#20
12/08/2004 (9:48 am)
@Frank: Not a bad idea, except that in a dedicated server, nothing is rendered (guis, playGui, etc) to save on performance. There does exist some basic functionality for admin capabilities via console on a dedicated server that appears to be old Tribes 2 code, but for a real DM interface, you would probably want to implement authorization levels for clients when they login, and allow a specific set of "DM" commands to be issued from the client to the dedicated server to implement what you are looking for...that way, they get both a rendered world, and the authority to do that type of control.
Page «Previous 1 2