Differences

This shows you the differences between two versions of the page.

Link to this comparison view

pjv:laboratoare:2025:a05 [2025/12/10 11:54]
alexandru.gradinaru
pjv:laboratoare:2025:a05 [2025/12/10 12:46] (current)
alexandru.gradinaru [Cerinte]
Line 32: Line 32:
 ==== Cerinte ===== ==== Cerinte =====
  
-Realizarea unui joc multiplayer de tip social:+Realizarea unui joc multiplayer de tip social, prin folosirea/​implementarea unui server multiplayer dedicat: 
 + 
 + 
 +  * Player avatar sincronizat la nivel de pozitie si animatii: minim 2 playeri/​clienti 
 +  * Comunicare chat cu interfata grafica 
  
-<​hidden>​ 
-  * Player avatar sincronizat la nivel de pozitie si animatii 
-  * Comunicare chat sau voice 
-  * Server multiplayer dedicat, implementare proprie 
-</​hidden>​ 
  
    
Line 45: Line 45:
  
 ===== Documentatie text ====== ===== Documentatie text ======
 +
 +Pentru acest laborator vom folosi [[https://​github.com/​DarkRiftNetworking/​DarkRift|DarkRift 2]], un server dedicat, modular, care implementeaza protocoale de comunicare ca TCP, UDP, dar si cu extensii pentru WebSocket sau RUDP.
 +Pentru integrarea cu Unity, se poate folosi pachetul din Asset Store [[https://​assetstore.unity.com/​packages/​tools/​network/​darkrift-networking-2-95309|DarkRift Networking 2]]
  
 ==== Server dedicat ===== ==== Server dedicat =====
  
-[[https://​github.com/​DarkRiftNetworking/​DarkRift|DarkRift 2]] este un server dedicat, modular, care implementeaza protocoale de comunicare ca TCP, UDP, dar si cu extensii pentru WebSocket sau RUDP. 
-Pentru integrarea cu Unity, se poate folosi pachetul din Asset Store [[https://​assetstore.unity.com/​packages/​tools/​network/​darkrift-networking-2-95309|DarkRift Networking 2]] 
  
 Folosind un server dedicat trebuie gestionate mai multe elemente: Folosind un server dedicat trebuie gestionate mai multe elemente:
Line 56: Line 57:
   * mesajele de update   * mesajele de update
  
-DarkRift foloseste un sistem modular, bazat pe plugin-uri C#, pentru ​implementarea serverului+DarkRift foloseste un sistem modular, ​astfel ca puteti programa mecanica serverului fie direct, fie bazat pe plugin-uri C#, pentru ​a nu recompila la fiecare modificare tot serverul
-Astfel, putem defini un plugin in felul urmator:+ 
 +Exemplu minimal: 
 <​code>​ <​code>​
 +using DarkRift;
 +using DarkRift.Server;​
 +
 +ServerSpawnData spawnData = ServerSpawnData.CreateFromXml("​Server.config"​);​
 +
 +var server = new DarkRiftServer(spawnData);​
 +
 +void Client_MessageReceived(object?​ sender, MessageReceivedEventArgs e)
 +{
 +    using Message message = e.GetMessage();​
 +    using DarkRiftReader reader = message.GetReader();​
 +    Console.WriteLine("​Received a message from the client: " + reader.ReadString());​
 +}
 +
 +void ClientManager_ClientConnected(object?​ sender, ClientConnectedEventArgs e)
 +{
 +    e.Client.MessageReceived += Client_MessageReceived;​
 +
 +    using DarkRiftWriter writer = DarkRiftWriter.Create();​
 +    writer.Write("​World of Hel!"​);​
 +
 +    using Message secretMessage = Message.Create(666,​ writer);
 +    e.Client.SendMessage(secretMessage,​ SendMode.Reliable);​
 +}
 +
 +server.ClientManager.ClientConnected += ClientManager_ClientConnected;​
 +
 +server.StartServer();​
 +
 +Console.ReadKey();​ // Wait until key press. Not necessary in Unity.
 +
 +</​code>​
 +
 +cu un sistem de configurare in XML
 +
 +<​code>​
 +<?xml version="​1.0"​ encoding="​utf-8"​ ?>
 +<!--
 +  Configuring DarkRift server to listen at ports TCP 4296 and UDP 4297.
 +-->
 +<​configuration xmlns:​xsi="​http://​www.w3.org/​2001/​XMLSchema-instance"​ xsi:​noNamespaceSchemaLocation="​https://​www.darkriftnetworking.com/​DarkRift2/​Schemas/​2.3.1/​Server.config.xsd">​
 +  <server maxStrikes="​5"​ />
 +  ​
 +  <​pluginSearch/>​
 + 
 +  <​logging>​
 +    <​logWriters>​
 +      <​logWriter name="​ConsoleWriter1"​ type="​ConsoleWriter"​ levels="​trace,​ info, warning, error, fatal">​
 +        <​settings useFastAnsiColoring="​false"​ />
 +      </​logWriter>​
 +    </​logWriters>​
 +  </​logging>​
 +
 +  <plugins loadByDefault="​false"/>​
 +
 +  <data directory="​Data/"/>​
 +
 +  <​listeners>​
 +    <​listener name="​DefaultNetworkListener"​ type="​BichannelListener"​ address="​0.0.0.0"​ port="​4296">​
 +      <​settings noDelay="​true"​ udpPort="​4297"​ />
 +    </​listener>​
 +  </​listeners>​
 +</​configuration>​
 +
 +</​code>​
 +
 +==== Client =====
 +
 +Pentru realizarea clientului puteti folosi direct pachetul din Asset Store [[https://​assetstore.unity.com/​packages/​tools/​network/​darkrift-networking-2-95309|DarkRift Networking 2]]
 +
 +Exemplu de conectare si trimitere de mesaj simplu:
 +<​code>​
 +
 +using DarkRift;
 +using DarkRift.Client;​
 +using System.Net;
 +
 +var client = new DarkRiftClient();​
 +
 +void Client_MessageReceived(object?​ sender, MessageReceivedEventArgs e)
 +{
 +    using Message message = e.GetMessage();​
 +    using DarkRiftReader reader = message.GetReader();​
 +    Console.WriteLine("​Received a message from the server: " + reader.ReadString());​
 +}
 +
 +client.MessageReceived += Client_MessageReceived;​
 +
 +client.Connect(IPAddress.Loopback,​ tcpPort:​4296,​ udpPort:​4297,​ noDelay:​true);​
 +
 +Console.WriteLine("​Connected!"​);​
 +
 +using DarkRiftWriter writer = DarkRiftWriter.Create();​
 +writer.Write("​Hello world!"​);​
 +
 +using Message secretMessage = Message.Create(1337,​ writer);
 +client.SendMessage(secretMessage,​ SendMode.Reliable);​
 +
 +Console.ReadKey();​ // Wait until key press. Not necessary in Unity.
 +
 +</​code>​
 +
 +Puteti folosi tag-uri pentru a delimita diverse tipuri de mesaje.
 +De exemplu pentru actualizare de miscare puteti folosi tagul 1 si pentru chat puteti folosi tag-ul 10
 +
 +Exemplu de trimitere mesaj de chat
 +<​code>​
 +    //This will be called when the user presses enter in the input field
 +    public void MessageEntered()
 +    {
 +        //Check we have a client to send from
 +        if (client == null)
 +        {
 +            Debug.LogError("​No client assigned to Chat component!"​);​
 +            return;
 +        }
 +
 +        //First we need to build a DarkRiftWriter to put the data we want to send in, it'll default to Unicode ​
 +        //encoding so we don't need to worry about that
 +        using (DarkRiftWriter writer = DarkRiftWriter.Create())
 +        {
 +            //We can then write the input text into it
 +            writer.Write(input.text);​
 +
 +            //Next we construct a message, in this case we can just use a default tag because there is nothing fancy
 +            //that needs to happen before we read the data.
 +            using (Message message = Message.Create(10,​ writer))
 +            {
 +                //Finally we send the message to everyone connected!
 +                client.SendMessage(message,​ SendMode.Reliable);​
 +            }
 +        }
 +    }
 +</​code>​
 +
 +Pentru actualizare miscarii, trebuie sa tinem cont de ficare client in parte: ​
 +  * trimtem actualizari de la input doar pentru clientul curent
 +<​code>​
 +void UpdateNetworkPosition() {
 +        if (
 +            Vector3.Distance(lastPosition,​ transform.position) > moveDistance ||
 +            Vector3.Distance(lastRotation,​ transform.eulerAngles) > moveDistance
 +            ​
 +            )
 +        {
 +            using (DarkRiftWriter writer = DarkRiftWriter.Create())
 +            {
 +                writer.Write(transform.position.x);​
 +                writer.Write(transform.position.y);​
 +                writer.Write(transform.position.z);​
 +                writer.Write(transform.eulerAngles.x);​
 +                writer.Write(transform.eulerAngles.y);​
 +                writer.Write(transform.eulerAngles.z);​
 +
 +                using (Message message = Message.Create(1,​ writer))
 +                    Client.SendMessage(message,​ SendMode.Unreliable);​
 +            }
 +
 +            lastPosition = transform.position;​
 +            lastRotation = transform.eulerAngles;​
 +        }
 +    }
 +</​code>​
 +
 +  * instantiem diferit playerii: unul controlabil din input local, pentru clientul curent, si ceilalti doar sincronizati la actualizarile din server
 +<​code>​
 +void SpawnPlayer(object sender, MessageReceivedEventArgs e)
 +    {
 +
 +        using (Message message = e.GetMessage())
 +        using (DarkRiftReader reader = message.GetReader())
 +        {
 +            if (message.Tag == 0)
 +            {
 +                while (reader.Position < reader.Length)
 +                {
 +                    ​
 +                    ushort id = reader.ReadUInt16();​
 +              ​
 +
 +                    Vector3 position = new Vector3(reader.ReadSingle(),​ reader.ReadSingle(),​ reader.ReadSingle());​
 +                    Vector3 euler = new Vector3(reader.ReadSingle(),​ reader.ReadSingle(),​ reader.ReadSingle());​
 +                    ​
 +                    GameObject obj;
 + 
 +                    if (id == client.ID)
 +                    {
 +                        // instantiate local user
 +                        obj = Instantiate(localPrefab,​ position, Quaternion.identity) as GameObject;
 +                     
 +                    }
 +                    else
 +                    {
 +                        // instantiate network user
 +                        obj = Instantiate(networkPrefab,​ position, Quaternion.identity) as GameObject;
 +                        ​
 +                        //keep a list with all network players
 +                        networkPlayerManager.Add(id,​ playObj);
 +                    }
 +
 +                    ​
 +                }
 +            }
 +        }
 +    }
 +    ​
 +</​code>​
 +  * actualizam sincronizarile din server pentru toti playerii. Pentru asta in general avem nevoie sa tinem minte toata lista de clienti ​
 +<​code>​
 +Dictionary<​ushort,​ NetworkPlayerObj>​ networkPlayers = new Dictionary<​ushort,​ NetworkPlayerObj>​();​
 +
 +void MessageReceived(object sender, MessageReceivedEventArgs e)
 +    {
 +        using (Message message = e.GetMessage() as Message)
 +        {
 +            Debug.Log("​network message ");
 +            if (message.Tag == 1)
 +            {
 +                // Debug.Log("​position message ");
 +                using (DarkRiftReader reader = message.GetReader())
 +                {
 +                    ushort id = reader.ReadUInt16();​
 +                    Vector3 newPosition = new Vector3(reader.ReadSingle(),​ reader.ReadSingle(),​ reader.ReadSingle());​
 +                    Vector3 newEulerAngles = new Vector3(reader.ReadSingle(),​ reader.ReadSingle(),​ reader.ReadSingle());​
 +
 +                    if (networkPlayers.ContainsKey(id))
 +                    {
 +                        // Debug.Log("​new network position: "​+newPosition);​
 +                        networkPlayers[id].movePosition = newPosition;​
 +                        networkPlayers[id].currentEulerAngles = newEulerAngles;​
 +                    }
 +                }
 +            }
 +        }
 +    }
 +</​code>​
 +==== Server Plugin =====
 +
 +Putem folosi si un plugin modificand in configurare in felul urmator:
 +
 +<​code>​
 +  <!--
 +    Specifies where DarkRift should look for plugins.
 +  -->
 +  <​pluginSearch>​
 +    <​pluginSearchPath src="​Plugins/"​ createDir="​true"​ />
 +    <​pluginSearchPath src="​LogWriters/"​ />
 +    <​pluginSearchPath src="​NetworkListeners/"​ />
 +  </​pluginSearch>​
 +   <​plugins loadByDefault="​true">​
 +    <!-- Example:
 +    <plugin type="​Sniffer"​ load="​false"​ />
 +    -->
 +  </​plugins>​
 +</​code>​
 +
 +In acest caz veti face un proiect separat pentru plugin si il veti compila intr-un dll, care va fi pus/​actualizat in folderul de Plugins.
 +
 +<​code>​
 +using DarkRift;
 +using DarkRift.Server;​
 +using System;
 +using System.Collections.Generic;​
 +
 public class NetPlugin : Plugin public class NetPlugin : Plugin
 { {
Line 197: Line 464:
     }     }
    </​code>​    </​code>​
 +   
 +   
  
 +Pentru sincronizarea de animatii se poate proceda in mai multe feluri, in functie si de modul de gestiune al animatiilor:​
 +     * fie se trimite si un indicator de stare al animatiei si se sincornizeaza over network
 +     * fie se folosesc valori de speed, hieght etc (calculate prin diferenta sau luate/​transmise direct)
 ==== Chat ===== ==== Chat =====
  
pjv/laboratoare/2025/a05.1765360446.txt.gz · Last modified: 2025/12/10 11:54 by alexandru.gradinaru
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0