Jump to content
  • Advertisement

hplus0603

Moderator
  • Content count

    12167
  • Joined

  • Last visited

  • Days Won

    1

hplus0603 last won the day on April 15

hplus0603 had the most liked content!

Community Reputation

11470 Excellent

7 Followers

About hplus0603

  • Rank
    Moderator - Multiplayer and Network Programming

Personal Information

  • Role
    DevOps
    Programmer
    Technical Director
  • Interests
    DevOps
    Programming

Social

  • Twitter
    jwatte
  • Github
    jwatte

Recent Profile Visitors

The recent visitors block is disabled and is not being shown to other users.

  1. This goes to cryptographic protocol design. The first parts of your encrypted payload, when decrypted, will likely be quite guessable, because it will contain things like sequence numbers, object IDs, packet type IDs, and so forth, that all take a fairly limited set of values. This means that, if someone has a large number of packets encrypted with the same key, and know enough about the first 8-16 bytes of the payload, when you use a single IV for every packet they will be able to use differential cryptoanalysis to break the session, recover the key, and then decrypt the entire session. However, when you use a different IV for each packet, the differential analysis doesn't work, and your key can stay secure. The problem is that the receiving end needs the IV to be able to decrypt each packet, hence the IV is generally prepended to the packet payload. As opposed to the key, the IV doesn't need to be secret; it just needs to be sufficiently different between packets. An alternative, that "should" be as good, but has not had the seal of approval by crypto designers, is to use a good random number generator to generate 16 bytes of random data, and put that first in your encrypted payload. Because there is no similarity to look for, and assuming you don't use "ECB" mode for your cypher (you REALLY shouldn't!) then this will similarly confuse the differential attacks. The receiver would then decrypt the payload, throw away the first 16 random bytes, and recover the message you sent. This has the same overhead as sending the IV in the packet, and accomplishes the same thing, but is not the "recommended" way by cryptographic experts. There exists a protocol called DTLS which is approximately TLS/SSL over UDP. If you don't want to implement your own, you can use that. It may have slightly higher overhead than a to-the-metal implementation, because it also provides additional features and flexibility, just like TLS has overhead on top of TCP, and provides additional features.
  2. If you want to write the game as a Java form, then use simple Java sockets to connect to a simple Java server using TCP sockets.
  3. HTML5, JavaScript, CSS3, and Websockets would probably be the easiest. A typical websocket web server (on Node.js or golang or Erlang or whatever) will be quite lightweight, unless you put a ton of processing on it. So, without knowing more, I'd say building this like a typical webapp, with perhaps a node.js server, would be the first think I'd try.
  4. hplus0603

    Lobby, Connection

    A stable file serialization and download protocol exists: It's called HTTP! As long as you can identify the right files (say, using a SHA256 checksum or a unique name + version) then a HTTP server can serve the files as appropriate. The benefit of this is that you can also use HTTP caching, CDN servers, and so forth. The drawback is that you need to somehow get the right files to the HTTP server/s you're running, but this is true no matter which download protocol you're using. Regarding lobbying, this is typically specific to whatever platform you're using. If you're rolling everything from scratch, I'm not sure you'll find much in the ways of from-scratch java lobby implementations. You might want to look at existing systems, for example SteamWorks for PC, or the appropriate Game services API for mobile phones.
  5. You don't want to use port 80 unless you actually speak HTTP. Doing so will confuse "smart" routers that try to interpret the protocol. For real-time-ish data, that needs to be encrypted, the best solution is to use HTTP/2.0 with a protocol upgrade. This will be bidirectional, support server push, and be encrypted. For example, the "gRPC" protobuf-based protocol from google uses this mechanism. In fact, I would recommend gRPC, except I don't know if there are any good libraries for Erlang for it. Another option is to use the Websockets protocol, which you can run over HTTP/1.1. As long as you run it over HTTPS (on port 443) data will still be encrypted. Websockets lets you frame payloads in JSON objects, which is good, but is going to use more bandwidth than a binary based protocol like protobuf/gRPC. The third option, and the most work, is to use HTTPS to establish a session, and exchange a shared secret (key) as part of that session. Then send data with UDP, and encrypt the payload with the key. Make sure to send a new, random, IV at the beginning of each packet, and you'd also want some session ID up front to know which key to apply for decryption. This is a lot more work to get going, but it allows you to use UDP (if low latency jitter really matters) All of these require that you use HTTPS in some form. The easiest way to use HTTPS is to set up certificates with Let's Encrypt, which are free, and last three months; there are scripts to auto-renew these certificates, but again I don't know whether they exist specifically for Erlang or not.
  6. I doubt it's a local game. It's more likely that each phone connects to a game server, and the TV/browser also connects to taht game server, and they just act as slightly different clients for the same game instance. To push updates to the clients, if you use web browsers, you can use websockets these days; all browsers support that, and server support is pretty simple for most languages. It depends on which particular language and framework you're using, so google for the appropriate combination.
  7. Are you talking about the client or the server here? The server will typically always have the complete view, but only give each client a separate view based on what they can see. If you only store client views, then nothing can exist if no client sees it. Perhaps for some games, this might be acceptable, but for most turn-based games, there's "world state" that no player can currently observe, yet needs to be persistent.
  8. The latency of requesting data from a remote store will totally kill any attempt to keep game state remote. Compared to all the display information (applied CSS rules and DOM elements) a browser keeps for text on your screen, the state needed even for a highly detailed game with lots of units is pretty small in RAM. I doubt you'll run out of memory. You also don't want to store each element of the game in its own little chunk or database row or whatever. This generates way too much overhead. A single "JSON.stringify()" on your entire map data structure would be quite sufficient. Also, keeping behavior and actions separate from the raw data is, in general, a good design principle, so not using objects with methods for the raw data would probably help. Instead, use separate functions or objects that are "mutators" on the state. Those mutators may, in turn, end up being your command objects. There are a few additional patterns that work well for updating game states and checkpointing them. One is to store the initial conditions, and then each command being executed, as well as what's needed to reproduce your random number generator, and stream it all out. If you need to recover, simply replay all commands from the beginning. If your model is "queue commands, resolve turn" then clearly you have to store all commands per turn, to play them back at the right turns. If you use timing, then your timers and commands need to be appropriately timestamped. Another is to write "save game" as a feature, and simply call it once after each turn, saving the game state for later restore. A third is to implement simulation as two copies of state. Commands look at the old state, and transform the old state into a new state. If you can enforce that old state is never changed by the commands, you can build a full chain of all states the game has gone through, and "timeline wind" forward and backward. Although for a very late game with lots of turns, you might eventually run out of space! Keeping last turn and next turn, though, would be reasonable. However, when resolving commands, if you want order to matter (Unit A goes first and kills unit B, so the command for unit B to attack A will not take affect) you have to take that into account in your command resolution -- because, in the constant "old state," unit B still exists! On the other hand, this may be what you want, as it means that turn order don't matter, everybody does their commands, and THEN units that died are removed.
  9. hplus0603

    To Upnp or not

    The security problems are for users who have UPnP enabled on their network. Your game is no more or less secure whether it tries to use UPnP or not. So, try to use UPnP, and if it works, great. If not, you should have a fallback NAT introducer server to enable connecting to other players (and you'll need a server for matchmaking anyway.) Finally, your documentation/help site could tell users how to set up port forwarding if they want to; you can implement that as a "will always work, last resort," but don't put that front and center in your default user flow.
  10. When the server sees a new player connect, it should collect all the state of the already-connected players and send those to the new player.
  11. You don't need a history buffer on the client when you apply the state in the incoming packets. There are some interpolation mechanisms that will work better if you do, but that's not for communications purposes. You just need to know the packet number that you get. Discard packets that are out of order. Applying the state when you receive it (assuming it's not out-of-order) is sufficient to get the object to a state that you know it has had on the server. If you miss a packet, the server will just re-send the deltas that were in that packet (or, more accurately, deltas for objects that were in that packet, but with later state) in the next update, because you're not going to acknowledge that packet. And if you discard a packet that arrives out-of-order, that's the same as that packet being dropped. This assumes that you send ALL the objects that have outstanding changes in each packet. If you want to schedule updates across different packets, it gets a lot more complicated, and you do need at least a "last packet per object" counter, if not the full state, to make it work. So, this delta compression works best for systems with fewer moving objects (dozens, not hundreds or thousands.)
  12. If something hasn't changed at all, you still shouldn't send it. What XOR does is cancel out bits that don't change. If you have a triplet of Xpos, Ypos, Zpos, stored as three 32-bit integers, and you move 1000 units along X, 20 units along Y, and nothing at all along Z, then most likely, the two top bytes of X won't change (and will turn into 0,) the three top bytes of Y won't change (and will turn into 0,) and all four bytes of Z won't change, and it will be all zero. If you have a single bit for "the position changed," then compressing the delta you send for position will save you some extra space. The draw-back is that you need a copy of the exact old data that the XOR was based on, to recover the intended update.
  13. Note that the client then needs to know which previous server state this is in reference to, so the server needs to include which last acked client tick it based its compression on. The client then needs to also have as long a queue of old client states as the server has, to be able to reconstruct the correct value. As you said, a lot more complex, not to mention uses more memory. I'd love to see some numbers on the actual size uses of the different approaches, on the wire and in RAM, if you have them!
  14. I'm assuming this is initial map download data? The best protocol for bulk data transfer is HTTP. If the server is publicly addressable, you can spin up a HTTP server on some known port, and tell the client which URL to use to download the map. If the server is not publicly addressable, you can perhaps set up a separate central map server, or use some Dropbox or Google Drive or OneDrive connection to share the map data.
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!