Материалы по сокетам для программирования игровых серверов

Учиться программировать и тренироваться, чтобы не забывать, а развивать навыки через написание простых игрушек - это интересно и полезно, а учиться писать сетевые игры - это ещё более интересно. Можно развивать одновременно большое количество навыков: программирование графики, математику, базы данных, клиент-серверное программирование и т.д.

Выкладываем здесь, всё что касается программирование игровых серверов.

Содержание:

Multiplayer game Node.js

Из того, что я находил в сети, эти уроки я бы рекомендовал для начинающих. Я считаю, что только первые 4 урока полезны. Остальные уроки путают. Нельзя пересылать нажатия клавиш напрямую без учёта сетевых задержек. Но первые 4 урока дадут быстры старт для начала программирования игр, которые не требуют учитывать сетевые задержки: крестики-нолики, морской бой, карточные игры (например, игра “Дурак”). Рекомендую сразу после первого соединения и отправки первого сообщения через сокет развернуть свой первый простейший сервер на бесплатном хостинге Heroku. Потому что локально не так интересно и на реальном хостинге вы можете тестировать сервер со своими друзьями, публиковать на форуме для тестирования и предложений. Наберите в интернет поисковике: heroku node.js и первая ссылка будет на эту пошаговую инструкцию: Getting Started on Heroku with Node.js. После создания нового приложения на Heroku можете перейти на вкладку Deploy и нажать кнопку “Connect to GitHub”. Вам предложат ввести имя репозитория на GitHub и поставить галочку для автоматического Deploy, тогда прим “push” Heroku будет забирать изменения кода с GitHub и переразвёртывать приложение. Можно оставить Manual Deploy по кнопке, а можно как в Getting Started on Heroku with Node.js развёртывать со своего компьютера через CLI Heroku. Мне больше нравится автоматического развёртывание с GitHub. На Heroku есть бесплатные базы данных: MySQL, MongoDB и т.д.

Real Time Multiplayer in HTML5

Потренировавшись с играми не требующими учитывать сетевые задержки можно перейти к тем, которые требуют. Лучший пример, который я нашёл из этой статьи: Real Time Multiplayer in HTML5. Исходники примера можно скачать с GitHub. Я развернул пример на Heroku: запустите по клику. Так как хостинг бесплатный, то если приложением никто не пользовался 30 минут, то оно засыпает. Если оно заснуло, то нужно будет подождать пробуждения примерно 10 секунд. Запустите в двух браузерах и оцените плавность перемещений. Отключите на GUI методы компенсации задержек (вкладка “Methods”): “client_smoothing” (интерполяция позиций других клиентов на вашей стороне) и “client_predict” (предсказание движения клиента без ожидания его реальзной позиции с авторитарного сервера).

Source Multiplayer Networking

В этой статье объясняется, как работает игровой сервер движка Source от Valve Software. На этом движке сделаны игры: Counter Strike, Half-Life и Left 4 Dead. На данной статье базируется статья Real Time Multiplayer in HTML5, в которой есть отсылка на статью данную статью о Source. Слева вверху сайта данной статьи можно переключить язык на русский, но я думаю, лучше всегда читать на английском, если есть возможность, а то вдруг опять обманут, как это было ни раз, потому что часто переводят плохо. Лучше всегда быть в курсе английской терминологии. В самом низу статьи есть раздел “See also”, где есть ссылки на связанные темы. Я пока только проглядел и сильно не вчитывался, но вникать постепенно придётся. Неприступная крепость не берётся сразу. Мозг должен привыкнуть к новой реальности сетевого программирования.

Я забыл вставить ссылку на статью: Source Multiplayer Networking

Перевод: Многопользовательские игры. Разработка сетевых приложений
Оригинал: Multiplayer Game Programming: Architecting Networked Games
Исходники примеров: https://github.com/MultiplayerBook/MultiplayerBook

