Lines
Slide
Slide
Slide
Slide
Slide
Slide
Slide
Slide

INVENTED
WORLDS

Unity DarkRift2

Скачать

https://assetstore.unity.com/packages/tools/network/darkrift-networking-2-95309

Создать БД

CREATE DATABASE darkrift
    WITH 
    OWNER = andedali
    ENCODING = 'UTF8'
    CONNECTION LIMIT = -1;

Запуск

Разархивировать DarkRift Server (.NET Framework 4.0) Запускать DarkRift.Server.Console.exe В конфиге Server.config можно поменять порт (4296 по умолчанию)

<listeners>
    <listener name="DefaultNetworkListener" type="BichannelListener" address="0.0.0.0" port="4296
        <settings noDelay="true" />
    </listener>
</listeners>

В юнити создаём в сцене пустой объект DarkRiftClient и вешаем на него скрипт UnityClient

Билд на .NET 8.0

1. Качаем себе репозиторий с гитхаба https://github.com/DarkRiftNetworking/DarkRift (cmd в адресной строке окна куда ставить)

git clone https://github.com/DarkRiftNetworking/DarkRift

2. Скорректировать сборку, убрать не работающий плагин BadWordFilter из сборки. D:\Projects\DarkRift\DarkRift Server\DarkRift.Server\DarkRift.Server.csproj Добавить

<ItemGroup>
    <Compile Remove="Plugins\Chat\BadWordFilter.cs" />
    <Compile Remove="Plugins\Chat\IBadWordFilter.cs" />
</ItemGroup>

D:\Projects\DarkRift\DarkRift Server\DarkRift.Server\DarkRiftServer.cs Убрать

public IBadWordFilter BadWordFilter => PluginManager.GetPluginByType<BadWordFilter>();
...
typeof(Plugins.Chat.BadWordFilter),

D:\Projects\DarkRift\DarkRift Server\DarkRift.Server\Plugin.cs Убрать

public IBadWordFilter BadWordFilter => PluginManager.GetPluginByType<BadWordFilter>();

3. Обновим версию для сборки D:\Projects\DarkRift\DarkRift Server\DarkRift.Server.Console\DarkRift.Server.Console.csproj Заменить

<TargetFrameworks Condition=" '$(DRBuildMode)' != 'coreonly' ">net4.0;netcoreapp2.0;netcoreapp3.1;net5.0;net6.0;net8.0</TargetFrameworks>
<TargetFrameworks Condition=" '$(DRBuildMode)' == 'coreonly' ">netcoreapp2.0;netcoreapp3.1;net5.0;net6.0;net8.0</TargetFrameworks>

4. Сам билд

dotnet build DarkRift2.sln -c Release -f net8.0 -p:NoWarn=NU1903 -p:TreatWarningsAsErrors=false -p:SkipCopyToBuild=true

Создается D:\Projects\DarkRift\unordinal\dr-build

5. Настройка

mkdir "D:\Projects\DarkRift\unordinal\dr-build\Release\net8.0" && echo Created net8.0 directory
cd "D:\Projects\DarkRift\unordinal\dr-build\Release\net8.0"

Создаём папки

mkdir Lib
mkdir Data
mkdir Logs
mkdir Plugins

Копирование основных библиотек

copy "D:\Projects\DarkRift\unordinal\dr-build\DarkRift.Server.Console\bin\Release\net8.0\DarkRift.Server.Console.dll" "Lib\"
copy "D:\Projects\DarkRift\unordinal\dr-build\DarkRift.Server.Console\bin\Release\net8.0\DarkRift.Server.Console.deps.json" "Lib\"
copy "D:\Projects\DarkRift\unordinal\dr-build\DarkRift.Server.Console\bin\Release\net8.0\DarkRift.Server.Console.runtimeconfig.json" "Lib\"
copy "D:\Projects\DarkRift\unordinal\dr-build\DarkRift.Server.Console\bin\Release\net8.0\DarkRift.dll" "Lib\"
copy "D:\Projects\DarkRift\unordinal\dr-build\DarkRift.Server.Console\bin\Release\net8.0\DarkRift.Server.dll" "Lib\"
copy "D:\Projects\DarkRift\unordinal\dr-build\DarkRift.Server.Console\bin\Release\net8.0\DarkRift.Client.dll" "Lib\"

