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 - Patterrun

Pages: [1]
1
TNet 3 Support / Re: TNManager.Create'ed objects doesn't initialize
« on: June 13, 2014, 03:39:46 AM »
If you want to work with the GameObject in Create(), you can do that but you will need to follow the instructions in this thread:

http://www.tasharen.com/forum/index.php?topic=5416.0

Basically you create a custom function callback which is called an RCC that is used in CreateEx() (instead of simply Create() ). He also wraps the CreateEx() call in a static function for easier use. In the custom RCC you make you can work with the GameObject that is created in a normal Create() call. It is tedious but it is worth it if you need to work with the GameObjects in Create().

2
TNet 3 Support / Re: Syncronizing Players And Intialization
« on: June 13, 2014, 03:33:47 AM »
I ended up scrapping a lot of code over the week and I decided to avoid using Create() calls for everything as much as possible except for players. I ended up synchronizing some things like powerups being picked up by sending arbitrary ids based on grid data I made and then sending RFC calls from the player that entered them to everybody else. Speaking of the grid data I decided to do that so everyone can receive the data and make local copies (via RFCs) when joining, and I based a lot of the code around this concept. Long story short, I did quite a bit for somethings which I thought were going to be simple.

About the new players seeing the bombs on join, when I was still using Create() calls and lots of TNManager.isHosting logic, it was initially for visual effect since it would look strange to be dropped in a match where bombs are exploding and such. If I don't have a kind of protection period for the new player either, then they could die and not know what hit them (host seeing they died) which would be frustrating.

However, now that I changed everything besides the players to local objects, if I don't sync the bombs on join, the game worlds will be desyncronized and different so it was actually important for me to do it now. I already did it though with a convoluted system involving my grid data and keeping track of the bombs.

As for this,
Quote
The lag with Create calls is to be expected as it has to happen for all players. You can only eliminate this lag if you create a local object, followed by tno.Send to others. Then there is no visual delay on the client's side, but as we talked about this runs into other difficulties for you since you aren't using TNManager's Create calls in this case. You can never eliminate network lag. You can only make it invisible with a lot of forward thinking and clever tricks.

Would this not cause de-syncs though? If I create the local object early on the player's screen, then it will explode earlier too on the player's screen but not everyone's elses. Ideally I would like to do this as now the only visual lag I have is when laying down bombs, I managed to hide everything else by doing what I said above which was making everything local and synchronizing player pickups at the very end.

Finally for the players deaths, I do see that way is much better but it's not too much of a problem right now as opposed to the laggy feeling of laying down bombs right now. Apart from a rare de-sync or two in game worlds, I managed to get everything else down.

However, one more thing, since I was feeling better about everything else, I went back to work on the smoothing of client's avatars since that was the most jarring. I don't know if I should open a new thread for this but for now I'll continue. Initially I just sent out position updates without lerping or anything. It's of course not good so I decided to use interpolation on it by keeping states on positions and lerping between them 100ms in the past. This hardly proved to be any better, but I've tried the same popular technique with Photon and such and it's not great there either. Using a simple lerp between the latest update position is smoother, but it slingshots the character which is not much better. I decided to then move everything to FixedUpdate() and it was a bit better but not much. Is there anything else I can do to improve the smoothing? Also, I am using a character controller, not a rigidbody for movement. Using a rigidbody is even worse, especially above 50ms of lag where there is no way to smooth it well even with all the stuff I read here before, re-syncing on collision events, syncing transform and rigidbody 4-5 times per second, etc. My character controller is jerky above 100ms but like the rigidbody is also visible above 50ms.
 

3
TNet 3 Support / Re: Syncronizing Players And Intialization
« on: June 05, 2014, 03:06:54 PM »
I don't think I am explaining it very well but what you suggested is what I already tried, and even the your post about the timer with the bombs is what I did and said in my post (I synchronized the timers with OnNetworkPlayerJoin() so I could show it in the onGUI and see in realtime how the timers are counting down). This is my goal: I want new players to be able to join and see and know about all the latest action on the map so they can join rounds at any time in a relatively synchronized state.

