Skip to content

ldoubil/OnlineCity

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

86 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

OnlineCity

Mod OnlineCity for game RimWorld Author Vasilii Ivanov aka Aant

OnlineCity

OnlineCity мод для игры RimWorld Автор Василий Иванов aka Aant

OnlineCity – это модуль сетевой игры для симулятора выживания RimWorld. Он позволяет нескольким игрокам играть на одной планете в режиме онлайн. После регистрации, вы сможете создать свое поселение и начать развиваться бок о бок с другими участниками. Вы сможете наблюдать за прогрессом соседей, их поселениями и караванами, но самое главное вы сможете оказывать друг другу вполне материальную помощь, передавая еду, медикаменты, оружие или любые другие вещи, включая поселенцев. Для этого необходимо лишь по всем правилам игры собрать караван и добраться до них!

Цель мода – сделать возможной игру с друзьями, не нарушая баланса и не снижая уровень погружения в игру. На данный момент жизненный путь мода только начался. Он обладает минимальным набором функций, чтобы предоставить вам возможность совместной игры. Вы можете видеть других игроков на карте планеты, переписываться с ними в чате и обмениваться товарами с караванами и поселениям. А разработка продолжается! За ее прогрессом вы можете следить в новостях группы.

Ссылки

Официальная страница мода: https://vk.com/rimworldonline (там же есть ссылки для финансовой помощи автору)

Общение в Дискорд: https://discord.gg/5DzWrnR

Почта emAnt@mail.ru

Процесс разработки на Trello: https://trello.com/b/gXtWtDjy/onlinecity-mod-rimworld

Текущий сервер для игры и тестов 194.87.95.90 (актуально на 10.2019)

Игрокам

Текущая версия RimWorld 1.0+

Чтобы начать играть установите мод как обычно в папку Mods. Для работы также требуется установленный мод HugsLib. Таким образом минимальный набор может быть в такой последовательности: Core HugsLib OnlineCity

Мод должен быть совместим практически со всеми другими модами. Однако набор модов и, возможно, каких-то настроек может ограничиваться сервером, на котором вы хотите играть. Т.е. на одном сервере набор определенных (конфликтных) модов должен быть одинаков у всех игроков.

Синхронизация с сервером происходит каждые 5 секунд, полноценное сохранение – раз в 15 минут или при выходе из игры посредством меню. Не рекомендуется закрывать игру нажатием на крестик! Это может привести к потере прогресса игры с последнего сохранения.

Полезно знать:

  • Пока сетевая игра ориентирована только на взаимопомощь в выживании.

  • Цвет домов и караванов других игроков – синий. С ними можно взаимодействовать, выделив свой караван и нажав на них правой кнопкой мыши.

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

  • Чтобы товары, полученные от сделок с другими игроками, складировались в определенном месте вашего поселения, переименуйте нужный склад так, чтобы он содержал символы "торг" или "trad".

  • В общем чате можно общаться со всеми игроками, которые находятся онлайн. Так же можно создать приватный канал для общения с одним игроком лично.

  • По щелчку любой кнопки мыши на никнейме игрока происходит добавление игрока в активный чат, открытие приватного канала чата, либо просмотр общей информации об игроке на выбор.

Помощь в разработке

Разработка задумывается из папки OnlineCity в игровой папке Mods.

Проекты:

  • Chat - утилита через которую можно залогиниться и общаться в общем чате
  • Converter - утилита для перевода файла сохраненного мира на более новые версии
  • RimWorldOnlineCity - библиотека мода прикрепляемая к игре
  • ServerConsole - оболочка запуска сервера
  • ServerDll - сервер, открывает указанный порт и радует игроков (по задумке)
  • UnionDll - содержит модель и некоторый код, который используется и клиентом и сервером

Проект сервера ServerConsole разворачивается в специальную папку RimWorldOnlineCityServerOut Сама библиотека мода RimWorldOnlineCity в папку Assemblies так, что после компиляции можно сразу тестировать в игре.

Начать знакомство можно с:

  • StartPoint.cs - здесь точка запуска нашего мода. Сейчас тут два класса которые добавляют кнопку на нижней панели в игре. И здесь же (в конструкторе) идет первая инициализация. Основная инициализация происходит после входа в игру (после логина или регистрации).
  • SessionClientController.cs - тут собственно Init (который запускается из StartPoint), и InitConnected (начало работы над игрой сразу после коннекта и авторизации на сервере). А также тут функции с общими действиями.
  • Dialog_MainOnlineCity.cs - основная форма игры, которая запускается по кнопке на нижней панели в игре. Сейчас, временно, при старте формы происходит запрос подключения к серверу и начало всех диалогов с пользователем.

Связь клиент сервер.

Начало обмена (или как оно устроено)

Клиент.

  • Начало обмена начинается на форме Dialog_LoginForm, либо Dialog_Registration.
  • Они вызывают функции SessionClientController Login и Registration соответственно.
  • Они вызывают создание подключения функцией SessionClientController.Connect.
  • Она же вызывает Connect из класса SessionClient (он реализован как синглтон).
  • Здесь происходит следующее (пока ключ на сессию передаётся открыто):
  • Посылаем серверу первый пакет в один байт 0x00
  • В ответ нам приходит симметричный ключ на сессию, которым мы будем шифровать и расшифровывать трафик
  • Непосредственную связь обеспечивает ConnectClient и класс открывающий порт на сервере ConnectServer.

