Open crazy2be opened 13 years ago
Networking sounds like a great :). Do you have any thoughts on multiplayer gameplay? Do we want a co-op mode where multiple players can build on the same tower? Versus mode where players build towers competitively? And we definitely need achievements :)
IMHO TCP is the right choice, since it guarantees packet transmission which UDP doesn't. I guess we're going to detect differences in the game state and transmit them (delta compression), which requires that all changes are transferred correctly.
I assume that the value for a key is always of the same type. So my suggestion for the keys:
byte
s) as value and the key name string
as key.This would make it possible to have key names in the networking code, but transmit only bytes as keys in the actual packets. Except for the first use of a key of course, which also contains the key name and type.
I like the idea of multiple keys in the packet!
A field I would add to the packet is something like a sequence number. A number which the sender increases by 1 for each packet. Due to the complexity of the internet I think it is possible (even for TCP) for one packet to arrive faster at the destination than another packet that was earlier sent. With a sequence indicator, the recipient may postpone the processing of any packets that arrive earlier than their predecessors. Otherwise this would mess up delta compression.
See the other issue for how players would interact :).
Transmitting deltas is one possibility, it depends on how we want to design the server architecture. However, in a central server-based design, you'd probably have something more like this:
I like your idea of transmitting key/type pairs at the start, then keeping them in memory. This should provided the best of both worlds at the cost of a bit of additional complexity in the protocol implementations. Server would have to keep track of this map per-client.
If we use TCP
, a sequence number is included in the protocol for us (see http://en.wikipedia.org/wiki/Transmission_Control_Protocol#TCP_segment_structure). TCP
guarantees that packets will arrive in the proper order, as long as the underlying connection is still functional (and even then, they will not arrive at all, rather than out-of-order). However, adding a timestamp to each packet could be beneficial, as it would allow client and server to synchronize their time offsets at the start, keeping track of lag afterwards.
Sounds great. I wasn't aware of TCP keeping track of the order of packets, you never stop learning :).
I like your approach on how the client/server interact. I'd say we move the simulation-relevant stuff to the server, and the animation stuff to the client. This would allow the server to handle the stuff relevant for gameplay and eventually winning the game, and the client to present the simulation situation in a nice way.
Take elevators for example: They use a bunch of formulae I made to calculate the elevator movement. The overall time of the journey is known beforehand, and the animation is simply filled in. Therefore the server might only calculate the overall time required for the elevator ride, as that's the only thing relevant for the simulation. The clients however could use the more detailed formulae to show the acceleration, const. speed and deceleration phases accordingly.
I think moving the entire animation stuff to the server would be overkill for the network connection, with potentially 15'000 inhabitants being animated and transmitted over the network.
I like this entire client/server split idea. It requires some detailed rethinking of the entire engine, which will make the game much more modular and easier to extend for the deluxe version :)
I was starting to implement this, but i'm not sure about having the key/value IDs being sent with each packet. Personally, I think that a KEYIDS packet that contains this information would be best, as it allows you to simplify the normal packet structure. Without this separate packet, you either have to identify in each field if you are defining the key type there, like this:
0x43 // ID
0x003F // Length
0x00 0x0010 [string "Hello"] // Key with already defined type-keyname ID
0x01 ??? ??? // Key without already defined type-keyname ID
as opposed to with a seperate packet:
0x43 // ID
0x003F // Length
0x0010 // Key ID for key 1
... // Value
your seperate packet looks something like this:
0x04 // ID (KEYIDS packet)
0x0045 // Length (of packet)
0xFFFF // Special ID: KEYID
[string] // Key name
0x0002 // Key ID
0x01 // Key Type
I was also going to suggest that we could put a length on each of the key-value pairs, but reflecting on that it seems silly. If we have so many key-value pairs that it matters to verify correct parsing, we're doing something wrong.
Go server is getting closer to actually being able to read and write packets from a connection, as this is probably the most important part for getting the client to talk to the server. Internal representation and interaction of items comes later, but there will be plenty of time for writing all that code as the client matures.
I've been thinking about this a bit more, and i'm wondering if the string-based keys are really all that useful. Usually, what the packet data means can be inferred from the code, as in this example:
No Keys:
packet := conn.NextPacket()
x := packet.ReadByte()
y := packet.ReadByte()
roomid := packet.ReadInt32()
With keys:
packet := conn.NextPacket()
x := packet.FindByte("x")
y := packet.FindByte("y")
roomid := packet.FindInt32("roomid")
In C++, the difference is even more significant (example only, may have syntax errors as I haven't written C++ in a while)
Packet packet = conn.NextPacket()
char x, y;
int roomid;
packet >> x >> y >> roomid;
vs
Packet packet = conn.NextPacket()
char x, y;
int roomid;
x = packet.FindByte("x");
y = packet.FindByte("y");
roomid = packet.FindByte("roomid");
In additional to the increased complexity of the API, the string keys would also increase the complexity of the internal implementation, and potentially make it slower by adding the additional overhead of string creation and a hashmap.
I imagine any concerns about having the order of data accidentally vary between packets can be addressed with relative ease given a little planning, such as having a standard convention for order when both an X and Y coordinate are required. Other than that, the other major cause for errors would likely be reading less than the full length of the packet, or attempting to read past the end of the packet. I'm not sure how to rectify potential issues with reading less than required, but reading more should be easy to detect and handle.
Oh, and we might want to borrow a cool idea from the websocket implementation: make the length of the length part of the header variable, yielding packets of effectively limitless size. See here: http://tools.ietf.org/html/draft-hixie-thewebsocketprotocol-76#section-4.2
Yay nice one, sounds good.
What protocol is going to be used for networking? I've come up with a rough draft/idea at https://github.com/fabianschuiki/OpenSkyscraper/wiki/NetworkProtocol, based on the Minecraft protocol with a few modifications to correct what I understand to be the biggest pitfalls. There's some discussion questions there that we could discuss here, namely:
(you should read the page first, or else these questions don't make much sense)
I wasn't sure if an issue was the best place to bring this up, but i'm itching to get started on a server. Due to the lack of networking, however, I am unable to. Thus, I would consider it an issue :).