copy "D:\Projects\DarkRift\unordinal\dr-build\DarkRift.Server.Console\bin\Release\net8.0\*.xml" "Lib\"

copy "D:\Projects\DarkRift\unordinal\dr-build\DarkRift.Server.Console\bin\Release\net8.0\Server.config" "."

Создание bat файла

echo @echo off > start_server_net8.bat
echo cd /d "%%~dp0" >> start_server_net8.bat
echo echo Starting DarkRift Server (.NET 8.0)... >> start_server_net8.bat
echo echo. >> start_server_net8.bat
echo dotnet Lib/DarkRift.Server.Console.dll >> start_server_net8.bat
echo pause >> start_server_net8.bat

6. В самом юнити обновить dll D:\Projects\Unity\MMOProject\Assets\DarkRift\DarkRift\Plugins DarkRift.dll DarkRift.xml D:\Projects\Unity\MMOProject\Assets\DarkRift\DarkRift\Plugins\Server DarkRift.Server.dll DarkRift.Server.xml D:\Projects\Unity\MMOProject\Assets\DarkRift\DarkRift\Plugins\Client DarkRift.Client.dll DarkRift.Client.xml

Плагины

1. Соединение с БД postgres В Visual Studio 2022 Создать проект - Библиотека классов PostgresConnector .NET 8.0 Nullable ПКМ - PostgresConnector - Свойства Сборка - Общее - Допускающий значение NULL - Отключить ЛКМ - PostgresConnector

<PropertyGroup>
    <TargetFramework>net8.0</TargetFramework>
    <Nullable>disable</Nullable>
    <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
    <LangVersion>latest</LangVersion>
</PropertyGroup>

ПКМ - Зависимости - Управление пакетами NuGet... Ставим npgsql (последняя на момент 9.0.3) + зависимости (Microsoft.Extensions.Logging.Abstractions так же установить) ПКМ - Зависимости - Добавить ссылку на проект Выбрать через обзор DarkRift.dll и DarkRift.Server.dll Удалить Class1.cs ПКМ - PostgresConnector - Добавить - Создать элемент - Connector.cs

using System;
using System.Collections.Generic;
using System.Data;
using System.Threading.Tasks;
using Npgsql;

namespace PostgresConnector
{
    public static class Connector
    {
        private static string connectionString = "Host=127.0.0.1;Port=5432;Database=darkrift;Username=andedali;Password=pass;";

        public static void SetConnectionString(string value)
        {
            connectionString = value ?? throw new ArgumentNullException("value");
        }

        public static void ExecuteNonQuery(string query, params KeyValuePair<string, object>[] parameters)
        {
            try
            {
                using (NpgsqlConnection connection = new NpgsqlConnection(connectionString))
                {
                    using (NpgsqlCommand command = new NpgsqlCommand(query, connection))
                    {
                        foreach (KeyValuePair<string, object> pair in parameters)
                        {
                            command.Parameters.AddWithValue(pair.Key, pair.Value ?? DBNull.Value);
                        }

                        connection.Open();
                        command.ExecuteNonQuery();
                    }
                }
            }
            catch (NpgsqlException e)
            {
                throw new Exception(e.Message, e);
            }
        }

        public static object ExecuteScalar(string query, params KeyValuePair<string, object>[] parameters)
        {
            try
            {
                using (NpgsqlConnection connection = new NpgsqlConnection(connectionString))
                {
                    using (NpgsqlCommand command = new NpgsqlCommand(query, connection))
                    {
                        foreach (KeyValuePair<string, object> pair in parameters)
                        {
                            command.Parameters.AddWithValue(pair.Key, pair.Value ?? DBNull.Value);
                        }
                        connection.Open();
                        return command.ExecuteScalar();
                    }
                }
            }
            catch (NpgsqlException e)
            {
                throw new Exception(e.Message, e);
            }
        }

