PlayerIO Урок 2 - Создание сервера

Что такое сервер?

Определим это понятие так: сервер — это программа, которая позволяет связать некое количество игроков в одном игровом мире, обрабатывать этот мир, реагируя на действия пользователя и посылая ответ на них. Клиент(игрок, пользователь) — программа, которая общается с другими клиентами через сервер.

Важно понимать следующее: клиенту нельзя доверять! Все, что клиент присылает на сервер нужно проверить и только потом выполнить нужные действия. По сути, роль клиента — это отражение данных, которые присылает сервер и отправка серверу команд типа «я пошел прямо», «нажал стрелять» и т.д. А сервер должен проверить и выполнить какие-либо действия, полученные от клиента.

Едем дальше… PlayerIO строиться на комнатной архитектуре. Комната — это место, в котором собираются клиенты и что-то делают(игровая карта, доска для партии шашек...). В комнате одновременно может находиться не более 45 человек. Комнат может быть огромное число. Причем комнаты по функционалу могут отличаться(одна комната для чата, другая для игры, третья для...). Думаю мысль понятна:) На этом с теорией пока все. Приступим к написанию нашего первого сервера.



Подготовим проект
1. Запускаем Visual Studio 2010(далее VS) — Пуска->Все программы->Microsoft VS->Microsoft VS 2010…


2. Нажимаем File->New->Project. Выбираем и списка шаблонов C# — Windows, далее Class Library, ставим Framework 4.0, пишем название проекта «GameServer», указываем путь сохранения(я указал «D:\») — жмем «ОК».


3. Далее нужно добавить ссылку на библиотеку. Сперва распакуйте ранее скачанный архив библиотек. Далее перейдите обратно в VS и в окне Solution Explorer(если нет — нажмите Ctrl+W+S) щелкните правой кнопкой мыши по «References», а затем «Add Reference...»


4. Выберите вкладку «Browse» и найдите в распакованных библиотеках в папке «Player.IO Serverside .NET Libraries» файл «Player.IO GameLibrary.dll». Выберите его и нажмите «ОК». Теперь в списке «References» у вас есть «Player.IO GameLibrary». Это операция называется подключением библиотеки к проекту, запомните это;)


Кодим код
1. Приступим. Для начала добавим пространство имен «using PlayerIO.GameLibrary;». Это даст нам возможность работать с классами фреймворка PlayerIO.

2. Далее нужно объявить класс Игрока, на котором строится комната.Пока добавим пустой класс, а затем допишим по мере надобности остальной код. Класс игрока может иметь любое имя, но должен обязательно наследоваться от базового класса BasePlayer:

public class Player : BasePlayer
{

}


3. Теперь объявим класс Комната. Он должен наследоваться от класса Game, где T — класс Игрока. Также, нужно назначить атрибут RoomType, чтобы в последующем можно было подключаться к данной комнате. Создадим комнату MainGame и назовем ее MainRoom, хотя имя класса и имя комнаты могут совпадать при желании.

[RoomType("MainRoom")]
public class MainGame : Game<Player>
{

}


4. В целом имеем:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PlayerIO.GameLibrary;

namespace GameServer
{
    public class Player : BasePlayer
    {

    }
    [RoomType("MainRoom")]
    public class MainGame : Game<Player>
    {

    }
}


5. Мы имеем опоры, но еще не каркас. Давайте переопределим методы в классе MainGame и заодно посмотрим за что они отвечают:

[RoomType("MainRoom")]
    public class MainGame : Game<Player>
    {
        //Вызывается при старте игры (когда в комнату входит первый игрок).
        public override void GameStarted()
        {

        }
        //Вызывается при окончании игры (когда выходит последний игрок).
        public override void GameClosed()
        {

        }
        //Вызывается при входе игрока в комнату.
        public override void UserJoined(Player player)
        {

        }
        //Вызывается при выходе игрока из комнаты
        public override void UserLeft(Player player)
        {

        }
        //Вызывается при приеме сообщения от пользователя.
        public override void GotMessage(Player player, Message message)
        {

        }
        //Вызывается перед тем, как пользователь входит в комнату
        //В случае возврата False, пользователь не войдет в комнату
        //т.е. не вызовится метод UserJoined
        public override bool AllowUserJoin(Player player)
        {
            return true;
        }
    }


Есть еще не переопределенные методы, но мы их трогать не будем, т.к. нам они не понадобятся.

Рассмотрим еще несколько членов класса MainGame:
Players — коллекция игроков в комнате.
PlayerCount — их количество.
RoomData — словарь параметров комнаты.
Broadcast — метод отсылает сообщение всем подключенным игрокам.

Теперь стоит поговорить о классе Player, а точнее о его родителе — BasePlayer. Нас интересуют следующие члены:
ConnectUserId — идентификатор пользователя. Его задает сам пользователь, когда подключается к серверу.
JoinData — дополнительные данные при подключении к комнате. Например можно передать Имя игрока.
Send — метод для отправки сообщения пользователю.

