Skip to main content
GameDev.net gamedev.net
🔒 Locked

Game Engine - Networking Library

Started by ClickerMonkey Nov 20, 2011 at 3:17 AM 2 replies 2k views
Original Post
ClickerMonkey
ClickerMonkey
I've been working diligently on a 2d and 3d game engine for a couple months now (actually 6 years if you were to count all the times I started to make one and then switched graphics or languages). Currently I've developed the engine in Java utilizing LWJGL. I'll share with you my current networking design (what I have programmed), and I hope you can help me decide how to structure the final pieces!

Terminology:
  1. Attribute: any variable that can be read or written to a buffer and can be interpolated between a start and end value.
  2. Field: has the reference to a specific attribute, the value of the attribute in the last update frame, and the most recent value from the server ( for interpolation )
  3. FieldType: defines several properties of a field, such as how often it gets sent to the server, when it gets sent (on entity creation, deletion, on request, on update, on change)
  4. RemoteEntity: has a remote state and is notified when it has been created, updated, or deleted (remotely and locally).
  5. RemoteType: defines several properties for a remote entity, such as the list of field types, and how often the entity is transmitted.
  6. RemoteState: has a remote type, a reference to the remote entity, and a list of all the fields in the remote entity.
  7. Message: something that's sent across the wire, an entity create, update, deletion, event, RPC, etc. Has a priority, a retry count, among other things.

You may be thinking "a lot of these sound the same" or "are all those classes necessary?" and to that I say yes, here's an example class with angle, center, velocity, and health. I use the static FieldType and RemoteType to avoid repetitious data in memory. I have the class level fields final because "immutability" in Java games is really important to me.



public class Example implements RemoteEntity
{
// the unique ID that says "I'm an Example entity"
public static final short TYPE = 23;

// a generic factory for creating this entity
public static final Factory<RemoteEntity> factory = new Factory<RemoteEntity>() {
public RemoteEntity create() {
return new Example();
}
};

// the set of types that describe a field
private static final FieldType angleType = new FieldType( 2, OnCreation | OnChange ); // sent at most every 2 network updates
private static final FieldType centerType = new FieldType( OnCreation | OnChange | OnDeletion );
private static final FieldType velocityType = new FieldType( OnCreation | OnChange );
private static final FieldType healthType = new FieldType( OnCreation ); // server controlled
// the type that describes the entity
private static final RemoteType remoteType = new RemoteType( TYPE, angleType, centerType, velocityType, healthType );

// the set of attributes
private final Scalarf angle = new Scalarf();
private final Vec2f center = new Vec2f();
private final Vec2f velocity = new Vec2f();
private final Scalari health = new Scalari();

// the state the holds the fields of this instance
private final RemoteState state = new RemoteState( this, remoteType,
// the set of fields that hold the attributes, and their types
new Field<Scalarf>( angle, angleType ),
new Field<Vec2f>( center, centerType ),
new Field<Vec2f>( velocity, velocityType ),
new Field<Scalari>( health, healthType )
);
public Example() { }
public RemoteState getRemoteState() { return state; }
public void onCreate() { }
public void onUpdate() { }
public void onDelete() { }
}


So basically when I do:


Example ex = new Example();
network.create( ex );
... some time later
network.delete( ex );
OR
ex.onDelete() is invoked because server said so.
OR
ex.expire() was invoked by client, notifying "network" to automatically delete it.


It will send the create request to the server, which can deny it, or accept it (and give proper field values if any are wrong). then the server (if accepted) will notify all clients that should care about the entity a creation notification. this also will automatically handle when the entity changes values, to send a proper update message.