The problem is when new players join, they only see the latest bomb from the tno that created them (player avatar) if I do not use Create() but Send(Target.AllSaved). But if I use Create(), I have to use Create() for the explosions and TNManager.Destroy() after the timer is over, and only by one person (I use the host because if I use tno.isMine and the player leaves, the logic never gets executed because no one owns the bomb object when that happen it seems. If I don't have the host or owner do the logic, every client creates an explosion. Then if I do the explosion locally instead, sometimes the explosion never occurs for some clients as the time between TNManager.Destroy() might reach them faster than their own ticking down of the timer. If I then change TNManager.Destroy() to a normal local destroy, new clients that join never get these messages. Anyway you can ignore all the stuff inside these parantheses but basically I have thought this through and made sure to actually try each thing. ). This way seems to work but introduces a lot of unnecessary delay (becomes apparent at above 100ms ping to server) in every step of the process from:

1) Lay down bomb
2) Bomb timer is over, raycast other objects and send a destroy message to them
3) Create explosion, destroy self (bomb)
4) Other objects that have received a destroy message (that then calls TNManager.Destroy after running their own logic like drop an item) destroy themselves
5) Item is dropped (use similar logic as the above two steps and TNManager.Destroy self after adding to player when someone touches it)

For example, it takes time to see the bomb laid down for everyone, making it feel laggy as soon as you press space. Next, explosion takes a little bit to appear. After, objects that have been sent a destroy message take a while to destroy even though the explosion has already occurred, making it look further laggy. Next items take a bit to appear. Finally when a faster player runs over an item, it takes a while to disappear. If I replace all the logic with Send() messages instead it's all fine but then new players do not see any of the action that may be currently happening and affect them. I suppose I could just cut out this realtime joining and change the game completely but I really, really do not want to do this. I know there has to be a way to get this done.


4
TNet 3 Support / Re: Syncronizing Players And Intialization
« on: June 03, 2014, 12:48:18 AM »
Well the projectiles aren't that quick or many created per second, they are more like cannonballs. I also have bomb objects ala Bomberman. And yes, I am using TNManager.Create() to create these slow projectiles and bombs. As for the dictionary, don't mind it, I think I need to approach that differently and I will after I tackle this immediate issue first.

When I did what you said:

Press Space to:
tno.Send("FireCannonballOrDropBomb",Target.All)

[RFC]
void FireCannonBallOrDropBomb()
{
GameObject.Instantiate(slowProjectileLikeObject,transform.position,Quaternion.identity);
}

With the above when a new player joins the channel, they are not aware the cannonballs or bombs laid even exist and there could be many on the screen waiting to detonate or cannons still traveling across the map still.

If I use Target.AllSaved as my target, only the latest cannonball/bomb is saved. And with that when objects are destroyed without another RFC, the last cannonball/bomb is recreated everytime a player joins a map.

While I tried various ways of logic with TNManager.Create() and TNManager.Destroy() instead and having each projectile be a tno, I got better behavior but I still haven't reached what I wanted to do. The closest to success I got for bombs was: they are created by anyone, but only host the ticks down the bomb counter. At the end of the timer it runs some logic such as if it the raycast it generates hits a destroyable object, it calls a CustomDestroy() on it which simply makes the objects drop items if possible and then calls TNManager.Destroy() on itself because destructible objects should disappear when hit. After this raycast logic is run, a Create() is called for an explosion effect and then Destroy()s itself.

The problems with this are that there is an unnecessary delay for everyone as to when the explosion effect occurs and the bomb is destroyed, as well the destroyable objects being destroyed. There is already normal latency lag for when the bomb is created (I am testing with 100-150ms of latency from my computer to the TNserver.exe I put on a cloud) and that is why I know I am not doing it right. Ideally I'd just have clients network create a bomb, and since I know when it will always explode, just have clients do the logic themselves and create the effects, and destroy the bombs and objects locally themselves. The thing is I need all the bombs to be present when players join (syncing the explosion times would be easy all I would have to do is within the coroutine just check and decrement the timer every frame and when players join, use OnNetworkPlayerJoin() to sync the timer, which I already do to keep track of the bomb timers in a GUI).