И последний класс — Message. Используется для передачи сообщений между сервером и клиентом. Сообщение имеет тип и данные. Тип задается строкой, а данные неким типом. Члены класса:
Message.Create — создает сообщение с заданным типом.
Type — тип сообщения.
Add — добавляет данные.
Get* — извлекает данные.

ВАЖНО: в сообщение вазен порядок записи/чтения. Если вы записали строку, потом число, потом строку, то в таком же порядке нужно и прочитать. Например:
Создаем сообщение с типом «monsterData»

            Message message = Message.Create("monsterData");
            message.Add(1);//число int
            message.Add("Dark Spider");//строка
            message.Add((byte)100);//число byte
            message.Add(false);//переменная bool
            message.Add(200);//число int
            Broadcast(message);//отсылаем всем игрокам


Читаем в методе GotMessage

        public override void GotMessage(Player player, Message message)
        {
            switch (message.Type)
            {
                case "monsterData":
                    int mId = message.GetInt(0);
                    string mName = message.GetString(1);
                    int mHp = message.GetInt(2);
                    bool mAgr = message.GetBoolean(3);
                    int mCoins = message.GetInt(4);
                    break;
            }
        }

Порядок, как вы видите, при записи и чтении одинаковый: int-string-int-bool-int.

Теперь давайте напишем что-нибудь простое. Допустим, наше приложение будет принимать от пользователя сообщение и рассылать его всем игрокам, эдакий эхо-сервер. Нам нужно всего лишь принять и отправить одно сообщение. Принимаем сообщение в методе GotMessage и там же создаем и отправляем новое сообщение всем пользователям. Полный код:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using PlayerIO.GameLibrary;

namespace GameServer
{
    public class Player : BasePlayer
    {

    }
    [RoomType("MainRoom")]
    public class MainGame : Game<Player>
    {
        //Вызывается при старте игры (когда в комнату входит первый игрок).
        public override void GameStarted()
        {

        }
        //Вызывается при окончании игры (когда выходит последний игрок).
        public override void GameClosed()
        {

        }
        //Вызывается при входе игрока в комнату.
        public override void UserJoined(Player player)
        {

        }
        //Вызывается при выходе игрока из комнаты
        public override void UserLeft(Player player)
        {
           
        }
        //Вызывается при приеме сообщения от пользователя.
        public override void GotMessage(Player player, Message message)
        {
            switch (message.Type)
            {
                case "sendall":
                    string mMessage = message.GetString(0);//получаем текст сообщения
                    mMessage = player.ConnectUserId + ": " + mMessage;//добавим к тексту ид того, кто прислал его
                    Message newMessage = Message.Create("sendall");//создаем новое
                    newMessage.Add(mMessage);//добавляем измененный текст
                    Broadcast(newMessage);//отсылаем всем
                    break;
            }
        }
        //Вызывается перед тем, как пользователь входит в комнату
        //В случае возврата False, пользователь не войдет в комнату
        //т.е. не вызовится метод UserJoined
        public override bool AllowUserJoin(Player player)
        {
            return true;
        }
    }
}


Код готов! Компилируем нажатием клавиши F6. Теперь зайдем в папку со скомпилированной библиотекой. У меня это «D:\GameServer\bin\Debug», у вас — путь до проекта + «GameServer\bin\Debug» и там должен лежать файл «GameServer.dll».

Запуск сервера
Заходим в админку. Нажимаем Create New Game и вводим название игры(у нас будет MyFirstGame) и жмем «Create Game». Нажимаем на ее название и видим такое окно:


«Game ID» нам понадобиться потом, а пока слева нажимаем на раздел «Multiplayer», затем сверху «Game Code»:


Далее жмем кнопку «Upload Game Code» и в появившемся окне, напротив Game Code (.dll): нажимаем кнопку «Выберите файл». Тут нужно выбрать вашу скомпилированную библиотеку. Далее нажимаем «Upload».


В итоге мы получили запущенный сервер, на котором могут создаваться комнаты с типом MainRoom.

На этом пора заканчивать данный урок. Получился он довольно большой и требует времени на переваривание. Если что-то не понятно — прочтите еще раз, задайте вопрос, но обязательно разберитесь со всем, что было написано в данном уроке, иначе дальше не поймете хода работы всей системы. Успехов!

С Уважением, Александр:)

3 комментария

комментарий был удален
avatar
То вы за Photon агитируете, то за FGS, а теперь за Playerio взялись. Запутывает такая ситуация.
Если можно, вы по-простому разложите для не слишком одарённых, когда имеет смысл использовать первое, когда второе, а в каких случаях лучше подойдёт третье?
avatar
Мне нравится все, но эти вещи созданы для разных аудиторий.

Если вы не очень знакомы с программированием, вы одиночка(или просто мало людей в команде) и хотите создать быстро сетевую игру, то остановиться можно на PlayerIO

Если у вас крупный проект, где нужно тонко настроить сетевую часть, то Photon

FGS тоже создан под большие проекты, но так как он появился недавно, то ничего не могу сказать по нему.
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.