Noticias

¡RECUERDA QUE SI ERES UN NUEVO USUARIO, DEBES PRESENTARTE PARA PODER PUBLICAR MENSAJES! | TENEMOS CANAL OFICIAL DE TELEGRAM: t.me/unity3dspain

networkbehaviour!!!

Iniciado por Kvashir, Junio 25, 2018, 06:16:03 PM

Tema anterior - Siguiente tema
Saludos gente, hace tiempo que no me pasaba por aquí falta de tiempo libre, pero ahora eh vueeeelto ! 
 
Estoy haciendo un "proyecto" en unity conectando unity a un servidor JAVA (eso lo eh conseguido)
 
el problema que tengo es que los datos llegan al servidor y del servidor llega a todos los clientes
 
los clientes reciben los datos, pero algunos clientes mueven a todos los jugadores otros no y otros no aparecen ni el propio player de ese cliente

 
 

 
creo que es un problema con el cliente unity y no con el servidor java, eh probado locks para bloquear el acceso a funciones cuando esten en uso por otro proceso y falla menos pero sigue con errores (en el servidor java eh usado synchronized)
 
de momento estoy revisando los scripts c# me parece que el fallo está ahi porque reciben información del servidor.

Mi duda es, alguien a intentado algo así?? 
 
se puede usar networkbehaviour para servidores java?? 
 
siempre que busco información para un mmo en unity todos y cada uno saltan con la genial idea de usar un cliente unity como servidor utilizando esas librerias, algo que no me parece muy eficiente del lado del servidor O-o

Cita de: Kvashir date=1529943363Saludos gente, hace tiempo que no me pasaba por aquí falta de tiempo libre, pero ahora eh vueeeelto ! 
   
   
      Estoy haciendo un "proyecto" en unity conectando unity a un servidor JAVA (eso lo eh conseguido)
   
   
      el problema que tengo es que los datos llegan al servidor y del servidor llega a todos los clientes
   
   
      los clientes reciben los datos, pero algunos clientes mueven a todos los jugadores otros no y otros no aparecen ni el propio player de ese cliente

       
   
   
      
   
   
      creo que es un problema con el cliente unity y no con el servidor java, eh probado locks para bloquear el acceso a funciones cuando esten en uso por otro proceso y falla menos pero sigue con errores (en el servidor java eh usado synchronized)
   
   
      de momento estoy revisando los scripts c# me parece que el fallo está ahi porque reciben información del servidor.

      Mi duda es, alguien a intentado algo así?? 
   
   
      se puede usar networkbehaviour para servidores java?? 
   
   
      siempre que busco información para un mmo en unity todos y cada uno saltan con la genial idea de usar un cliente unity como servidor utilizando esas librerias, algo que no me parece muy eficiente del lado del servidor O-o
   


Del lado del servidor, ¿necesitas utilizar alguna función de Unity? si es así entonces vas a tener que utilizar una librería que se integre en Unity, esto podrias hacerlo utilizando Unet u otros servicios tipo Photon, tambien puedes armar tu librería utilizando Sockets.
 
Si el servidor no requiere ninguna funcionalidad de Unity entonces requerirá crear una librería backend y otra frontend - 
 
¡- Pero de ningún modo podrias utilizar NetworkBehaviour fuera de Unet -!
 
Tu problema puntualmente es un problema de TAG de paquetes, o Relay, cuando un cliente envia un paquete al servidor es siempre requiriendo una acción o un dato cuando el servidor envia un dato a los clientes siempre se trata de un "SET" entonces podes crear un sistema que te identifique con TAG el tipo de paquetes 
 
Tipos: COMMAND, GET, SET

Propietario: OWNER, REMOTE, ROOT (Servidor)
 
- De ese modo sabias que paquete proviene de un RELAY o RPC -
 
