This is a mobile optimized page that loads fast, if you want to load the real page, click this text.

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

DaVilka

Гуру
Автор темы
16 Сен 2020
613
231
108
Кастомная реализация вызова 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
309
103
112
Круто
Чисто ради интереса, для чего это может понадобиться?
 

DaVilka

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