• Из-за обновления GTA 5 (был добавлен новый патч) может временно не работать вход в RAGE Multiplayer.

    ERROR: Your game version is not supported by RAGE Multiplayer.

    Данная ошибка говорит о том, что GTA V обновилась до новой версии (GTA Online тоже). Вам необходимо обновить саму игру в главном меню вашего приложения (Steam / Epic Games / Rockstar Games).
    Если после этого RAGE:MP все равно не работает - вам нужно дождаться выхода патча для самого мультиплеера (обычно это занимает от нескольких часов до нескольких дней).

    Новости и апдейты Rockstar Games - https://www.rockstargames.com/ru/newswire/
    Статус всех служб для Rockstar Games Launcher и поддерживаемых игр: https://support.rockstargames.com/ru/servicestatus


    Grand Theft Auto 5 (+ GTA Online) последний раз были обновлены:

Урок (C#&JS) Делаем мини игру для сервера

Продолжать серию подробных текстовых мануалов


  • Всего проголосовало
    21

IronPython

Специалист
Автор темы
high coder
7 Ноя 2020
169
64
82
Всем привет, сегодня сделаем небольшую мини игру для вашего RageMP сервера :)

Сегодня будем закреплять знания с предыдущих уроков на примере создания мини игры для вашего сервера :)

В статье есть ссылки на файлы которое лежат на github. Так что если вы увидели текст, который напоминает вам ссылку то кликайте

Что вам понадобиться, для того чтобы понять этот урок
1- Мозг
2- Прямые руки (но это не обязательно)
3- Ну и желательно не быть Питонистмом
4- Также предполагается что до этого вы прошли два предыдущих урока или умеете имплементировать разные конкретные примеры под свои проекты

Предыдущие Уроки
  1. Настройка окружения
  2. Настройка серверной части
  3. Создание и настройка клиентской части сервера для RAGEMP
  4. Использование CEF в RAGEMP
  5. Делаем Shared сборку на C#
Типа ТЗ
Нужно чтобы на карте был маркер чтобы при попадании на этот маркер у игрока открывалась эта мини игра, и после завершения игры игроку выдавалась определенная сумма игровой валюты

Делаем

1- Создадим в любом месте на компьютере новую папку
2- Создадим папку rage и src
  • rage - тут будем хранить сам сервак который по идее должен будет работать на продакшене
  • src - тут будем хранить все исходники
3- Откройте этот урок и выполните все пункты из секции Настройка и создания сервера только файлы из 1‑го пункта нужно скопировать в папку rage
4- Дальше создайте внутри папки src VS Решение(*.sln), и библиотеки классов в которых будут сами исходники проекта
  1. Откроем внутри src консоль и выполним следующую команду dotnet new sln --name Keymaster
  2. Выполним следующее команды для создания нужных нам проектов
    - dotnet new classlib -f netcoreapp3.1 -o Keymaster.Rage.Server
    • dotnet new classlib -f netcoreapp3.1 -o Keymaster.Rage.Client
    • dotnet new classlib -f netcoreapp3.1 -o Keymaster.Rage.Shared
  3. Выполним следующее команды для добавления ранее созданіх проектов в решение
    - dotnet sln add Keymaster.Rage.Client
    • dotnet sln add Keymaster.Rage.Server
    • dotnet sln add Keymaster.Rage.Shared
  4. Ну и сделаем ручками папку Keymaster.Rage.Client.CEF где будем хранить все CEF ресурсы
5- Также создайте внутри src папку Libraries где мы будем хранить все нужные нам внешнее dll
6- Теперь вам нужно разыскать и забросить rage-sharp.dll и Bootstrapper.dll в папку Libraries. Где их достать вы можете прочитать в предыдущих уроках
7- Теперь давайте подключим эти библиотеки к ранее созданным проектам, добавьте следующие конфигурации в нужные *.csproj файлы
Keymaster.Rage.Client.csproj
XML:
<ItemGroup>
    <Reference Include="rage-sharp">
        <HintPath>..\Libraries\rage-sharp.dll</HintPath>
    </Reference>
</ItemGroup>
<ItemGroup>
    <ProjectReference Include="..\Keymaster.Rage.Shared\Keymaster.Rage.Shared.csproj" />
</ItemGroup>
Keymaster.Rage.Server
XML:
<ItemGroup>
    <Reference Include="Bootstrapper">
        <HintPath>..\Libraries\Bootstrapper.dll</HintPath>
    </Reference>
</ItemGroup>
<ItemGroup>
    <ProjectReference Include="..\Keymaster.Rage.Shared\Keymaster.Rage.Shared.csproj" />