Internamente esto funciona debido a que cada cliente se conecta al servidor, el servidor debe crear un ID asociado con el ENDPOINT del cliente para poder enviarle datos luego y lógicamente identificarlo, cada paquete que el servidor recibe sabe de qué cliente se trata, un ejemplo el inicio de sesión, podrias descartar todos los mensajes de X cliente si X cliente no está dentro de la lista de las sesiones abiertas -
 
La única entidad que controla los ID es el servidor, por lo que si un "man-in-the-middle" altera la información saltando lógicamente la encriptación el servidor podria descartar dicho mensaje -
 
 
 
 

el tema de identificar a los clientes en el servidor esta echo, lo de man in the middle olvídate, mas a delante se como poner seguridad en ese punto. 

lo de unet me parece muy interesante y lo de photon también, si puedo utilizar librerías de unity en el servidor puede que lo investigue mas que nada para ver si puedo usar funciones para la IA del juego. (no es un juego, estoy probando "piezas" sueltas sin tener ningún proyecto claro en mente, para trastear como muchos :P)
 
no se con que comunicarías tu el cliente con el servidor pero yo uso JSON me parece lo mas cómodo aunque si tenéis alguna idea mejor me gustaría escucharla :D, lo del tag ya lo pensé pero para otros propósitos como meter en el string de json que es ese json y después poder mover el objeto al constructor que quiera o hacer X jeje.
 
y bueno dicho esto, voy a investigar eso que me dijiste, muchas gracias por responder :D

 
 
PD: alguien a echo algo parecido? o intentar hacer un servidor  "a mano" como el que estoy haciendo?
 
ya hablando de bases de datos, hace tiempo realice un proyecto que conectaba a mysql pero estoy pensando en hacer una bbdd con mongodb, me parece mas ágil para este tipo de proyectos
 

   void readData()
    {
        if (stream.CanRead)
        {
            try
            {
               
                byte[] bLen = new Byte[4];
                int data = stream.Read(bLen, 0, 4);
                if (data > 0)
                {
                    int len = BitConverter.ToInt32(bLen, 0);
                    print("len = " + len);
                    Byte[] buff = new byte[1024];
                    data = stream.Read(buff, 0, len);
                    if (data > 0)
                    {
                        print("aaaaaaaaaquiii");
                        string result = Encoding.ASCII.GetString(buff, 0, data);
                        print(result);
                        stream.Flush();
                        parseData(result);
                    }
                }
            }
            catch (Exception ex)
            {
                ex.ToString();
            }
        }
    }

 
casi se me olvida, tanto en el cliente como en el servidor uso en el caso de C# "NetworkStream stream;"

esta es la funcion en unity para leer el packete que le llega del servidor, peeeeeero muchas veces no entra en el if(data >0) aunque tenga datos ¬¬

tengo una duda existencial 
 

           lock (this)
            {
                t.Moviment(transform.position, transform.rotation);
            }

 
esto a mi entender bloquea la clase o bloquea lo que hay dentro de los { } ??

Yo entiendo que eso bloquea el objeto instanciado(POO) de esa Clase, el cual está asignado como componente a un GameObject.

es que en java es diferente y bloquea solo lo que tiene dentro, me pregunto si hay algo así en c# o a la fuerza bloquea el objeto entero...

Julio 07, 2018, 02:25:08 AM #6 Ultima modificación: Julio 07, 2018, 02:38:03 AM por francoe1
Lock bloquea el objeto para que este no sufra cambios en tiempo de ejecución de tareas paralelas -
 
Por ejemplo, si quieres modificar una lista desde 2 tareas a la misma vez dependiendo del contexto de ejecución te va a dar un error, o vas a ocasionar que el procesador no pueda trabajar como debería (EN BLOQUE) -
 
Cuando estás programando una clase networking necesitas controlar todo desde un hilo único, pero el problema de esto es que los SOCKETS trabajan en bloque, quiere decir que la ejecución se detiene hasta que haya una actualización, para solucionar este problema los Sockets se ejecutan en otro hilo, pero esto trae otro problema, "Modificación de objetos por procesos diferentes", lo que en un 90% te va a dar un error fatal -
 
