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

    Ошибка: Ваша версия Grand Theft Auto V не поддерживается 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/newswire/
    Статус всех служб для Rockstar Games Launcher и поддерживаемых игр: https://support.rockstargames.com/ru/servicestatus


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

Мануал [C#][Client] Кастомный ExecuteJS из поддержкой результата, Storage C#

DaVilka

Старожил
BackEnd developer
16 Сен 2020
761
276
128
Кастомная реализация вызова js кода на клиенте из C# клиента, которая так же поддерживает результат вызова.
Для начала в index.js или другом файле добавим ивент который будет просто вызывать eval и возвращать результат
в виде json строки.

JavaScript:
mp.events.add("executeJS", (code, id) => {
    let result = eval(code)
    if(id != undefined) mp.events.callLocal("executeJSCallback", id, JSON.stringify(result));
});

На стороне клиента создадим .cs файл ExecuteJS.cs
И запишем него код

Код:
using HardLife.Utils;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;

namespace HardLife.Utils
{
    internal class ExecuteJSDate
    {
        public Type Type { get; private set; }
        public Action<object> Action { get; private set; }
        public ExecuteJSDate(Type type, Action<object> action)
        {
            Type = type;
            Action = action;
        }
    }
}
internal static class ExecuteJS
{
    private static readonly Dictionary<int, ExecuteJSDate> _callback = new Dictionary<int, ExecuteJSDate>();
    private static int _id = 0;
    static ExecuteJS()
    {
        RAGE.Events.Add("executeJSCallback", ExecuteJSCallback);
    }
    private static void ExecuteJSCallback(object[] args)
    {
        //RAGE.Ui.Console.Log(RAGE.Ui.ConsoleVerbosity.Info, $"ExecuteJSCallback: {args[1]}");
        if (_callback.TryGetValue((int)args[0], out ExecuteJSDate data) && data.Action != null)
        {
            object result = Convert.ChangeType(JsonConvert.DeserializeObject((string)args[1]), data.Type);
            data.Action.Invoke(result);
        }
        if (_callback.ContainsKey((int)args[0])) _callback.Remove((int)args[0]);
    }
    public static void Execute<T>(string code, Action<T> result = null)
    {
        void action(object o) => result?.Invoke((T)o);
        _callback.Add(_id, new ExecuteJSDate(typeof(T), action));
        RAGE.Events.CallLocal("executeJS", code, _id);
        _id++;
    }
    public static void Execute(string code)
    {
        RAGE.Events.CallLocal("executeJS", code);
    }
}
Апи просто, две функции Execute
Первая предназначена для вызова функций которые хотят получить результат
C#:
Execute<T>(string code, Action<T> result = null)
Вторая просто для вызова кода на клиенте
C#:
public static void Execute(string code)

Пример использования:
Если на клиенте есть условная функция:
JavaScript:
function test(){
    return 228;
}
То вызов будет таким, где в r будет передано число (<int>) которое вернет функция на клиенте js
C#:
ExecuteJS.Execute<int>("test()", (r) => { RAGE.Ui.Console.Log(RAGE.Ui.ConsoleVerbosity.Info, $"Result: {r}"); });
Вызов без получения результата.
C#:
ExecuteJS.Execute("test()");
Пример реализации Strorage на C# с использованием ExecuteJS:

API - две функции, первая для записи по ключу, вторая для чтения
Как юзать:

Код:
internal class Test
{
    public string Name { get; set; }
    public int Id {  get; set; }
    public bool IsAlive { get; set; }
}
//Записываем обьект с ключем "test"
Storage.Write("test", new Test() { IsAlive = false, Id = 5435, Name = "Hello World" });
//получаем обьект с ключем "test"
Storage.Read("test", (Test t) =>
{
    RAGE.Ui.Console.Log(RAGE.Ui.ConsoleVerbosity.Info, $"Result: {JsonConvert.SerializeObject(t)}");
});
Код:
using Newtonsoft.Json;
using System;

namespace HardLife.Utils
{
    internal static class Storage
    {
        public static void Write<T>(string key, T data)
        {
            ExecuteJS.Execute($"mp.storage.data.{key} = '{JsonConvert.SerializeObject(data)}';");
            ExecuteJS.Execute("mp.storage.flush();");
        }
        public static void Read<T>(string key, Action<T> result)
        {
            ExecuteJS.Execute<string>($"mp.storage.data.{key}", (r) => { result?.Invoke(JsonConvert.DeserializeObject<T>(r)); });
        }
    }
}

ExecuteJS Github
 

Bloodlust

Специалист
25 Апр 2021
311
91
112
Круто
Чисто ради интереса, для чего это может понадобиться?
 

DaVilka

Старожил
BackEnd developer
16 Сен 2020
761
276
128
Круто
Чисто ради интереса, для чего это может понадобиться?
Ну вопевых storage, его нету на c#, токо js, так же есть не очень популярные апи гта которые работают не корректно на шарпе(не тот типо возаращаемого значения, или вообще не все ref можно передать и тд), а на жс норм
 
Реакции: vpn и Bloodlust

sonnyk

Участник портала
26 Ноя 2022
53
9
43
Ну вопевых storage, его нету на c#, токо js, так же есть не очень популярные апи гта которые работают не корректно на шарпе(не тот типо возаращаемого значения, или вообще не все ref можно передать и тд), а на жс норм
А какой смысл от этого? Ведь можно хранилище сделать на js и потом эвентить с c# на js, будет аналогичный эффект
А юзать eval я вообще не рекомендую, ибо крайне не безопасный
 

Dmitry_V

Гений
23 Июн 2023
2,085
342
131
27
А какой смысл от этого? Ведь можно хранилище сделать на js и потом эвентить с c# на js, будет аналогичный эффект
А юзать eval я вообще не рекомендую, ибо крайне не безопасный
А нахуя апать темы двухлетней давности?)
Ты если хочешь что-то предложить - залей в ресурсы.
 

sonnyk

Участник портала
26 Ноя 2022
53
9
43
А нахуя апать темы двухлетней давности?)
Ты если хочешь что-то предложить - залей в ресурсы.
Я просто сказал, что данный метод крайне небезопасный
Двухлетней давности, а что то поменялось, может я чего то не знаю, добавлялись только апишки и всё?
 

DaVilka

Старожил
BackEnd developer
16 Сен 2020
761
276
128
А какой смысл от этого? Ведь можно хранилище сделать на js и потом эвентить с c# на js, будет аналогичный эффект
А юзать eval я вообще не рекомендую, ибо крайне не безопасный
смысл в том что бы делать клиентку только на c#, а в чем опасность использования eval?
 

sonnyk

Участник портала
26 Ноя 2022
53
9
43
смысл в том что бы делать клиентку только на c#, а в чем опасность использования eval?
В том, что уже была ситуация со сборкой state99, где eval использовался и этим воспользовались читеры, они просто в эксекуторе передовали команды через eval и наносили вред серверу, вплоть до выкачивания файлов и запуском скримеров на экран игроков
 

DaVilka

Старожил
BackEnd developer
16 Сен 2020
761
276
128
В том, что уже была ситуация со сборкой state99, где eval использовался и этим воспользовались читеры, они просто в эксекуторе передовали команды через eval и наносили вред серверу, вплоть до выкачивания файлов и запуском скримеров на экран игроков
какие файлы, исходники клиентки? Дак они дампятся и без евалов всяких, скримеры были и на редаге, а на ней нету eval