        public static Dictionary<string, object>[] ExecuteQuery(string query, params KeyValuePair<string, object>[] parameters)
        {
            try
            {
                using (NpgsqlConnection connection = new NpgsqlConnection(connectionString))
                {
                    using (NpgsqlCommand command = new NpgsqlCommand(query, connection))
                    {
                        foreach (KeyValuePair<string, object> pair in parameters)
                        {
                            command.Parameters.AddWithValue(pair.Key, pair.Value ?? DBNull.Value);
                        }
                        connection.Open();
                        using (NpgsqlDataReader reader = command.ExecuteReader(CommandBehavior.SequentialAccess))
                        {
                            int fieldCount = reader.FieldCount;
                            List<Dictionary<string, object>> rows = new List<Dictionary<string, object>>();

                            while (reader.Read())
                            {
                                Dictionary<string, object> row = new Dictionary<string, object>(fieldCount);

                                for (int i = 0; i < fieldCount; i++)
                                {
                                    object value = reader.IsDBNull(i) ? null : reader.GetValue(i);
                                    row.Add(reader.GetName(i), value);
                                }

                                rows.Add(row);
                            }

                            return rows.ToArray();
                        }
                    }
                }
            }
            catch (NpgsqlException e)
            {
                throw new Exception(e.Message, e);
            }
        }

        public static string EscapeString(string s)
        {
            if (s == null) return string.Empty;
            return s.Replace("'", "''");
        }

        // Async методы для .NET 8.0
        public static async Task ExecuteNonQueryAsync(string query, params KeyValuePair<string, object>[] parameters)
        {
            try
            {
                await using var connection = new NpgsqlConnection(connectionString);
                await using var command = new NpgsqlCommand(query, connection);

                foreach (var pair in parameters)
                {
                    command.Parameters.AddWithValue(pair.Key, pair.Value ?? DBNull.Value);
                }

                await connection.OpenAsync();
                await command.ExecuteNonQueryAsync();
            }
            catch (NpgsqlException e)
            {
                throw new Exception($"Database error: {e.Message}", e);
            }
        }

        public static async Task<object> ExecuteScalarAsync(string query, params KeyValuePair<string, object>[] parameters)
        {
            try
            {
                await using var connection = new NpgsqlConnection(connectionString);
                await using var command = new NpgsqlCommand(query, connection);

                foreach (var pair in parameters)
                {
                    command.Parameters.AddWithValue(pair.Key, pair.Value ?? DBNull.Value);
                }

                await connection.OpenAsync();
                return await command.ExecuteScalarAsync();
            }
            catch (NpgsqlException e)
            {
                throw new Exception($"Database error: {e.Message}", e);
            }
        }

        // Проверка подключения к БД с детальной диагностикой
        public static async Task<(bool success, string error)> TestConnectionAsync()
        {
            try
            {
                await using var connection = new NpgsqlConnection(connectionString);
                await connection.OpenAsync();
                bool isOpen = connection.State == ConnectionState.Open;

                if (isOpen)
                {
                    // Дополнительно проверим, что можем выполнить запрос
                    await using var cmd = new NpgsqlCommand("SELECT 1", connection);
                    await cmd.ExecuteScalarAsync();
                    return (true, "Connection successful");
                }

                return (false, $"Connection state: {connection.State}");
            }
            catch (Exception ex)
            {
                return (false, $"Connection failed: {ex.Message}");
            }
        }
    }
}

Для проверке создать логин плагин (библиотека LoginPlugin) Добавить в зависимости PostgresConnector.dll Создать Login.cs

using System;
using System.Threading.Tasks;
using DarkRift;
using DarkRift.Server;
using PostgresConnector;

namespace LoginPlugin
{
    public class Login : Plugin
    {
        public override bool ThreadSafe => true;
        public override Version Version => new Version(1, 0, 0);