Entonces que se hace .... una técnica llamada (Push and Pop) - todos los mensajes recibidos se insertan en una lista, y luego se quitan con cada actualización del hilo principal -
 

public class Server
{
    private object lockObj = new object();
    public delegate void OnReadDelegate(byte[] bytes);
    private Stack<byte[]> _stackReceiver = new Stack<byte[]>();
    private void handleReceiver(byte[] bytes)
    {
        lock(lockObj)
        {
            _stackReceiver.Push(bytes)
        }
    }
    public void ReadMessages(OnReadDelegate callbackRead)
    {
        lock(lockObj)
        {
            while(_stackReceiver.Count > 0)
                callbackRead.Invoke(_stackReceiver.Pop());
        }
    }
}

 
¿Por qué se utiliza un object para el lockeo? por que de usar el stack estaríamos desperdiciando memoria y dependiendo del tamaño del stack tendríamos una pérdida de rendimiento considerable.
 
En el ejemplo puedes ver cómo handleReceiver bloquea el objeto, porque va a modificar _stackRecevier aca se genera un "Semáforo" entonces hasta que la invokación no finaliza el objeto lockObj sigue bloqueado,  a su vez el objeto tambien se bloquea cuando se utiliza ReadMessages justamente para el mismo propósito -
 
Ahora para cualquier modificación en _stackRecevier se debe utilizar lock(lockObj) .- si utilizas lock(this) estas bloqueando todo el objeto y es una practica malisima -
 
 
 
Espero que se haya entendido, esto es más fácil explicarlo hablado que escrito.
 
 
 
Para terminar -
 
handleReceiver se llama desde el hilo que trabaja con Sockets - 
 
ReadMessage(callback) se llama desde una función Update de Unity <<< Ejemplo ---
 
 ------------------------------------
 
En cuanto al método para armar los mensajes lo más práctico es trabajar con bytes, puedes crearte una clase que trabaje con BinaryWriter y BinaryReader, luego creas una clase base para los paquetes que tenga una función virtual para escribir y leer - por ejemplo - 
 

public class NetMsg
{
    public int MessageId { get; internal set; }
   
    internal void Write(BinaryWriter writer)
    {
        writer.Write(MessageId);
        OnSerialize(writer);
    }
    internal void Read(BinaryReader reader)
    {
        MessageId = reader.ReadInt32();
        OnDeserialize(reader);
    }
    protected virtual void OnSerialize(BinaryWriter writer){}
    protected virtual void OnDeserialize(BinaryReader reader){}
}
public class PlayerPositionNetMsg : NetMsg
{
    public Vector3 Data { get; set; }
    protected override void OnSerialize(BinaryWriter writer)
    {
        writer.Write(Data.x);
        writer.Write(Data.y);
        writer.Write(Data.z);
    }
    protected override void OnDeserialize(BinaryReader reader)
    {
        float x = reader.ReadSingle();
        float y = reader.ReadSingle();
        float z = reader.ReadSingle();
        Data = new Vector3(x, y, z);
       
        //o de una manera mas comprimida        
        Data = new Vector3(
            reader.ReadSingle(),
            reader.ReadSingle(),
            reader.ReadSingle()
        );
    }
}

 
  -------------------------------> 

muchas gracias por las respuestas, 

quizás el problema es que no eh compartido todo el proyecto y me eh explicado a medias ya que solo pregunto cosas en concreto y no todo el código de cliente y servidor.
 
lo que tiene bien mi proyecto por ahora es:
 
-los clientes conectan al servidor JAVA

-el servidor JAVA ya manda de forma correcta al resto de clientes la información. 
 
-los clientes ya reciben y interpretan correctamente cada tipo de mensaje recibido por el servidor. 
 
 
 
Indico nuevamente que no estoy utilizando una clase de networking en UNITY porque el servidor es java. 
 
los clientes se comunican con el servidor JAVA con JSON.
 