5
TNet 3 Support / Re: Syncronizing Players And Intialization
« on: June 01, 2014, 03:21:10 AM »
Managed to more or less fix it by creating an additional invisible object that creates a player avatar (this object is created after the level is randomized, it is the last to be created. It is created by the host player, therefore host player also uses it. My problem is Create() and Send()s are not syncronized with each other so I changed the Send() to Create() and this basically fixed it.

I could probably do this with RFC's Send() by not using Create() to create the randomized level environment objects, but I realize that Create() takes care of ownership for me so I just focused on making that work for me since I would not know how to handle it otherwise. Anyway, is my way of doing this inefficient or wrong? Is it also okay for all objects created after the level is loaded to be a TNObject (I have a lot of them because they are placeholder cubes and make up the randomized game objects in the level)?

Also, speaking of ownership, I want to keep track of the order in which players enter and leave the room (so I can do some stuff like assigning spawn areas). I was thinking of using a dictionary or class to keep track of the information but I am not sure how I am going to synchronize this one. Maybe I will have the host create and take care of it but then I am not sure how to keep it in sync if the host leaves. How should I approach this?

My logic of ownership is not great as you can see. Just one more thing, since I do not want to clutter the forum with more threads, and I feel it's the same topic as the above two questions. I also want critique on my logic of ownership with projectile weapons. Currently, my way is a player creates the projectile when he presses the fire button, so ownership is his at this point (tno.isMine). If it collides with an obstacle, it destroys it and itself (obstacles are owned by host) and the obstacles may drops items if they are marked to do so. The items dropped are owned by the projectile's owner that destroyed them (again using tno.isMine). Finally when a player goes near and picksup/collides with the item, it calls TNManager.Destroy() on it. Is this way of doing it okay? I notice if I use TNManager.isHosting the results appear to be the same, but I think with actual lag conditions and not just testing it on my computer would show different results.

6
TNet 3 Support / Re: Syncronizing Players And Intialization
« on: May 31, 2014, 08:10:58 PM »
Hi Aren, the reason I didn't do it in OnNetworkJoinChannel() was because I am reloading the scene within the game. If I do it within OnNetworkJoinChannel(), it only executes once. Also, I need to be checking when there are 2 more players ready to play before simply creating the player's avatars right away.  I tried polling for that by checking when the TNManager.players list became populated and then sending calls to the players to create the avatars but it is very buggy the way I did it which I posted in the OP.

7
TNet 3 Support / Syncronizing Players And Intialization
« on: May 30, 2014, 12:29:31 AM »
Hi, I want to know how I can synchronize Players in the order they join, and when the level is done "loading". That is, after the level is loaded, the play field is randomized in Start(), like so:

  1.         public void Start()
  2.         {
  3.                 if (!TNManager.isHosting) return;
  4.  
  5.                 for (int row = 0; row < numberOfRows; row++)
  6.                 {
  7.                         for (int col = 0; col < numberOfColumns; col++)
  8.                         {
  9.                                 if(Random.value > 0.9) TNManager.Create(blockObject, new Vector3(row,0,col), Quaternion.identity);
  10.                         }
  11.                 }
  12.  
  13.                 StartCoroutine(PlayerWaitSpawn() );
  14.         }
  15.  

Cut the down code to what it is essentially like, it creates a random playing field each time the level is loaded. So that works fine. However, I do not know how to synchronize players properly. The two conditions I need fulfilled are

1) Wait for at least 2 players to be in the channel/level
2) Also, wait for the level to completely load, that is after the Create() functions called in Start() finish appearing for other clients

In the coroutine I start after calling the Create() functions in Start(), I tried a few things, with the closest resembling any form of success being:

First yield waits continually until TNManager.players.Count is greater than 0 (Why does this not include the host player by the way?)
Next, Spawn the host's player character (since the coroutine was called from Start() where the check ensures only the host player is doing logic, it does not create multiple characters from other clients)
Finally, in a loop, for each player send them an RFC telling them to Create() their player (So they have ownership. On a side note I spawn them in certain locations according to the order of the TNManger.players list, but this is only to simulate what I want to do mentioned further below. It won't well once players leave the level/channel in the middle of a game)

However, this does not really work well as sometimes the RFC reaches the client faster than the Create() calls from Start() apparently as the player will fall through the floor when it happens. Also, upon joining for the first time, clients do not spawn their players ever, only the host player does. The level must be reloaded via TNManager.LoadLevel() for clients to spawn players this way, and not sure why. I am not using SendQuickly() either, as it is important that the message sent be received. Note sure why I didn't just post it but here it is

  1.         IEnumerator PlayerWaitSpawn()
  2.         {
  3.                 while (TNManager.players.Count == 0)
  4.                 {
  5.                         yield return new WaitForSeconds(1f);
  6.                 }
  7.  
  8.                 if (TNManager.isHosting)
  9.                 {
  10.                         TNManager.Create(playerObject, new Vector3(0f ,0f, 0f), Quaternion.identity, false);
  11.                 }
  12.  
  13.                 int lastPlayerID = 0;
  14.                 foreach (Player p in TNManager.players)
  15.                 {
  16.                         //if (p.id > lastPlayerID) {StaticPlayerIDsDict.Add(lastPlayerID,true);}
  17.                         //if (StaticPlayersIDsDict[p.id]) ...
  18.                        
  19.                         lastPlayerID += 1;
  20.                        
  21.                         switch(lastPlayerID)
  22.                         {
  23.                                 case 1:
  24.                                 tno.Send(99, p, new Vector3(numberOfRows, 0f, 0f) );
  25.                                 break;
  26.                                 case 2:
  27.                                 tno.Send(99, p, new Vector3(numberOfRows/2, 0f, numberOfColumns) );
  28.                                 break;
  29.                                 case 3:
  30.                                 tno.Send(99, p, new Vector3(0f,0f,numberOfColumns/2) );
  31.                                 break;
  32.                                 //etc.. will finish later
  33.                         }
  34.                 }
  35.         }
  36.        
  37.         [RFC(99)]
  38.         void PersonalCreate(Vector3 vector)
  39.         {
  40.                 TNManager.Create(playerObject, vector, Quaternion.identity, false);
  41.         }
  42.  

Finally, if I get the above solved, I need to spawn players in the order they joined the channel/level (so I can spawn them in proper positions on the map, ie. the player that has second place in the room always spawns in the upper middle section of the map), and if they leave, a player must take their place (such as 2nd place of 8 players if first place, and third-eighth place is taken). I figure I could do something with the Player.id and compare the ids in the TNManager.players list and add them to a dictionary in order or something but then I don't know how to synchronize this properly or if it would even work for organizing players spawning like this.

8
I figured as much. I will work on it as I develop further.

Thank you, Aren.

9
Hi Aren,

I think I'm not understanding it, for example I have,
  1. using UnityEngine;
  2. using System.Collections;
  3. using TNet;
  4.  
  5. [RequireComponent(typeof(TNObject))]
  6. public class TestingSync : TNBehaviour {
  7.  
  8.         private int someStat = 1;
  9.  
  10.         void FixedUpdate()
  11.         {
  12.                 someStat += 1;
  13.         }
  14.  
  15.         void OnNetworkPlayerJoin(Player p)
  16.         {
  17.                 Debug.Log (p+"has joined");
  18.                 if (TNManager.isHosting)
  19.                 {
  20.                         tno.Send(1, p ,this.someStat);
  21.                 }
  22.         }
  23.  
  24.         [RFC(1)]
  25.         void SyncStat(int sentStat)
  26.         {
  27.                 this.someStat = sentStat;
  28.         }
  29.  
  30.         void OnGUI()
  31.         {
  32.                 GUILayout.Label("SOMESTAT: "+someStat, myStyle);
  33.         }
  34. }
  35.  

I chose FixedUpdate() because I know it updates fixed amount of times per second (currently other player's someStat is behind host player's someStat as I would expect). don't I have to compensate for the time the message takes to reach the other player? I understand of course for things like transform.position of a player controlled object may only be predicted (hence interpolation/extrapolation done in all games for movement variables such as that) however this can and should probably be the exact same for everyone because the output should always be deterministic. I think I need to subtract the time spent between the message received and sent and divide by the fixed delta time to get the amount of frames that has gone by the time the new player receives the message but somehow I don't think that is right either. I am probably doing something wrong already by using FixedUpdate() as a test or something else is wrong with my script.

Can I ask how you are synchronizing time for your day/night cycle (won't it be slightly off for everyone if you are sending a lot of different variables too, for example the wind variables)? Perhaps a snippet of code so I can understand better by reading it. thanks.



10
TNet 3 Support / Re: Preventing Cheating
« on: May 09, 2014, 01:34:15 AM »
Thank you for the informative reply, Max. I understand that cheating can not be eliminated, I just want to prevent it as much as possible via server authoritative setup. However, my confusion stems from not knowing how to set one up, especially in TNet, and seeing, reading, and studying about server authoritative setups. I read that some people easily setup a server authoritative setup with TNet and then some say it's not possible.

I also understand that I should not go for a complex solution right off the bat. That's not why I got TNet originally for anyway. However, I want to start with something simple so I can understand how to start building off it in case I actually do make a somewhat playable or even fun game instead of having to build scratch all over again if it happens, and honestly this is really bugging so much that I can not move on so it giving me headaches now. I thought I would start with a simple setup for movement where clients send input to one entity, and that entity processes the input and sends it back to the clients like some photon tutorial I read. It didn't really work out very well as I only got the clients to move somewhat okay but when the host client moves none of the clients see it moving. I might be able to fix it if I put more time into but, I don't even know if I am really doing it "right" (putting all this logic in one script).

I can understand the logic of what you said, and to use
(!TNManager.ishosting)
return;

for example to dictate that only the host client should be processing the input sent. However, what I don't understand, should I be doing this within one script, in Unity? For example, a movement script with the (!TNManager.ishosting) logic included in it? Would that be enough to do what I want, deter cheaters? Won't the host client also be able to still cheat though? Or am I misunderstanding and this logic somehow goes in the the code for the TNServer.exe (ServerMain.cs)? If it is not asking too much, perhaps a very, very simple example would be nice.

11
TNet 3 Support / Re: Preventing Cheating
« on: May 03, 2014, 02:01:44 AM »
the best way to protect the games and easy to implement, it is using anti-cheat toolkit (search in the asset store). This solition is in the user side, to implement some server side protection you need to make yourself.

I've actually checked it out before. It doesn't seem like a long-term solution which is what I'm looking for. At best it deters some novices with Cheat Engine that are curious.

12
TNet 3 Support / Preventing Cheating
« on: May 02, 2014, 10:11:16 PM »
Hi, TNet forum and Aren.

I was wondering, how do I prevent cheating with TNet? I won't pretend I know a lot about networking or setups. I have used Unity's default networking and Photon to create some tests but TNet seems much better. For example when I use interpolation techniques to smooth out clients movements and animations in player's views, no matter what I did, TNet's examples still were way smoother even with my best techniques. So it seems I have a lot to learn and I will settle with what I know for now. And so I was reading the forum for threads about server setups and mainly, to prevent cheating, but I don't quite understand.

At first I saw that you do not recommend setting up an authoritative server setup as opposed to default authoritative host setup that TNet is. But then I also read that other people are trying to do the former or something similar but even after several threads I haven't pieced enough information to understand. I realize that to do an authoritative server setup, I would need something like the Photon Server where I write server side code and lobby and put that on the server, then clients connect to the Photon server and request to start rooms. Logic is then handled by clients sending requests to the server and performing prediction on clients to make them seem smooth with the responses coming from the server correcting mistakes/also preventing cheating. To do that with TNet I would have to create a game instance with each request to create a room/channel so the game instance in the server would be authoritative instead of any of the clients as the first creator is the authoritative host, but this is not feasible even with a few dozen concurrent players in a day. I'm not sure if that is even possible.

And as far as I know, with a client authoritative setup, the host client may be a cheater. If so he can just do whatever he wants, manipulate players, inflate scores to be sent, etc. especially if there are only 2 players in one room any checks would be impossible against the host player anyway. To be honest, I am not making an MMORPG or something super complicated like that,  however I plan to have a multiplayer only game, similar to MOBAs, but much simpler with 2 to 8 players in one room(channel) with many games/rooms going on at one time. I want to keep persistent scores, statuses, etc., so cheating is something that must absolutely be dealt with as soon as possible and I it would take a great burden off I know how to build with it in mind. Ideally I'd like to have one server (or do I need a cloud service? Amazon EC2 maybe?) that handles the lobby and game logic and have users request to create rooms on that (would also get TNet to work on webplayer). But again, I do not know how this works and I don't think it's even possible and I'm just being naive.

So, sorry for the tl;dr but how should I approach cheating with TNet and build around that? I realize I kept going on and on but I'm not sure what I needed to elaborate on to sound clear. If there is something I should be more clear please tell me.

Pages: [1]