Смотрел перевод, он вроде хороший. Но я читаю оригинал. Я пока только некоторые места данной книги посмотрел обзорно. На протяжении книги создаётся игра по локальной сети, где, как я понял, играешь за робота-кота, который что-то ловит. Цель поймать больше и набрать больше очков, чем соперники. Происходит действие игры в одном игровом мире, где каждый за себя и пытаешься выжить в конкурентной борьбе. Чёткого описания игрового процесса я не нашёл. Может я что-то не правильно понял. То что я точно понял, что для клиента и сервера используется C++. Для 2D графики используется библиотека SDL. Для сервера используется чистый Winsock (https://ru.wikipedia.org/wiki/Winsock). Я использую для сервера и клиента C#. Клиента пишу OpenGL 3.0 и OpenTK. С помощью OpenTK можно создать окно из консольного приложения. Можно встроить OpenTK.GLControl в WPF и WinForms. Устанавливаются OpenTK и OpenTK.GLControl очень просто и очень быстро, через NuGet. Не нужно долго настраивать SDL2. В Xamarin встроена OpenTK, то есть можно написать на C# клиента для Android и iOS. В целом, я считаю, что C# вполне подходит для написания игровых серверов. Я много находил информации, что если есть небольшие отличия в скорости C# и C++, то эти отличия сходят на нет, потому что это пренебрежимо мало с сетевыми задержками, которые неизбежны даже при самой лучшей скорости соединения. Я за то, чтобы переписывать примеры книги на C#. C# намного более дружелюбный, мне он больше нравится. Тем более всегда есть возможность перейти на Unity, который является самым популярным движком. Можно использовать Unity, как клиент для C# TCP-сервера.

Создание простейшего чата с клиентом на консольном C# и с сервером на Node.js/socket.io/JavaScript. Бонус - WPF-клиент

Бонус - клиент на WPF: WpfChatBySocketIoClientDotNet.zip (14.6 КБ) (файл server.js лежит в папке Server)

Далее описан консольный проект на C# (клиент) и сервер на Node.js/socket.io/JavaScript.

Создаём пустую папку для сервера. Заходим в папку через консоль. Вводим команды:

npm init -y
npm i socket.io shortid

Создаём файл socket.js и копируем в него код, я написал комментарии к каждой строке:

// Подключаем нужные библиотеки
var io = require('socket.io')(process.env.PORT || 1337);
var shortid = require('shortid');

// Выводим сообщение, что клиент запущен
console.log('server started');

// Это функция вызывается, как только подключается клиент
io.on('connection', function (socket) {

    // Генерируем ID для подсоединившегося клиента, т.е. для текущего
    var thisClientId = shortid.generate();

    // Выводим ID текущего клиента
    console.log('client connected, broadcasting spawn, id: ', thisClientId);
	
    // Отправляем сообщение всем клиентам
    socket.broadcast.emit(thisClientId + ' is connected');
	
    // Принимаем сообщение и отсылаем остальным клиентам
    socket.on('message', function (data) {
    // Выводим принятое сообщение в консоль
    console.log('from server: ' + data);
    // Пересылаем принятое сообщение остальным клиентам
        socket.broadcast.emit('message', data + '(from id/' + thisClientId + ')');
    });
	
    // Выводим сообщение, что клиент отсоединился
    socket.on('disconnect', function () {
        console.log('client disconnected');
    });
});

Запускаем сервер командой: npm server.js

Создаём консольный проект на C#. Ставим через NuGet: SocketIoClientDotNet. Внимание! Сначала нужно поставить пакет с зависимостями, а потом сам SocketIoClientDotNet. Иначе выдаёт ошибку при установке.

Копируем код в Program.cs:

using System;

namespace ConsoleChatBySocketIoClientDotNet
{
    class Program
    {
        static void Main(string[] args)
        {
            // Создаём сокет
            var socket = Quobject.SocketIoClientDotNet.Client.IO.Socket("http://localhost:1337");

            // Принимаем сообщение и выводим на экран
            socket.On("message", (data) =>
            {
                // Переходим на новую строку
                Console.WriteLine();
                // Выводим принятое сообщение на экран
                Console.WriteLine("Ответ: " + data);
                // Выводим приглашение ввести сообщение
                Console.Write("Введите сообщение: ");
            });

            while (true)
            {
                // Выводим приглашение ввести сообщение
                Console.Write("Введите сообщение: ");
                // Читаем сообщение из консоли
                string mess = Console.ReadLine();
                // Отправляем сообщение на сервер
                socket.Emit("message", mess);
            }
        }
    }
}

Запускаем проект и чат работает.

Рекомендую развернуть чат на бесплатном хостинге Heroku по официальной инструкции: Getting Started on Heroku with Node.js . Тогда на C#-клиенте нужно изменить адрес с локального на следующий, где указать имя домена, который даётся Heroku во время создания приложения автоматически:

var socket = Quobject.SocketIoClientDotNet.Client.IO.Socket("ws://имя-вашего-приложения.herokuapp.com");

Автор пакета SocketIoClientDotNet написал здесь, что он объявил пакет SocketIoClientDotNet не рекомендуемым к использованию (deprecate), то там же он написал, что будет использовать этот пакет для своих проектов.

имхо лучше писать комменты не с описанием того, что выводится в консоль, а про менее очевидные для новичков вещи, типа что в

порт берется из переменной среды, либо (если не задана) — просто 1337.

ЗЫ в первом коде отступы сломались из-за смешивания табов и пробелов.

1 Симпатия

Видео-туториал: Tic-tac-toe multiplayer in pygame

Онлайн руководство: Socket Programming in Python (Guide)