</ItemGroup>
Keymaster.Rage.Shared
XML:
<ItemGroup>
    <Reference Include="Bootstrapper">
        <HintPath>../Libraries/Bootstrapper.dll</HintPath>
    </Reference>
    <Reference Include="rage-sharp">
        <HintPath>../Libraries/rage-sharp.dll</HintPath>
    </Reference>
</ItemGroup>
8- Настроим копирования готовых dll и файлов в папку сервера(rage)
Keymaster.Rage.Client
XML:
<Target Name="CopyCSFiles" AfterTargets="build">
    <ItemGroup>
        <AllOutputCSFiles Include="./**/*.cs" Exclude="./obj/**/*.*;./bin/**/*.*" />
        <AllSharedCSFiles Include="../Keymaster.Rage.Shared/Server/**/*.cs;../Keymaster.Rage.Shared/Enums/**/*.cs" Exclude="../Keymaster.Rage.Shared/obj/**/*.*;../Keymaster.Rage.Shared/bin/**/*.*" />
        <AllCEFFiles Include="../Keymaster.Rage.Client.CEF/**/*.*" />
    </ItemGroup>

    <RemoveDir Directories="../../rage/client_packages/cs_packages" />
    <RemoveDir Directories="../../rage/client_packages/cef_packages" />

    <Copy SourceFiles="@(AllOutputCSFiles)" DestinationFiles="@(AllOutputCSFiles->'../../rage/client_packages/cs_packages/%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="false" />
    <Copy SourceFiles="@(AllSharedCSFiles)" DestinationFiles="@(AllSharedCSFiles->'../../rage/client_packages/cs_packages/Shared/%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="false" />
    <Copy SourceFiles="@(AllCEFFiles)" DestinationFiles="@(AllCEFFiles->'../../rage/client_packages/cef_packages/%(RecursiveDir)%(Filename)%(Extension)')" SkipUnchangedFiles="false" />
</Target>
Keymaster.Rage.Server
XML:
<Target Name="CopyBuildFiles" AfterTargets="build">
    <ItemGroup>
        <AllOutputBuildFiles Include="$(OutputPath)\*.*" />
    </ItemGroup>

    <Copy SourceFiles="@(AllOutputBuildFiles)" DestinationFolder="../../rage/dotnet/resources/core/" SkipUnchangedFiles="false" />
</Target>

<Target Name="CopyPublishFiles" AfterTargets="publish">
    <ItemGroup>
        <AllOutputBuildFiles Include="$(OutputPath)\publish\*.*" />
    </ItemGroup>

    <Copy SourceFiles="@(AllOutputBuildFiles)" DestinationFolder="../../rage/dotnet/resources/core/" SkipUnchangedFiles="false" />
</Target>
9- Также в папке Keymaster.Rage.Server не забудьте создать файл meta.xml в который необходим для того что rage мог как-то определить конфиги ресурса, и добавьте в Keymaster.Rage.Server.csproj следующий конфиг
XML:
<ItemGroup>
    <None Update="meta.xml">
        <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    </None>
</ItemGroup>
10- Теперь загрузите этот архив, разархивируйте содержимое в папку Keymaster.Rage.Client.CEF
Теперь разберемся что там за файлы в этом архиве
После того как вы забросите все папки и файлы из архива в Keymaster.Rage.Client.CEF у вас должна получиться примерно такая структура
  • css // Тут должны храниться общее css стили
    - bootstrap.css
  • js // Тут должны храниться общее js скрипты
    • bootstrap.js
    • jquery.js
    • popper.js
  • keymaster-game // А это уже папке где лежит сама наша игра
    • index.html // Верстка, думаю тут без пояснений
    • script.js // JS Скрипт, думаю тут тоже без пояснений
    • style.css // Стили, думаю тут тоже без пояснений
Но все таки хотелось бы заглянуть в script.js файл, и пояснить за объект settings который на 7-й строке, массив keys на 22 строке и к методу sendResult на 272 строке
Объект settings это конфиг нашей игры, а именно в нем есть небольшое количество параметров описание которых есть ниже
JavaScript:
let settings = {
  handleEnd: true, // Определяет, будет ли открываться модальное окно после завершения игры
  speed: 2, // Скорость передвижения  объекта -> Пикселей/Секунду
  baseSpeed: 2, // То же самое что и speed
  scoreWin: 50, // Счет для выигрыша
  scoreLose: -50, // После превышения этого счета игра автоматически завершить
  maxTime: 30000, // Время по истечению которого игра автоматически завершиться
  maxMistake: 5, // Максимально допустимое количество пропущенных клавиш
  speedIncrement: 1, // Из названия все понятно
}
JavaScript:
const sendResult = () => {
  if (mp != null) {
    mp.trigger("Browser:Close", window.browserId); // Тригерит событие, которое закрывает текущий браузер
    mp.trigger("Client:Game:KeyMaster:SendScoreToServer", score); // Отправляет счет на сервер
  }
};
JavaScript:
// Массив keys это просто массив из клавиш которые будут отображаться у игрока
// Объект клавиши выглядит так
{
  key: "g", // Сама клавиша
  right: -128, // Стартовая позиция
  controlled: true,
  shown: true,
}
Объекты setting и keys вы можете переопределить через ExecuteJs