Desde que empecé, eh modificado el código tanto del cliente como del servidor, haciendo pruebas y extrapolando ideas que me han generado vuestras respuestas
 
la verdad se agradece muchísimo la ayuda! 
 
@francoe1 
 
ya mire algo de UNET y PHOTON, seguire probando con java y programando desde 0 todo, ya que mi proyecto no es para hacer un juego, mas bien es para aprender y probar 
 
de todas formas me han parecido bastante interesante y seguramente pueda sacar información de ahí para programar mas :P 
 
 
 
@pioj
 
gracias por estar siempre por aquí activo en el foro y ayudar :)
 
 
 
**********************************************************************
 
Ahora mismo el problema que tengo es:
 
si tengo 3 clientes activos. se mueven y se ven con 0 lag
 
el problema es cuando colisionan 2, esos 2 se ben bien entre ellos pero el tercero ve a esos 2 con lag.
 
lo que ocurre en el código es: 
 
-el primero se mueve arrastrando al segundo - (el primero manda su posición al servidor)
 
-el segundo al ser empujado manda al servidor su posición actual cada vez que es modificada
 
-el tercero los ve con lag pero el movimiento se genera correctamente. 
 
 
 
lo que creo que está ocurriendo es que el tercero está recibiendo los dos movimientos a la vez constantemente y tarda en calcular todo eso. 
 
creo que es justo lo que me indicaste @francoe1 que hay que usar stack, tendré que buscar sobre eso o quizás probar de generar coroutines
 
alguna idea? :P
 
 
 
 

no tengo ni idea de networking....
 
pero... puedes mandar los mensajes en LateUpdate? LateUpdate se ejecuta despues de las fisicas... con lo cual estarian las posiciones ya previamente calculadas... no se si servira... y no se si puede hacer...

A ver .... lo que yo te explique arriba se trata de la integración del "NÚCLEO" de tu librería -.
 
¿Con que estas trabajando UDP o TCP? -
 
TCP funcionaria desde un primer punto, pero luego ocasiona problemas por sus algoritmos de seguridad de transferencia, si implementas UDP puedes tener pérdida, alterados, duplicados de paquetes para solucionar esto se puede implementar un técnica de "UDP RELIABLE" - 
 
En la capa de envío tanto del servidor como del cliente tienes que contar con diferentes tipos de mensajes, por ejemplo, en envío de posiciones debería ser un paquete no seguro pero ordenado, esto quiere decir que el receptor solo recibe paquetes con un DATE o ID más alto que el anterior y a los otros los descarta << esto genera pérdida de paquetes, pero a la misma vez te asegura de estar o intentar estar en el último estado.
 
----
 
Creo que el problema en tu proyecto es que estás permitiendo que los usuarios decidan sus propias posiciones, es decir, el servidor no puede calcular las posiciones por que no tiene una simulación del mundo en el que se está jugando, si piensas hacer un FPS esto te podría traer problemas con absolutamente todo, por eso te pregunte si tu juego iba a utilizar algún componente de UNITY, es decir Rigidbody, RayCast, Etc... 
 
También, te recomiendo no trabajar 2 lenguajes diferentes, si vas a programar solo, podrias diseñar tu servidor en C#, podrias crear una librería y luego desde unity crear la capa para el servidor, el cliente y el servidor utilizar el mismo core, las mismas estructuras, por lo que no tendrías que tener problemas para esto -

Julio 08, 2018, 06:11:30 PM #10 Ultima modificación: Julio 08, 2018, 06:11:58 PM por Kvashir
 holas ! @francoe1 todos los movimientos que recibe el servidor son correctos y los envia a todos los clientes correctamente, el problema es que a los clientes les cuesta calcular todo, es como si se les acomulase el trabajo pero al final lo calculan todo correcto