Features Done:

  1. Prioritized messages
  2. Retry count on messages (if a message can't be fit in the next payload to be sent, it will be queued)
  3. Optional interpolation of attributes between the last update cycle and the most recently received.
  4. Each attribute has its own "reliability", when its sent ( on create, delete, update, request, changed ), and how often it would be sent (if its sent on update)
  5. Easy integration into existing game (using engine). Nothing additional needs to be done, it can track the attributes of an entity by it self and handle synchronization. Only thing that needs to be done is the server logic.

Todo:
  1. Define the interface for the player view.
  2. Define the interface for the player. It has an id, a view, a set of created entities, a set of currently/previous/maybe interested entities.
  3. Define the interface for the server. It must have all players, an optional set of non-player entities, and must permit the network to accept creation, updating, and deletion. Through various methods this interface must give permission, adjust incorrect information, manage the sets of interested entities for each player, maintain a set of game states for the past 128 (?) updates to properly handle collision detection (so when player A thinks they hit player B, the server can actually test that), and many more things (need help here)

Thoughts:
  • Should I enforce that each entity has a "bound", and I should use this for determining interest (intersects with players view, or the area which surrounds their view - "may be interested in") I could use this then to make the world a huge grid of bounds - essentially an index for quick searching and collision detection. Is there an instance where you think an entity won't have a bound?
    So basically, I was wondering what you think are good designs for the player, player view, and server interfaces. Important note: I also plan on adding continuous world functionality into the networking library - so you can span a world across multiple servers.

    Anything would be well appreciated!
hplus0603
hplus0603

I've been working diligently on a 2d and 3d game engine for a couple months now (actually 6 years if you were to count all the times I started to make one and then switched graphics or languages).


What kinds of games are you going to support with this library? I can think of at least six kinds of game networking structures:

- RTS games, lock-step simulation
- FPS games, high frame rates, optimized for deathmatch
- Action games, medium frame rates, server-side physics
- MMO games, server-side game rules, RPG style
- Virtual Worlds, complex objects, varied gameplay (also mil/sims)
- Turn-based games

How you structure your networking, explicit vs implicit metadata, how interactions are broadcast vs deduced, where you do simulation, which lag compensation approach you use -- they all matter to how the structure is designed.

It sounds to me as if you're targeting MMO games and virtual worlds, perhaps?
enum Bool { True, False, FileNotFound };
ClickerMonkey
ClickerMonkey
[color="#1C2837"]It sounds to me as if you're targeting MMO games and virtual worlds, perhaps?[/quote]
[color="#1C2837"]
[color="#1C2837"]Correct.
[color="#1C2837"]
[color="#1C2837"]
[color="#1C2837"]What kinds of games are you going to support with this library? I can think of at least six kinds of game networking structures[color="#1C2837"]

- RTS games, lock-step simulation

[color="#1C2837"]

- FPS games, high frame rates, optimized for deathmatch

[color="#1C2837"]

- Action games, medium frame rates, server-side physics

[color="#1C2837"]

- MMO games, server-side game rules, RPG style

[color="#1C2837"]

- Virtual Worlds, complex objects, varied gameplay (also mil/sims)

[color="#1C2837"]

- Turn-based games


[color="#1C2837"]

[/quote]


[color="#1C2837"]

I hope to keep it generic enough so that any of these types can be done - with a proper set of interfaces and implementations. My current stall on design exists I assume simply because I've never done networking for a multiplayer game before. My end goal is a little ambitious, but you're right - currently I'm targeting MMO games to get my feet wet (or soaked rather).

hplus0603
hplus0603

[color="#1C2837"]

I hope to keep it generic enough so that any of these types can be done - with a proper set of interfaces and implementations. My current stall on design exists I assume simply because I've never done networking for a multiplayer game before. My end goal is a little ambitious, but you're right - currently I'm targeting MMO games to get my feet wet (or soaked rather).



Sockets are generic enough that all of those kinds can be done. However, each of them use a different kind of data management, and really need a specific communications strategy.

For example, a lock-step RTS generally sends only input commands, plus meta-information for game/turn timing. A FPS game generally sends state updates that are highly compressed not using general data compression encodings, but instead using knowledge of the game state and what data will be transferred (almost entirely only position/velocity/facing information per player). To support a high data rate and high player count, everything about the data packets is implicit; there generally is very little framing information. Meanwhile, a turn based game generally looks a lot more like RPC, or even like state transfer/REST.

It's fine to target MMO/VW games -- that's probably the kind of game that's most "general" in the data representation requirements -- but "game" networking will then *highly* specialize and optimize the network protocol away from that general system when targeting a specific game genre. That's why most RTS games don't use Unreal Engine, for example :-)
enum Bool { True, False, FileNotFound };

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.