11- Теперь создадим класс с константами которые будет содержать названия событий для клиента и сервера, это все в проекте Keymaster.Rage.Shared
  1. Создадим папку enums где будем хранить наши классы с константами
  2. Теперь в ранее созданной папке создадим два файла -> ClientEvents.cs, ServerEvents.cs
  3. Вставим туда следующий код в ранее созданные файлы
ClientEvents.cs

C#:
namespace Keymaster.Rage.Shared.Enums
{
    public class ClientEvents
    {
        // Client
        public const string OpenKeyMasterGame = "Client:Game:KeyMaster:Open";
        public const string PushIntoChat = "Client:Chat:Push";

        // Browser
        public const string SendScoreFromKeyMasterGame = "Client:Game:KeyMaster:SendScoreToServer";
    }
}
ServerEvents.cs

C#:
namespace Keymaster.Rage.Shared.Enums
{
    public class ServerEvents
    {
        public const string ProcessScoreFromKeyMasterGame = "Server:Game:KeyMaster:Score:Process";
    }
}

12- Далее создадим две папки, а именно: Server и Client
13- Внутри папки Server создадим файл KeyMasterGameEvents.cs и вставим туда следующий код

C#:
namespace Keymaster.Rage.Shared.Server
{
    public static class KeyMasterGameEvents
    {
        public static void SendScore(int score) =>
            RAGE.Events.CallRemote(Enums.ServerEvents.ProcessScoreFromKeyMasterGame, score);
    }
}

14- Внутри папки Client создадим файл ChatEvents.cs и вставим туда следующий код
C#:
using GTANetworkAPI;

namespace Keymaster.Rage.Shared.Client
{
    public static class ChatEvents
    {
        public static void PushMessage(Player player, string message) =>
            player.TriggerEvent(Keymaster.Rage.Shared.Enums.ClientEvents.PushIntoChat, message);
    }
}

15- Сейчас приступим к написанию серверной части, для начала добавим этот код в файл meta.xml
XML:
<meta>
    <info name="Core" description="Core" />

    <script src="./Keymaster.Rage.Server.dll" />
</meta>
16- Теперь создадим папку Systems в которой будем хранить разные системы

17- Создадим внутри ранее созданной папки два файла KeyMasterGame.Events.cs(Для событий которые как-то связанны с этой системой) и KeyMasterGame.Checkpoints.cs(Здесь все что связанно с чекпоинтами для этой системы)
18- Забросим в файл KeyMasterGame.Events.cs следующий код
19- Забросим в файл KeyMasterGame.Checkpoints.cs следующий код

20- Теперь приступим к созданию клиента, для начала создадим файл Browser.cs который будет играть роль Обёртки поверх дефолтного HtmlWindow, и вставим туда этот код
21- Создадим файл BrowserContainer.cs который будет играть роль контейнера для браузеров, и вставим туда этот код

22- Создадим папку Exceptions, а внутри этой папки файл BrowserNotFoundException.cs, и вставим туда этот код

23- Создадим папку BrowserEvents, а внутри этой папки файл Browser.cs, и вставим туда этот код

24- Создадим папку Events
25- Внутри ранее созданной папки создадим файл Chat.cs, в который вставим следующий код
26- Ну и наконец-то создадим файл KeyMasterGame.cs внутри ранее созданной папки, и вставим туда следующий код

Ну а дальше собираете все ваши проекты, и запускаете сервак
Этот код не претендует на идеальность поскольку потребности как таковой в этом нет, его все еще можно улучшить

Все исходники есть на GitHub, можете загрузить их и поиграться

Видос

Буду надеяться что я вам как-то помог, также желаю вам удачи в жизни и разработке
Если есть какие-то пожелание, рекомендации, или замечания, то пишите их ниже в ответах к данному посту
Также вы можете писать свои отзывы/идеи для статей или уроков(возможно кто-то заметит и сделает) в комментариях под этим уроком
 

Vitalik70

Начинающий специалист
9 Июл 2021
373
39
69
А переделать эту игру что бы работала как на мажестике сбор апельсинов можно? Или там другая система.
 

IronPython

Специалист
Автор темы
high coder
7 Ноя 2020
169
64
82
А переделать эту игру что бы работала как на мажестике сбор апельсинов можно? Или там другая система.
Возможно ВСЕ! Думаю если иметь голову то переделать можно :))))))