Show Posts

This section allows you to view all posts made by this member. Note that you can only see posts made in areas you currently have access to.


Messages - Masaaki

Pages: [1] 2
1
TNet 3 Support / Re: Area of Interest
« on: February 06, 2014, 12:20:19 AM »
Turned out to not be too difficult to add this myself.
(to clarify the following, when I say TNServer I mean the actual physical server that comes with TNet, and when I say Game Server I mean a special build of my game that spins up a TNServer and joins as the host)

So I modified TNServer to add a "blacklist". So I can essentially register a TcpPlayer with a particular UID. So when the TNServer goes to send an RFC to everyone, it checks if a given player is on the blacklist for the given TNObject UID before sending.
I added a new Packet.RequestSetScope. This tells the TNServer to add or remove the given player from the blacklist of a given UID. It also generates ResponseDestroy and ResponseCreate packets if you set scope to False or True (respectively).
Then I wrapped this with a function TNObject.SetScope( TNet.Player player, bool hasScope ) which sends the RequestSetScope packet to the TNServer.

I use this for my area of interest management like this:
- Interesting Objects are sorted into a quadtree each frame.
- Interest Observers (players) query the quadtree for nearby objects within their area of interest. When new objects enter their area of interest, they call newObject.SetScope( myOwner, true ), and when objects leave their area of interest they call leavingObject.SetScope( myOwner, false ). This is performed on the Game Server (which always has all objects loaded, and never has it's own player)

Beyond an edge case (nullref exception is throwing my Game Server for a loop at the moment, nothing a little debugging can't fix), it appears to be working perfectly. If I walk away from my spawned enemy mob, they are deleted from the scene. If I return, they get re-instantiated.
So far has taken about a day.

EDIT: There's always another edge case, lol.

2
TNet 3 Support / Re: Area of Interest
« on: February 05, 2014, 07:10:43 PM »
I'm probably just going to get my hands dirty and rip apart the TNet code for this then :)
I think what I'll do is have my "interesting objects" (TNObjects which can enter and exit a player's area of interest), sorted into a quadtree. My server keeps track of which object a client is currently interested in at any given time (a list of interesting objects can be obtained by querying a rectangle of the quadtree). If any new objects get added to this list of interesting objects, Create messages are sent to the player. If any objects are removed from this list of interesting objects, Destroy messages are sent to the player. Then I could add a check to see if a given TNObject is "interesting" to a given player, so prior to sending an RFC packet I could check if the TNObject is interesting to the given client and if not don't send the packet.

That said, I would actually like to see a feature in TNet of being able to set the scope of a TNObject per-player. So perhaps I can say (in psuedo code) tno.SetScope( player, true/false ). So if I set it to "false" the player stops receiving any RPCs. If I set it to true, the player gets all buffered RPCs and any others sent from then on. It should be trivial to also add that setting False sends a Destroy message, and setting True sends a Create message (maybe controlled by a parameter of the SetScope function of whether or not I want it to send Create/Destroy messages).
That should afford pretty fine-grained control over this stuff.

3
TNet 3 Support / Area of Interest
« on: February 04, 2014, 09:37:26 PM »
Hello
I'm using TNet in an application designed for fairly large player populations (aiming for by default a max of 128 players per server, but server hosts can change this value).
One thing I want to add is interest management. With a 10km world, a hundred players scattered across the world, player-made structures, loot chests, monsters, and more, doing it "the naive" way (zero interest management, player gets messages for everything in the entire world) is probably not going to cut it.

So on a conceptual level, when an object enters a client's area of interest, the server sends a Create message for that object and additionally any buffered RFCs. When an object leaves a client's area of interest, the client destroys that object. The server only sends RFCs of an object to a player if that object is in their area of interest. (going to skip how the actual checks are performed for the sake of argument - doesn't really matter, will probably use quad trees though)

Question is, can I accomplish this without touching core TNet code, or should I modify TNet for my needs?

(by the way, when I refer to the server I mean a "game server" which is just a special build of my game that spins up a TNet Server and immediately joins as the host)

4
TNet 3 Support / Re: Server Itself become Authoritative Host
« on: February 04, 2014, 02:11:40 AM »
I'd like to clarify what Aren says.
So basically, in TNet, the actual physical server application is nothing more than a middleman for routing messages (it's a bit more complicated than that, but it helps to think of it that way). That's pretty much all it does, and it has zero knowledge of Unity at all.
In my game, I needed a dedicated server model, and the way you do this in TNet is by having a special build of your game which acts as the "game server", by starting up a TNet server instance and immediately joining it. Therefore your "server" is technically a player (as far as TNet is concerned) and because it joins first, becomes the host. This is what I'm doing in my game (since I needed server authoritative logic) and works like a charm.

5
TNet 3 Support / Re: Make the server host
« on: October 17, 2013, 03:35:48 PM »
If you want a dedicated server, you could always go the uLink route (not buying uLink, but taking some ideas and applying them to TNet) - make a dedicated build of your game specifically for servers, and run it with the -batchmode parameter. Requires Pro, but then so does uLink's dedicated server (because basically it's the same thing). I'd probably make an editor script for compiling server builds if you go that route - would set up appropriate build options (like compiler directives) and call BuildPlayer with a subset of the game scenes required by the server.

6
TNet 3 Support / Re: Networking Physics Discussion
« on: October 07, 2013, 07:55:27 PM »
If my understanding is correct, the Source engine doesn't do any sort of physics replay on the client. Instead, the clients are treated as though they exist slightly in the past (10 ms or so). This means that instead of having the extrapolate the position of where the object will be, the client can simply keep a buffer of positions where the object was (marked with timestamps) and interpolate where the object was 10 ms ago. Of course, having the clients "living in the past" no doubt creates its own set of issues, but it does seem to avoid the need to do physics extrapolation.

It does no replay on objects that aren't completely under the player's control, but any object the player owns and controls (their player object, mainly, perhaps a vehicle they are riding, etc) does use physics replay. That "living in the past" bit is only for interpolating game state received from the server for objects the client doesn't directly control.

7
TNet 3 Support / Re: Networking Physics Discussion
« on: September 28, 2013, 11:50:21 AM »
I am taking a look at doing that for my game (a simple networked physics car game), but I don't see how you can resimulate the whole physics on the client in Unity, assuming you're using Unity (since this is a TNet forum). Can you explain in more details what/how you're doing that thanks?

It seems you could hack something together with manipulating Time.fixedDeltaTime but I'm not sure the physics engine will appreciate that.

That is a problem, as you cannot really step the physics in Unity on a per-object basis. Unfortunately, I'm not really sure you CAN do this for vehicles and such just yet - unless you roll your own physics or grab a third party physics engine such as Jiggle or BulletX

In my case I was using CharacterController, which made it fairly easy to just call my own simulation code on-demand.

8
TNet 3 Support / Re: Networking Physics Discussion
« on: September 23, 2013, 12:06:11 PM »
In GMod, I don't believe they use any form of prediction when dragging physics objects. I think the default behavior in Source is that physical objects like ragdolls and props are always controlled by the server, and not predicted by clients.

9
TNet 3 Support / Re: Networking Physics Discussion
« on: September 23, 2013, 02:31:23 AM »
EDIT: I got rid of the "verified" system and now it's working pretty good. However I do have a question, collision with other objects usually causes prediction error and the client has to be corrected... causing noticeable view lag.
What's a good way to minimize this? I know a big flaw in CLSP is the fact that collision often causes prediction mishaps. Would the wisest solution be simply to sync a collision from the serverside with the client? Or perhaps the other way around? Or both?

Collision does seem to be an issue. In general, probably because of floating point precision, if I walk against another player (both players are capsules) either the client slides away to one side, or the server does, and in this case the client eventually snaps to where they should be. I'm not sure anything can be done about this - other than limiting the amount of collisions that occur. Collision with the environment seems to be much less of a problem than other players, oddly enough.
With other players, you're bound to end up with prediction problems anyway, as you don't have the exact state of that player at the time the server is performing physics with the data you sent to it. So you'll see some jitter when bumping into other players, especially if they are moving around.
One idea is, instead of instantly snapping to the correct position, the client smoothly interpolates to it. For small corrections much less noticeable than snapping.

10
TNet 3 Support / Re: Networking Physics Discussion
« on: September 15, 2013, 12:36:37 PM »
All my implementations of Client-Side prediction so far have given me unsatisfactory results.

If you're still interested I would take a look at the uLink Snowball demo. They implement server-authoritative physics with clientside prediction. The main changes I made was moving most of the logic from Update to FixedUpdate (I thought it was kind of fugly to have number of messages sent depend on framerate, and additionally I reduce another vulnerability as client does not have to send delta time - it's always the same between client and server for every fixed update), and I created an InputData class which was marked as serializable, so I batch together an array of them and send them 5 at a time as a byte array serialized with BinaryFormatter (so 10 times per second, rather than every fixed update).

You may (and probably will) run into lots of hair-pulling frustrations like rubber banding. I certainly did (spent I think 3 days on getting it working to my satisfaction). The main thing is to step away, drink some coffee, come back a little while later and double-check that the client and server are both running the same code, in the same order, with the same inputs. In my case, it was usually things running out of order.

11
TNet 3 Support / Re: Networking Physics Discussion
« on: September 13, 2013, 01:07:28 PM »
In my own implementation, I use a modified example ported over from uLink (I modified it to send messages periodically rather than every frame - ouch!)
It works like a dream. Basically, the client performs in the exact order:
  • Gather input state
  • Simulate physics with input state
  • Send input state to server along with position (redundant data)
  • Store input state (along with timestamp - I rolled my own network time system)

Server does upon receiving input state:
  • Simulate physics with input state (I use FixedUpdate, so time delta is the same between client/server therefore output is nearly same)
  • Check result against what client sent (redundant data). If client is too far off real value, send real value to client

Client does upon receiving a state correction:
  • Find the stored input state corresponding to when that correction was sent (matching timestamps)
  • Set state to server state
  • Resimulate every input state

The last part is very important (resimulating input), because by the time the player receives the state correction, it will have been sent some time in the past and is therefore old data (so the client must extrapolate what the correct position will be)

Syncs rarely ever happen (as everything is done in FixedUpdate using the same timestep, the output of client/server almost exactly matches, aside from numeric drift), and normally everything is smooth as butter with the very occasional hitch (hey it happens in Source too so I'm not concerned).

12
TNet 3 Support / Re: Network.Time - info.timestamp
« on: September 08, 2013, 11:42:27 AM »
I had need for something like this, so I just threw together my own network time component. It has a Time field, and this is synchronized with an RFC upon joining a game. It's based on the Time.realtimeSinceStartup of the host machine.

  1. using UnityEngine;
  2. using System.Collections;
  3.  
  4. public class NetworkTime : TNetBehaviour
  5. {
  6.         public static float time = 0f;
  7.  
  8.         void Start()
  9.         {
  10.                 time = Time.realtimeSinceStartup;
  11.         }
  12.  
  13.         void Update()
  14.         {
  15.                 time += Time.deltaTime;
  16.         }
  17.  
  18.         void OnNetworkPlayerJoin( TNet.Player player )
  19.         {
  20.                 if( TNManager.isHosting )
  21.                         tnObject.Send( "SynchronizeTime", player, time );
  22.         }
  23.  
  24.         [TNet.RFC]
  25.         public void SynchronizeTime( float t )
  26.         {
  27.                 float pingSeconds = (float)TNManager.ping / 1000f;
  28.                 NetworkTime.time = t + ( pingSeconds + 0.5f );
  29.         }
  30. }
  31.  

13
TNet 3 Support / [Request] More Array Types
« on: September 05, 2013, 12:02:33 PM »
In my code, I found that I had need to send arrays of Vector3s, and that TNet did not support it. It was easy enough to add this myself, but I'd like to not have my code broken by an update that wipes my changes.
Will you please add support for the basic Unity types in arrays? Such as Vector2, Vector3, Vector4, Quaternion, Color, etc.

14
TNet 3 Support / Re: Cannot call RFC before TNObject is created?
« on: September 02, 2013, 05:46:38 PM »
In case it helps, I noticed object ID assignment behaves differently depending on whether TNet is connected to a server or not. Connecting to a server, it seems to properly generate unique object IDs. When not connected, the behavior I mentioned in the last post happens.

EDIT: After some investigation, the behavior I mentioned appears to be a result of the UniqueCheck() which occurs in the editor. That's why the first object has the same ID as defined in the prefab - because UniqueCheck() determines that the ID is unique.

15
TNet 3 Support / Re: Cannot call RFC before TNObject is created?
« on: August 31, 2013, 01:01:23 PM »
Hmm... What is inside your custom creation function? RFCs get called on objects as-is without going through finding them, so the object ID is irrelevant in offline mode.

That doesn't appear to be the case. Following the functions:

I call Send
Send calls SendRFC
SendRFC sets a local 'executeLocally' flag
Later in the function it checks this flag, and if true calls TNObject.FindAndExecute passing the object ID, rfc ID (or name), and params.

My custom create handler isn't affecting anything, if I switch to just straight TNManager.Create I still get the issue.

Here's something odd. I checked the Example 2 scene, which spawns cubes. The cube prefab has ID 8 assigned. The first cube that spawns has ID 8, the next one has 9, etc. BUT if I let all of the cubes delete themselves and then spawn another one, it has ID 8 again. So if I had spawned 5 cubes the first time, the cubes had ID 8, 9, 10, 11, 12. If I let all of the cubes delete, then spawn another five cubes, they have IDs 8, 13, 14, 15, 16. It seems that the first object to be spawned, if there are no other dynamic objects in the scene, will get the ID of the prefab rather than an actually unique ID. I don't know if this is intended behavior or not, but it seems that assigning a non-zero ID to my dynamic object fixes the issue with not being able to call RFCs.

Pages: [1] 2