Весь дальнейший обмен происходит через функцию TransObject<>

  • В TransObject<> запаковываем различные данные в стандартный единый контейнер ModelContainer и передаем серверу методом Trans.
  • В Trans мы сериализуем объект в байты и сжимаем (GZip.ZipObjByte), шифруем (CryptoProvider.SymmetricEncrypt) и отправляем на сервер.
  • Принитое сообщение от сервера расшифровываем, разжимаем и десериализуем в такой же стандартный единый контейнер ModelContainer. В нем, также, может быть передано сообщение об ошибке.

Сервер.

При установлении подключения возникает событие ServerManader.ConnectionAccepted в котором порождается отдельная нить и запускается обработчик DoClient, который порождает игровую сессию на сервере в виде класса SessionServer и запускает в нём метод Do.

В этом методе мы бесконечно слушаем поток и принимаем пакеты аналогично описанному у клиента выше, после чего полученный пакет "маршрутизируем" методом Service. Подробнее смотри ниже про сервер.

Запрос - ответ (или как пользоваться)

Клиент.

Для всех типов запросов создается своя функция в SessionClient.

В ней происходит запаковка передаваемых параметров в модель и запускается TransObject<> для передачи на сервер и приема ответа от него. В TransObject<> помимо данных передается также модель ожидаемого ответа и коды приема-передачи (обычно нечётное - запрос, а ответ это +1 от него).

Сервер.

  • Принятый запрос в виде стандартного контейнера ModelContainer маршрутизируется функцией SessionServer.Service.
  • Здесь на основе кода запроса выбирается обрабатывающая функция в классе Service. Можно сказать, что класс Service это аналог SessionClient для клиента (в том смысле, что в SessionClient мы вызываем функцию, а сервер обрабатывает в её зеркальном отражении в классе Service)

Для добавления нового обработчика на сервере соответственно добавляем функции в классы SessionClient и Service, и запись с новыми кодами внутри функции SessionServer.Service.

Взаимодействие с игрой

Подключение

В основном игровые данные храняться в классе SessionClientController в ClientData Data.

  • Начало работы мода начинается на форме Dialog_LoginForm, либо Dialog_Registration.
  • Они вызывают функции SessionClientController Login и Registration соответственно, в которых происходит подключение к серверу.
  • После успешного подключения запускается InitConnected:

Если мир на сервере не создан, и вошел админ, то вызывается диалог создания мира Dialog_CreateWorld. По его завершении запускается создание мира GameStarter.GameGeneration, после окончании создания запускается CreatingWorld. Тут идет модернизация мира (пока отсутствует) и сохранение его данных на сервер connect.CreateWorld(toServ) После чего пользователя выкидывает в главное меню.

Если у игрока нет сейва на сервере, то создаем планету, загружаем туда поселения других игроков и передаем управение пользователя для выбора мета высадки и, потом, стандартным диалогам выбора поселенцев и прочим. По окончании диалога естественным образом игра стартует и срабоатывает событие GameStarter.AfterStart = CreatePlayerMap; (запускается функция CreatePlayerMap). В этой функции происходит первой сохранение игры и переход к InitGame (см ниже).

Если сейв на сервере есть, то загружаем его и по событию GameLoades.AfterLoad переходим также к InitGame

  • Если пользователь только что создал игру, или загрузил её, то в момент готовности будет запущена вункция InitGame. В ней запускается:

  • Предобработка мира в UpdateWorldController.ClearWorld() (пока только удаление все наших объектов (поселения сетевых игроков и их караваны наследуются от CaravanOnline))

  • Подготовка апдейтера UpdateWorldController.InitGame(); который будет синхронизировать планету с сервером

  • Запуск первого обновления мир UpdateWorld(true); Первое отличается тем, что мы только получаем данные, чтобы установить для наших поселений (которые уже есть на сервере) serverId для правильной связи. Иначе при загрузке карты мы бы каждый раз отправляли, что у нас новые поселения и караваны.

  • Запуск трёх циклических событий по таймеру (см ниже)

  • Установка события возникающего при выходе из игры любым способом. В неё происходит внеочередное сохранение игры на сервер и дисконнект.

Циклические события во время игры по таймеру

  • Каждые пол сек. обновление данных чата UpdateChats() Получаем данные с сервера dc = connect.UpdateChat(Data.ChatsTime);

Здесь передаем дату и время прошлого запроса. В ответ сервер выдает все сообщения от переданного времени до текущего момента. Новое текущее время сервера сохраняем до следующего запроса.

Далее запускаем функцию дополнения текущих данных чата теми, что пришли с сервера в Data.ApplyChats(dc);

Помимо этого в чате сохраняется время последнего отклика сервера. И если ответа на чат нет, то по проверке в ClientData в свойстве bool ServerConnected проверяем на диссконнект (не было отклика более 8 секунд)

  • Каждые несколько секунд синхронизация мира UpdateWorld(false) Cобираем данные с планеты UpdateWorldController.SendToServer (не запускается первый раз)

Обновляем информацию по игрокам, время обновления и прочее

Обновляем планету UpdateWorldController.LoadFromServer

  • Каждые 15 минут сохранение и передача сейва на сервер BackgroundSaveGame() Сохраняем запуская функцию сохранения SaveGame, а результат сохраняем в переменную, которую отправит на сервер следующий запуск синхронизаци мира

About

OnlineCity mod RimWorld

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • C# 100.0%