Cita de: francoe1 date=1530990877A ver .... lo que yo te explique arriba se trata de la integración del "NÚCLEO" de tu librería -.
   
   
      ¿Con que estas trabajando UDP o TCP? -
   
   
      TCP funcionaria desde un primer punto, pero luego ocasiona problemas por sus algoritmos de seguridad de transferencia, si implementas UDP puedes tener pérdida, alterados, duplicados de paquetes para solucionar esto se puede implementar un técnica de "UDP RELIABLE" - 
   
   
      En la capa de envío tanto del servidor como del cliente tienes que contar con diferentes tipos de mensajes, por ejemplo, en envío de posiciones debería ser un paquete no seguro pero ordenado, esto quiere decir que el receptor solo recibe paquetes con un DATE o ID más alto que el anterior y a los otros los descarta << esto genera pérdida de paquetes, pero a la misma vez te asegura de estar o intentar estar en el último estado.
   
   
      ----
   
   
      Creo que el problema en tu proyecto es que estás permitiendo que los usuarios decidan sus propias posiciones, es decir, el servidor no puede calcular las posiciones por que no tiene una simulación del mundo en el que se está jugando, si piensas hacer un FPS esto te podría traer problemas con absolutamente todo, por eso te pregunte si tu juego iba a utilizar algún componente de UNITY, es decir Rigidbody, RayCast, Etc... 
   
   
      También, te recomiendo no trabajar 2 lenguajes diferentes, si vas a programar solo, podrias diseñar tu servidor en C#, podrias crear una librería y luego desde unity crear la capa para el servidor, el cliente y el servidor utilizar el mismo core, las mismas estructuras, por lo que no tendrías que tener problemas para esto -
   


estoy utilizando TCP, pro el momento no pierdo paquetes, lo que ocurre es que los clientes tardan en calcular los datos,

en esta práctica que estoy haciendo no importa tanto que el servidor tenga conocimiento del "mundo" que tienen los clientes, ya que los propios clientes gestionan eso con unity y unity le dice al servidor lo que hay (por así decirlo)
 
entiendo que lo que dará problemas es en el caso de querer controlar un NPC y que este se comporte igual en todos los clientes, pero no estoy abordado ese caso por el momento.
 
no es ningún juego solo es un proyecto para probar y aprender, por eso quiero hacerlo en JAVA el servidor.
 
 
 
el problema que tengo no es de recepción de paquetes (estoy comprobando los paquetes que llegan y reciben tanto el servidor como los clientes y son correctos el 100% de las veces)
 
el problema es que los clientes "colapsan" al recibir tantos mensajes o esa es la sensación que me dá. 
 
por eso dije de usar coroutine.
 
seguiré probando mis locuras, os mantendré informados :P

Cita de: Kvashir date=1531066290 holas ! @francoe1 todos los movimientos que recibe el servidor son correctos y los envia a todos los clientes correctamente, el problema es que a los clientes les cuesta calcular todo, es como si se les acomulase el trabajo pero al final lo calculan todo correcto
   
   
      estoy utilizando TCP, pro el momento no pierdo paquetes, lo que ocurre es que los clientes tardan en calcular los datos,

      en esta práctica que estoy haciendo no importa tanto que el servidor tenga conocimiento del "mundo" que tienen los clientes, ya que los propios clientes gestionan eso con unity y unity le dice al servidor lo que hay (por así decirlo)
   
   
      entiendo que lo que dará problemas es en el caso de querer controlar un NPC y que este se comporte igual en todos los clientes, pero no estoy abordado ese caso por el momento.
   
   
      no es ningún juego solo es un proyecto para probar y aprender, por eso quiero hacerlo en JAVA el servidor.
   
   
       
   
   
      el problema que tengo no es de recepción de paquetes (estoy comprobando los paquetes que llegan y reciben tanto el servidor como los clientes y son correctos el 100% de las veces)
   
   
      el problema es que los clientes "colapsan" al recibir tantos mensajes o esa es la sensación que me dá. 
   
   
      por eso dije de usar coroutine.
   
   
      seguiré probando mis locuras, os mantendré informados :P
   


