• Advertisement


  • Content count

  • Joined

  • Last visited

Community Reputation

11392 Excellent


About hplus0603

  • Rank
    Moderator - Multiplayer and Network Programming

Personal Information

  • Interests


  • Twitter
  • Github
  1. If your top level data is an array, then your serializable object must also be an array. An object with an array member is different from just an array. Thus, you want to de-serialize into an array. It sounds like Unity's JSON doesn't support that (although that's legal JSON -- arrays and objects are allowed at top level) and you can't change the server, so you're in a tough spot. If your data comes back as "empty" then chances are that you're being hit by some kind of web security restriction. In general, scripts that run from domain X, will not have access to data loaded from domain Y, unless the headers on the response from domain Y specifically white-list domain X. This is to avoid credentials theft and cross-site scripting of various kinds. The concept is called "cross-origin resource sharing" and you can find a link about it here: https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS Perhaps the Unity editor implements those restrictions, and the service you're talking to does not include the appropriate headers. Try looking at the data in Wireshark to see what you actually get on the wire. Also, try looking in the Unity web request documentation for properties that may affect CORS.
  2. I imagine this would be quite useful to Unity developers, and other C# game developers! Are you planning to test performance when there is packet loss, too? How quickly they recover, and such?
  3. Building my Own Server, Help

    Real time, over mobile networks, is a real problem. People in un-crowded areas served by 4G will do pretty well (up to a few hundred ms latency.) People in crowded cells (popular places/cities, and so forth) or on slower networks (HSPA, 3G, etc) will have more lag. For a fighting game, you might want to read up on the GGPO architecture; they use a rewind-and-re-simulate mechanism, and hide latency with wind-up animations, to make "street fighter" type games work OK even over medium latency connections. I would recommend against using WebSockets, and socket.io. The reason is that TCP suffers when there are packet drops; a single packet drop means that all the data that comes after must wait for a re-send before the receiving end will actually deliver the data -- it'll sit waiting in the kernel for the earlier data to be re-sent, because of the in-order guarantee. For low-latency games, UDP is a better choice. "how do I game server" is a slightly too large subject to write about in a single forum thread, though. There's matchmaking, basic packet framing, basic socket usage, NAT traversal, latency compensation, metrics and statistics, performance tuning, hosting, and so much more...
  4. Need advices wich tool use.

    My guess is slither.io uses node.js with JavaScript (perhaps TypeScript or some variant,) and uses WebSockets. There's a built-in module in node.js for WebSockets. Btw, slither.io has occasional significant lag spikes, presumably because of the JS garbage collector, and/or because of the TCP data-blocking behavior when some packet is lost. If your game has action elements, this may or may not be good enough for you. Then again, if you need to run in a browser, then WebSockets is pretty much the only viable choice.
  5. Interesting. I assume you only chose libraries that had C# wrappers? Thus, no Raknet, for example?
  6. Forge Networking Sync Animations

    I assume every animation has a "current play position" parameter, to allow seeking? When animations start playing, and while they're playing, you should probably keep sending packets of "animation X is playing, at position Y when the game time is T." On the client, receive those, and make sure the animations sync up to animation-position / game-time. When animations stop playing, of course send a packet saying they aren't playing anymore (and, if you're using lossy packets, keep sending until you're sure the client knows.)
  7. Client websocket libraries for Unity and mobile-native may not be as robust as those built into a browser. The only reason to use Websockets is really that it's hard to get real-time communications out of browsers in other ways. When the platform is not a browser, other options open up. If you're writing native code, how about using nodejs, but with UDP sockets? They are fully supported in nodejs. Or, if you don't like to build some kind of replication protocol on top of UDP, you could use plain TCP sockets (although they are not as good on lossy networks as UDP about latency.)
  8. The question seems like it is entirely answered in this thread. What is that that is not working for you? Can you post code for setting the linger option and closing the socket? Can you describe what you expect to happen in the code? Can you describe what you observe actually happening, and why you think that's not what should happen? We can't read your mind, and thus can't answer your question without information.
  9. Server battle predictions?

    Easiest is to run the simulation on the server, once, and record the movement and actions of all entities. Then let players view this recording, a bit like a videotape. You can hide the fact that the outcome is already "determined" through UI. Second easiest is to develop the simulation code such that it is deterministic. The exact same inputs, simulated through the same simulation engine/code, should lead to the exact same output. Initialize all random number generators with know seeds. Make sure all inputs are provided in the exact same order. Step the simulation the exact same way, with the exact same simulation step size. Ideally, use integer math rather than float/double math. This will let you start the simulation, and then view it, as many times as you want. To run it "fast" on the server, simply step it forward as fast as you can. On the clients, you'd just step it forward once per render frame, to show a "real time" playback. Regarding "random" numbers used in games (and the default random library,) they really aren't random. If you seed a random number generator with a specific value, it will generate the same sequence of numbers in order, every time you re-seed it. If all other simulation bits are the same (the same objects, taking the same damage, going through the same code paths, ...) then the random number generator will generate the same random numbers. Perhaps a good resource for this is the "1,500 archers on a 28.8 kbps modem" article series from Gamasutra. It talks about how Age of Empires implemented deterministic gameplay to support input-synchronous gameplay for an RTS. It sounds like your simulation engine has very similar requirements, with the added simplification of not allowing any real user input after the simulation starts.
  10. Snapshot Interpolation

    You might want to look at the Entity Position Interpolation Code library: https://github.com/jwatte/EPIC
  11. Accounting for lost packets?

    You can still establish whatever tick rate you want, as long as you realize that some ticks may have zero inputs, or more than one inputs. Simply keep your own timer, and advance it by 0, 1, or more ticks each time in the main loop, based on what the time actually is, and what your tick rate is. Note that you can't send inputs for tick T from the client to the server until the client sees the beginning of tick T+1, because otherwise the next time through the main loop may still be within the time period of tick T. The other drawback, if the vsync is not well matched to your desired tick rate, is that you will get some jitter. Not all screens are 60 Hz. Some screens are even variable-rate (G-sync comes to mind.)
  12. Typically, when a client first connects to a socket, the server doesn't know who that client is (what account/user.) After the client/server agree on software and protocol versions, typically the first thing that happens is that the client authenticates to the server. This typically means sending a username ("this is who I claim to be") and a password ("this is how you know that I am actually who I say I am.") The server then looks up name/password in a database (typically after hashing the password using scrypt() or bcrypt() or mcrypt()) and if the database comes back with "this player exists," then the server knows that the given connection, has the given player on the other end. For TCP sockets, it's common to assume one TCP session is the duration for that authentication. If the client needs to disconnect and re-connect, name and password can be sent again. There are also various means by which you can first log in once, and get issued a secret token (only known by the server and you) which is good for some amount of time, identifying you as who you say you are. This allows the client to forget about the password the user typed in, sooner, which is slightly safer if the client gets hacked somehow. For UDP sockets, there is no "session," so you typically have to build your own session handling on top of the protocol. Using the remote IP address and port number of the UDP packet is a good start; typically the server will also issue a secret value/id ("strong random session id") to the client, who will then include that ID at the head of each UDP packet to keep proving that the packet is part of the given session.
  13. Accounting for lost packets?

    Some amount of de-jitter delay on the server is often a good thing. 100 ms seems a bit much, but might be OK on your system. What's important is to make sure that you simulate in discrete "ticks." A "tick" might be 1/100th of a second, 1/60th of a second, 1/30th of a second, or whatever. For each simulation tick on the client, there is some player input (which may just be nothing, or a repeat of what the previous tick was, or may be a new input state.) You need to send these inputs, in that order, to the server, so the server knows the relative spacing of those inputs. The server should then attempt to apply the inputs in the same order, at the same relative tick number. When something's lost, you can ignore those inputs, and the client will get corrected. When something arrives late, that's the same as "lost," although you should have a little bit of de-jitter buffer to account for this. Also, it's common to pack multiple input/simulation ticks into a single network packet -- simulate at 60 Hz, network at 15 Hz, packing 4 inputs in turn per packet. The packet size, transmission delay, and receive buffering will all add to input delay between client and server; this is unavoidable. Then, when the server sends state back to players, the players always accept this state, with the caveat that the state may be "old" for the player character (because the player already simulated ahead since it sent the inputs.) Thus, you typically want to keep a log of old player state, so you can compare what you get from the server, and apply the delta when you receive the updates. On screen, you can choose to smoothly lerp between positions, or just "cut/jump" the character to the new spot, if the difference is too much. But the simulation state, itself, must be derived from what you get from the server at all times. Some more additional bits: To support a simulation rate that is not an even multiple of the frame rate, you may wish to support interpolation for rendering. Or you can quantize to the "nearest" simulation step at each render frame. If you simulate at 200 Hz, and render at 60 Hz, that can work OK, for example, but with simulating at, say, 100 Hz, and rendering at 60, there will be jitter that some players will notice during movement. Snapshots should never be sent from client to server, only from server to client. The server can also forward the inputs for each other player more often than snapshots, if you want to save bandwidth. Each client can re-simulate the state of each other player based on the snapshot data and subsequent control inputs. It's not uncommon to simply send snapshots on a rotating basis; spread all entities over, say, a 3 second window, and snapshot them all during that time. If you send 15 Hz packets, that's 45 packets to send snapshots in, so if you only have 5 players, there's 8 packets without snapshot, for each packet with a snapshot. The packets also contain other-player input, as well as particular game events (say, explosions, or somesuch, that can affect gameplay for the player directly.) When there are NPCs or more players, there will be more snapshots to send. You also typically want to send a snapshot when a player/player interaction happens, even if it's "out of order" with the scheduled updates. When two players collide on the server, you know that they will not have seen the same thing on each client, so it's best to send immediate updates to each of the affected players to make the delta time between collision and adjustment as small as possible.
  14. Accounting for lost packets?

    There are two ways to do networked games: 1) You (the client) are provided an input state, and then, in order, each command given by each other player (including when the command was to be executed.) Your code is written to be deterministic; every player will run the exact same simulation with the exact same input, and will derive the exact same end state. This is not particularly common in FPS games, but very common in RTS games, and somewhere in between for RPGs. The main draw-back is that debugging de-sync is a pain, and there is significant command latency between giving a command, and seeing the result (because you need all player's inputs for time T to actually show the output at time T.) RTS games hide this latency behind the "yes, sir!" animation. 2) You (the client) are provided a stream of object events -- "start showing object," "object updated," and "stop showing object." The server figures out which objects are important to you, and tells you about them. It also figures out how wide your network pipe is, and updates changing state about objects every so often. The client then does what it can to display a "good enough" state of the world (this may include speculatively simulating physics for the objects.) However, when the server gives you an update that is different from what you speculated, you need to "fix" the state of the object to be consistent to what the server says. For small changes, this is easy to hide using interpolation and such. For bigger changes -- either in time, or in things like "did I get shot or not" or "did I trigger the bomb or not" -- this may be perceived as "lag" by the player. Your implementation sounds like it's a variant of 2). Yes, you will de-synch, almost all the time, but usually very little. Your job on the client is to try to hide the small corrections, and at least make the game still possible to play when you get big corrections.
  15. about mmo persistent player data

    Databases aren't necessarily faster than file systems. Instead, they provide features file systems don't, like block coalescing for small data items, and multiple indexing, and transparent management of millions of items, and transactional semantics. Try creating a directory with a million files in it. Most file systems will choke and slow down tremendously. Also, to actually get transactional update of a file, you need to: 1) write to a temp file 2) call fsync() and fdatasync() and close() 3) call rename() to replace the old file with the temp file 4) call sync() And sync() is asynchronous, so you don't REALLY know that the rename was actually persistently committed. But at least you'll be in one of two states: old file, or new file, without any half-files. (This is on UNIX -- Windows has similar system calls available)
  • Advertisement