Jump to content
  • Advertisement


  • Content Count

  • Joined

  • Last visited

  • Days Won


hplus0603 last won the day on April 15

hplus0603 had the most liked content!

Community Reputation

11579 Excellent

About hplus0603

  • Rank
    Moderator - Multiplayer and Network Programming

Personal Information


  • Twitter
  • Github
  • Twitch

Recent Profile Visitors

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

  1. HTTPS is significantly harder than HTTP, because you talk the HTTP protocol over TLS, and the available TLS libraries are all kind-of hard to work with. Especially OpenSSL is known to have an API mainly intended to support the OpenSSH project, and only accidentally also somewhat usable for establishing TLS connections ... Then again, the "chain of trust" security model of TLS is, in itself, not super simple, and thus requires some necessary complexity, including an up to date root certificate store, and mechanism to evolve that store over time. There's GnuTLS, fizz, mbed TLS, and a few other contenders you might want to look at.
  2. Yes, gethostbyname() should take the string "www.google.com" Separately, the Host: header does not include the protocol, but it (can) include the port number. Thus, the Host: header should be "www.google.com" or "www.google.com:80" not "http://www.google.com" I wrote a small library to do exactly what you want to do, and the last version update was 11 years ago. Time flies ... You may want to read the source code: http://www.enchantedage.com/http-get
  3. hplus0603

    Network Library API critique

    I like the "accept one incoming connection at a time" API. You could even turn it into: ... inside top level loop ... while (NetworkConnection *conn = server->AcceptConnection()) { deal_with_new_connection(conn); } ... You don't need to return the address as part of AcceptConnection(); you can just have a member on NetworkConnection. I, too, think that specific channels aren't necessary at the lower level API. Some games will want to use object IDs, some games will want to use explicit channels, some games will want to use unstructured text, ... There's room for another API on top that does message sourcing/steering, as well as entity allocation/mirroring/despawning, and so on. Yes, you need one copy when you compress/encrypt the payload, and one copy when you decompress/decrypt the payload. But you shouldn't copy more than that. You don't need an explicit "Release()" function, if you return an object instance (by value/copy/move) that is a smart reference that does the necessary refcounting. If you chase this direction down, you end up with multiple objects that point into different parts of the same buffer, and the buffer doesn't go away until all those objects have gone away. Then there's the question of the cost of the reference count, versus the cost of copying the data, which isn't a clear-cut win if you need to use atomic operations for reference counts. Which leads us to ... Thread safety? It's OK to define an API that says "all functions must be called from the same thread" or at least "no two separate functions may be called at the same time from different threads." It's also OK to define some kind of more relaxed threading model, if that's convenient. If you want to go full-bore thread safe, copying data may again pop up as a reasonable thing to do -- only actual measurements will tell you for sure. But if you want lowest overhead, single-threaded API and non-atomic reference counts may win out. Good luck on the library! You might want to look at other libraries like Enet and RakNet and Lidgren, and figure out specifically what you think you do better, and what you choose not to do for whatever reason, and create a little comparison matrix. That will make it easier for other people to understand what your goals are, and whether your library is right for them.
  4. hplus0603

    Network Library API critique

    Some things that jump out: NetworkPacketReceived Network_Get_Packet This is quite inefficient. It's better to receive into an existing packet buffer, and then use pointers-to-buffers to pass the data around, rather than copy the data. That in turn means that the client also needs some way of "releasing" a buffer when it's done, and perhaps also "getting" a buffer if you use the same structure for queuing outgoing data. It looks like that API is copying, too. Generally, I like APIs better that use some type that generates type errors if I use it wrong, that just plain "int." So, the "connectionSlot" could probably be replaced with a "connection_t" which could be a "struct connection *". You don't need to actually define "struct connection," just keep the type distinct. It's unclear, in NetworkPacketReceived, how I tell whether a message came over the unrealiable or reliable channels. Generally, a server will want to get the IP address of clients, so it can implement block lists or such. Keeping that inside the library is probably going to make it hard on users of the library. I don't see how you deal with IPv6 vs IPv4 -- do you use dual-stack getaddrinfo() calls in the implementation? I don't see any affordance for setting the timeout of a client -- how long does the library wait before it suggests a client has timed out? What happens if a client then comes back and tries sending more data?
  5. hplus0603

    Learning Netcode

    Nice visualization! I assume the double sound effects are because the client and server render on the same host, and thus measure the lag?
  6. hplus0603

    Understanding Lag Compensation & Timestamps

    I have no idea how the Unity FPS sample does it. Perhaps you can adjust the FPS sample to make fractions of small adjustments if you receive a small delta, and only make the "big jump" adjustment if you really end up with a big offset. One possible, somewhat simple implementation, is to make the server send back in each packet "I received commands for tick X when I was at tick Y" (which is really just a simple difference) and "your adjustment value was Z." The client will send its adjustment value to the server, together with the target tick number. The client can then easily adjust its adjustment value to target a specific number of ticks-ahead -- say, 2.0. Because the server tells you what the offset is as well as the delta, you can adjust the offset correctly without much risk of feedback / oscillation. If you don't want to include this value in each packet (it's 4 to 8 bytes, depending on representation,) then you can instead apply dampening and hysteresis to the adjustment, where if you see an unaccecptable value (less than -2.0 or greater than +20.0 in this case, for example) then you would adjust the entire difference in one big chunk, and forbid any more large adjustments for the next 2*RTT packets.
  7. Synchronous waiting for object state to interact is a deal killer. It simply cannot work in a real-time game. Sun Project Darkstar found this out the hard way, too. (That, plus a surprising number of other well-trodden land mines!) What sharded MMO games and virtual worlds did, was to shard geographically, and then let objects near the border of the land area "mirror" their state over to the other server (unconditionally -- no request needed.) Thus, every local object could interact with all objects it could see with zero latency. Note that the counter-party would be interacted with by the copy of the object -- there are various ways of either lag-compensating that, or making sure that you have the "control inputs" for the mirrors just like the original so that you can use deterministic simulation to have everyone see the same state at the same time. It turns out, this isn't particularly important to users, so it's not really worth the effort, according to how the market has reacted. You're better off focusing on jamming 200-20000 users on a single server by optimizing your physics, and then use some kind of travel or teleport or loading portal to travel between areas. Users can't reasonably interact with more than a dozen other users at once, anyway, and when your design gets too dense in users, you end up with the "everyone in a pile" problem where the physics state of everybody depends on the state of everybody else, which cannot be parallelized or solved with RPC -- it's a natural n-squared problem.
  8. hplus0603

    Understanding Lag Compensation & Timestamps

    So, first, the client should not use this to set its "tick," but use it to set the "relation between local clock and server clock," where "clock" literally means the high-precision timer used to advance time in the OS. This is stored as an offset to QueryPerformanceCounter() or clock_gettime() in Linux. These clocks, in general, should proceed at very similar rates over time, so drift should be minimal in the normal case. You don't need to only use the signal for "within tolerance" or "totally out of whack." You can let the server tell you how many ticks ahead/behind you are. If you aim for 2, and get a couple of messages saying you're 1, or 3, ticks ahead, you can adjust offset by a small amount based on that information. Because the offset is in clock terms, not tick terms, you can adjust by fractional ticks. Just make sure you have some hysteresis/damping in that adjustment loop, or you'll likely to get oscillations.
  9. There's a normal sequence to these kinds of efforts (these are not the first people to try this): Making a design that can conceivably work Getting some real games to try the technology Success from the real games Making it an actual business that can return 10x the invested money Most hobbyist projects fail in step 1; most commercial ventures fail in step 3. From looking at the web site, it looks like improbable is currently in step 2. If they make it past 3, I still have questions about how they'd manage step 4... So far, the most-used game networking middleware is probably RakNet, which sustained a company of approximate size "one main person." And in the end, that person moved on to Facebook and the library is now open source. Most game engines (Unreal, Lumberyard, Source, Id tech, Frostbite, ...) grow out of a successful initial game. I think the evolutionary pressures are similar, but even harsher, for lower-level components like multiplayer networking.
  10. I haven't used it, but I've followed that business for a long time. My guess is that they're running up against three main challenges: 1) each game generally needs a carefully tuned networking model that has intimate knowledge about that specific game 2) approaches you can take for military simulation style networking, don't work for internet real-time gaming networking 3) networking and work distribution are hard problems, but they're not AS HARD as "building a fun game that people want to play" I note that they are starting their own internal studios, which presumably will consume a fair chunk of the money they raised. My guess is that, if they're going to make it, they will make it as a games studio, on the basis of the strength of their games, not as a technology provider. There simply is no (big) market there currently. (Having tried to push into/create that market myself, twice, that's my current judgment.) And, because they're building technology with something described as a "generic game networking protocol," chances are that their games studio won't be sufficiently well served by the protocol, and they will either fork/adapt it, or the game(s) will fail.
  11. hplus0603

    TCP, login and database on a realtime world

    There is no way to identify players across multiple/different connections. When the TCP connection first comes in, you need to identify the player. You can do this by requesting the name and password, and check those against some data store, or you can have some other service that checks name/password and issues a token, and the new connection then verifies the token (rather than having to verify name/password.) Which model works best for you depends on specifics.
  12. hplus0603

    TCP, login and database on a realtime world

    Yes, you can use something like JWT. Another option is something like a Kerberos ticket. Another option is something like a web session cookie token. The GAME server generally keeps the state of the player in RAM as long as the player is connected. When the connection drops, and occasionally when the player does something worthwhile (gains experience, or gains important loot, or whatever) the server typically checkpoints the state back to the storage system. Note that the JWT should not contain the actual player state (as found in the database) because that would allow someone to log in and get token A, then log in and get token B, then play on token B, and if something bad happens, re-use token A to revert state back to the old state. The token should only implement authentication, and the actual data is transferred on the back-end between the game server and the storage system (database, file server, three-tier web service back-end, or whatever.) A TCP connection is believed to be hard to hijack unless you have nation-state level access to the network, or are part of the ISP/transit chain for the connection. A TCP socket running TLS is believed to be hard to hijack even for those kinds of actors. Thus, if you either trust that the NSA or Chinese government don't care about your game, OR if you're using TLS for your TCP connection, using the socket as a persistent identifier for the player for as long as the connection is alive, is reasonable. Also, for real-time games, you shouldn't think of each key press or action as a "request." Instead, think of the world as a large state machine, that evolves based on inputs/stimuli, where one such input is the passage of game time (tied to real time.) Player commands are messages that provide inputs to this state machine. The player object state is a subset of the large world state machine, and changes to the player state are communicated using messages going back to the client machine. An important architectural realization here is that there is no direct 1:1 (or even M:N) relationship between "input messages sent by the client" and "world change updates sent to the client" -- they are separate, unidirectional real-time message streams. Some of the individual messages may, at a higher level, end up being in the request/response form, but those are to be viewed as one of many patterns on top of the two directional message streams.
  13. I think you need two counters for ammo -- one for "ammo count displayed to user" and one for "ammo count received by server." The user would be quite surprised if they fired a bullet and didn't see a lower ammo count right away. Similarly, you shouldn't let the user fire too many shots just because the server is slow to respond, so when the user-display variable goes to 0, stop allowing fire. You will likely also want a time-step-when-changed for each of them, and if you get a server update for ammo count at a time step higher than the last time you changed the display-value, then update the display value to the server value if they are different -- this will make sure that your display is "eventually consistent."
  14. If your multiplayer server is for "asynchronous, turn-based" games like Candy Crush Saga or Backyard Monsters or Farmville, it's possible that a generic multiplayer back-end could make sense. However, for any game with real-time requirements (action games,) the multiplayer game server needs to have very tight integration with the game logic of the game client, and generally the server and client will share that game logic code. What kinds of games are you targeting with your "generic" engine, and how do you intend to solve the game-specific functionality challenges?
  15. hplus0603

    Server Replay Details

    5 seconds is FOREVER. I'd put the limit at 500 milliseconds, and ignore any input that's later than that. If someone tries to play over a dial-up modem from the south pole, they're going to have a bad time, but ... meh.
  • Advertisement

Important Information

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

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!