1º - Utilizar un servidor sin la simulación no solo causa problemas con los NPC si no, que el propio servidor desconoce el escenario y sus mecánicas.
 
2º - Una corrutina en lo absoluto solucionaria tu problema ya que esta se llama desde el mismo hilo de ejecución del juego.
 
3º - Creía que el error es "BUFFER OUT" esto se ocasiona porque no estás trabajando correctamente los mensajes, ¿tienes alguna forma de identificar cada mensaje? para por ejemplo en el caso de la posición evitar mantener en buffer aquellos que son más antiguos que el actual, y solo interpolar la posición actual con el último estado.
 
Por otro lado, replantea utilizar JSON, ya que vas a necesitar un "WRAPPER" para la des/serialización de los objetos lo cual es muy costoso, tambien para leer algunos datos vas a necesitar deserializar el objeto completo lo que es una perdida de tiempo inmensa - 
 
Paso a explicarte que contiene un mensaje -
 


  1.    ID


  2.    Secuencia


  3.    N_Secuencia


  4.    Owner


  5.    Length


  6.    Tag


  7.    Data


Esa sería la estructura base de cada paquete, gracias a la herencia puedes conmutar dos paquetes para crear un personalizado. 
 
Ahora si recibo un paquete ya tengo identificados cuantos campos debo leer - en total son 6, pero sin ningún tipo de costo para el procesador ya que simplemente casteo un valor binary a objeto lo cual es un 99% menos costoso que cualquier WRAPPER que requiere expresiones regulares, etc..
 
- ¿Se entiende? - 
 
"NO utilices CORRUTINAS" <<< ES LO MÁS CONTRAPRODUCENTE para este tipo de implementación.

yo seguiré dándole cabezazos a esto, eh pensado otra manera, 
 
@francoe1, repito esto es para testear, no para hacer algo viable 100%
 
y estoy haciendo esto porque por internet nadie a intentado esto.. o al menos no lo eh encontrado.
 
por ejemplo haciendo estas pruebas me planteo dudas nuevas con la cuales aprendo mas sobre esto y el porque las cosas son de una manera y no de otra.
 
 

Cita de: Kvashir date=1531171828yo seguiré dándole cabezazos a esto, eh pensado otra manera, 
   
   
      @francoe1, repito esto es para testear, no para hacer algo viable 100%
   
   
      y estoy haciendo esto porque por internet nadie a intentado esto.. o al menos no lo eh encontrado.
   
   
      por ejemplo haciendo estas pruebas me planteo dudas nuevas con la cuales aprendo mas sobre esto y el porque las cosas son de una manera y no de otra.
   
   
       
   


Yo te estoy invitando a evitar errores que pueden frustrarse por meses -
 
El Networking tiene una complejidad en 3 puntos - OPTIMIZACIÓN - SEGURIDAD - SERIALIZACIÓN si de inicio aprendes mal esto todo tu futuro arrastrara las malas prácticas, en NETWORKING hay muchísima información, lo que no existe es la adaptación a un proyecto, debido a que esto es algo propio de cada uno -
 
Creo que antes de ponerte a trastear con UNITY deberias de centrarte en C# y crear proyectos en consola para el testear, definir qué capa cubre qué responsabilidades, y luego empezar -
 
Por ejemplo - 
 
NetDebug > NetCore > NetPeer > NetConn > NetWrapper > NetSerialize  > NetCrypto > NetCatch
 
Te paso un canal, que desde mi punto personal aún está en un nivel bajo pero está bastante bien encaminado -.
 


   
eature=oembed" width="480">

 
Visita su canal tiene muchos videos de intentos que nunca llegan a algo en concreto pero en el proceso explica algunas cosas bastante bien.

investigando y dándome cabezazos con todo esto, eh encontrado algo interesante de unity 
 
pues parece ser que porfin han implementado threads en unity llamados "jobs" a mi entender es lo mismo que los hilos pero se puede usar la api de unity O_o alguien a trasteado con eso? 

Etiquetas: