This is an old revision of the document!


5. Servere multiplayer dedicate

Cerinte

Realizarea unui joc multiplayer de tip social:

Documentatie video

Documentatie text

Server dedicat

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 DarkRift Networking 2

Folosind un server dedicat trebuie gestionate mai multe elemente:

  • conexiunile si lista curenta de clienti conectati
  • datele stocate despre player
  • mesajele de update

DarkRift foloseste un sistem modular, bazat pe plugin-uri C#, pentru implementarea serverului. Astfel, putem defini un plugin in felul urmator:

public class NetPlugin : Plugin
{

    Dictionary<IClient, Player> players = new Dictionary<IClient, Player>();

    public override bool ThreadSafe => false;

    public override Version Version => new Version(1, 2, 5);

    public NetPlugin(PluginLoadData pluginLoadData) : base(pluginLoadData)
    {
        ClientManager.ClientConnected += ClientConnected;
        ClientManager.ClientDisconnected += ClientDisconnected;
    }
}

unde clasa Player reprezinta datele stocate despre player. Spre exemplu se pot stoca date legate de pozitie, rotatie sau id de utilizator.

public struct Player
{
    public ushort ID;
    public float X, Y, Z;
    public float rotX, rotY, rotZ;
}

In momentul in care se conecteaza un client, trebuie realizate urmatoarele lucruri:

  • instantierea Player-ului in server
  • notificarea tuturor celorlalti clienti conectati de conectarea unui nou player
  • trimiterea de informatii despre ceilalti clienti, clientului nou conectat
  • ascultarea de mesaje de actualizare
void ClientConnected(object sender, ClientConnectedEventArgs e)
    {
        //new player instance
        Player newPlayer = new Player();
        newPlayer.ID = e.Client.ID;
        newPlayer.X = 0;
        newPlayer.Y = 3;
        newPlayer.Z = 0;
        newPlayer.rotZ = 0;
        newPlayer.rotY = 0;
        newPlayer.rotZ = 0;
 
        using (DarkRiftWriter newPlayerWriter = DarkRiftWriter.Create())
        {
            newPlayerWriter.Write(newPlayer.ID);
            newPlayerWriter.Write(newPlayer.X);
            newPlayerWriter.Write(newPlayer.Y);
            newPlayerWriter.Write(newPlayer.Z);
            newPlayerWriter.Write(newPlayer.rotX);
            newPlayerWriter.Write(newPlayer.rotY);
            newPlayerWriter.Write(newPlayer.rotZ);
 
            //notify other clients
            using (Message newPlayerMessage = Message.Create(0, newPlayerWriter))
            {
                foreach (IClient client in ClientManager.GetAllClients().Where(x => x != e.Client))
                    client.SendMessage(newPlayerMessage, SendMode.Reliable);
            }
        }
 
        players.Add(e.Client, newPlayer);
 
        using (DarkRiftWriter playerWriter = DarkRiftWriter.Create())
        {
            foreach (Player player in players.Values)
            {
                playerWriter.Write(player.ID);
                playerWriter.Write(player.X);
                playerWriter.Write(player.Y);
                playerWriter.Write(player.Z);
                playerWriter.Write(player.rotX);
                playerWriter.Write(player.rotY);
                playerWriter.Write(player.rotZ);
            }
 
            //send all other players data to new client
            using (Message playerMessage = Message.Create(0, playerWriter))
                e.Client.SendMessage(playerMessage, SendMode.Reliable);
        }
 
        e.Client.MessageReceived += MovementMessageReceived;
    }

Actualizare de informatii

La fiecare actualizare (de ex miscarea personajului) trebuie facut broadcast.

void MovementMessageReceived(object sender, MessageReceivedEventArgs e)
    {
        using (Message message = e.GetMessage() as Message)
        {
            if (message.Tag == 1)
            {
                using (DarkRiftReader reader = message.GetReader())
                {
                    float newX = reader.ReadSingle();
                    float newY = reader.ReadSingle();
                    float newZ = reader.ReadSingle();
                    float newRotX = reader.ReadSingle();
                    float newRotY = reader.ReadSingle();
                    float newRotZ = reader.ReadSingle();

                    Player player = players[e.Client];

                    player.ID = players[e.Client].ID; //AA
                    player.X = newX;
                    player.Y = newY;
                    player.Z = newZ;
                    player.rotX = newRotX;
                    player.rotY = newRotY;
                    player.rotZ = newRotZ;

                    players[e.Client] = player; //AA

                    using (DarkRiftWriter writer = DarkRiftWriter.Create())
                    {
                        writer.Write(player.ID);
                        writer.Write(player.X);
                        writer.Write(player.Y);
                        writer.Write(player.Z);
                        writer.Write(player.rotX);
                        writer.Write(player.rotY);
                        writer.Write(player.rotZ);
                        message.Serialize(writer);
                    }

                    foreach (IClient c in ClientManager.GetAllClients().Where(x => x != e.Client))
                        c.SendMessage(message, e.SendMode);
                }
            }
        }
    }
   

Chat

Pentru a gestiona si mesajele chat, puteti adauga un event suplimentar in momentul in care se conecteaza clientul

e.Client.MessageReceived += ChatMessageReceived;

apoi sa ascultati mesajele si se face broadcast

    void ChatMessageReceived(object sender, MessageReceivedEventArgs e)
    {
        using (Message message = e.GetMessage() as Message)
        {
            if (message.Tag == 10)
            {
                using (DarkRiftReader reader = message.GetReader())
                {
                    using (DarkRiftWriter writer = DarkRiftWriter.Create())
                    {
                        writer.Write(reader.ReadString());
                    }

                    foreach (IClient c in ClientManager.GetAllClients())
                        c.SendMessage(message, e.SendMode);
                }
            }
        }
    }

Deconectarea

void ClientDisconnected(object sender, ClientDisconnectedEventArgs e)
    {
        players.Remove(e.Client);

        using (DarkRiftWriter writer = DarkRiftWriter.Create())
        {
            writer.Write(e.Client.ID);

            using (Message message = Message.Create(2, writer))
            {
                foreach (IClient client in ClientManager.GetAllClients())
                    client.SendMessage(message, SendMode.Reliable);
            }
        }
    }
    
 
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