        public Login(PluginLoadData pluginLoadData) : base(pluginLoadData)
        {
            // Читаем настройки из конфигурации, если есть
            if (pluginLoadData.Settings != null)
            {
                string connectionString = pluginLoadData.Settings["ConnectionString"];
                if (!string.IsNullOrEmpty(connectionString))
                {
                    Connector.SetConnectionString(connectionString);
                    Logger.Info($"Using custom connection string from config");
                }
            }

            // Инициализация плагина
            _ = InitializeAsync();
        }

        private async Task InitializeAsync()
        {
            try
            {
                Logger.Info("Initializing PostgreSQL plugin...");

                // Тестируем подключение к БД
                var (connectionSuccessful, errorMessage) = await Connector.TestConnectionAsync();

                if (!connectionSuccessful)
                {
                    Logger.Error($"Failed to connect to PostgreSQL database: {errorMessage}");
                    Logger.Info("Please check:");
                    Logger.Info("1. PostgreSQL server is running");
                    Logger.Info("2. Database 'darkrift' exists");
                    Logger.Info("3. Username/password are correct");
                    Logger.Info("4. Connection string in Connector.cs or ConnectionString in Server.config");
                    return;
                }

                Logger.Info("Successfully connected to PostgreSQL database");

                // Создаем таблицу users
                await CreateUsersTableAsync();
                Logger.Info("Users table created/verified successfully");

                // Тестовая вставка данных
                await TestDatabaseOperations();

                Logger.Info("PostgreSQL plugin initialized successfully");
            }
            catch (Exception ex)
            {
                Logger.Error($"Failed to initialize PostgreSQL plugin: {ex.Message}");
            }
        }

        // Создание таблицы users
        private static async Task CreateUsersTableAsync()
        {
            const string createTableQuery = @"
                CREATE TABLE IF NOT EXISTS users (
                    id SERIAL PRIMARY KEY,
                    username VARCHAR(50) UNIQUE NOT NULL,
                    email VARCHAR(100) UNIQUE NOT NULL,
                    password_hash VARCHAR(255) NOT NULL,
                    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
                    last_login TIMESTAMP,
                    is_active BOOLEAN DEFAULT TRUE
                );

                CREATE INDEX IF NOT EXISTS idx_users_username ON users(username);
                CREATE INDEX IF NOT EXISTS idx_users_email ON users(email);";

            await Connector.ExecuteNonQueryAsync(createTableQuery);
        }

        private async Task TestDatabaseOperations()
        {
            try
            {
                // Проверяем, есть ли уже тестовые данные
                var userCount = await Connector.ExecuteScalarAsync("SELECT COUNT(*) FROM users");
                Logger.Info($"Current users count: {userCount}");

                // Если таблица пустая, добавляем тестового пользователя
                if (Convert.ToInt32(userCount) == 0)
                {
                    await Connector.ExecuteNonQueryAsync(
                        "INSERT INTO users (username, email, password_hash) VALUES (@username, @email, @password)",
                        new System.Collections.Generic.KeyValuePair<string, object>("@username", "test_user"),
                        new System.Collections.Generic.KeyValuePair<string, object>("@email", "test@darkrift.com"),
                        new System.Collections.Generic.KeyValuePair<string, object>("@password", "hashed_password_123")
                    );

                    Logger.Info("Test user created successfully");
                }
            }
            catch (Exception ex)
            {
                Logger.Error($"Database test operations failed: {ex.Message}");
            }
        }

        protected override void Dispose(bool disposing)
        {
            if (disposing)
            {
                Logger.Info("PostgreSQL plugin disposed");
            }
            base.Dispose(disposing);
        }
    }
}

Добавить dll в D:\Projects\DarkRift\unordinal\dr-build\Release\net8.0\Plugins PostgresConnector.dll Npgsql.dll Microsoft.Extensions.Logging.Abstractions.dll LoginPlugin.dll (Пакеты - пакет - Открыть папку в проводнике, чтобы получить dll для связки)

Комментарии

Комментариев пока нет.