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

Урок Browser in world

MaryDay

Специалист
14 Мар 2021
174
52
92
Не знаю считается ли это уроком, но все же. Наверное почти все видели 3d рендеры браузеров в игре на телевизорах, что выглядит довольно таки круто и вполне интересно для ваших игроков.


Решил сделать себе на коленке такое же оставлю копию тут (Код хромает не ругайтесь)0)

Первое создаем класс Browser и наследуем ему Scripts, после вставляем данный код p.s оставил пару команд для того чтоб вы могли сразу посмотреть на результат

C#:
  private readonly List<BrowserModel> _objects = new();

    // /createobj prop_x17dlc_monitor_wall_01a xm_prop_x17dlc_monitor_wall_01a
    // /createobj prop_x17_tv_scrn_12 xm_prop_x17_tv_scrn_12

    // /pushurl 0 https://www.youtube.com/watch?v=dQw4w9WgXcQ

    [Command("createobj")]
    public void CreateObject(Player player, string name, string model)
    {
        var objectData = NAPI.Object.CreateObject(NAPI.Util.GetHashKey(model), player.Position, player.Rotation, 255, player.Dimension);

        var data = new BrowserModel(objectData.Id, objectData, name, model)
        {
            Url = "",
            Active = true
        };

        _objects.Add(data);

        objectData.SetSharedData("ServerObject", data);
    }

    [Command("updaterender")]
    private void _offTvRender(Player player, int id)
    {
        var objectData = _objects.FirstOrDefault(x => x.Id == id);

        if (objectData == null)
        {
            player.SendChatMessage("Object not found!");
            return;
        }

        objectData.Active = !objectData.Active;
        objectData.Object.SetSharedData("ServerObject", objectData);
    }

    [Command("pushurl")]
    private void _pushUrl(Player player, int id, string url)
    {
        var objectData = _objects.FirstOrDefault(x => x.Id == id);

        if (objectData == null)
        {
            player.SendChatMessage("Object not found!");
            return;
        }

        objectData.Url = url;
        objectData.Object.SetSharedData("ServerObject", objectData);
    }

    [Command("removeobj")]
    private void _deleteObject(Player player, int id)
    {
        var objectData = _objects.FirstOrDefault(x => x.Id == id);

        if (objectData == null)
        {
            player.SendChatMessage("Object not found!");
            return;
        }

        objectData.Active = false;
        objectData.Object.SetSharedData("ServerObject", objectData);

        NAPI.Task.Run(() =>
        {
             objectData.Object.Delete();
             _objects.Remove(objectData);
        }, 250);


        _objects.Remove(objectData);
    }

Далее создаем класс BrowserModel и вставляем в его следующее

C#:
    public ushort Id { get; set; }
    public Object Object { get; set; }
    public string ObjectName { get; set; }
    public string ObjectModel { get; set; }
    public string Url { get; set; } ;
    public bool Active { get; set; };

    public BrowserModel()
    {

    }

    public BrowserModel(ushort id, Object obj, string objectName, string objectModel)
    {
        Id = id;
        Object = obj;
        ObjectName = objectName;
        ObjectModel = objectModel;
    }

И так же нам нужен browser.js и в него мы вставляем этот код
JavaScript:
let player = mp.players.local;
mp.events.add("render", () =>
{
     renderObject();
})
let renderBrowsers = new Map();

function renderObject()
{
    mp.objects.forEachInRange(player.position, 30, (obj) =>
    {
        let serverData = obj.getVariable("ServerObject");
        if (!serverData) return;
        mp.game.graphics.drawText(`Телевизор ${obj.remoteId } [${serverData.Url}]`, [obj.position.x, obj.position.y, obj.position.z + 2], {
            font: 0,
            color: [255, 255, 255, 185],
            scale: [0.20, 0.20],
            outline: true
        });
        let browser = renderBrowsers.get(obj.remoteId);
        let render = CreateRenderTarget(serverData.ObjectName, serverData.ObjectModel);

        if (serverData.Active == false)
        {
            if (browser != null)
            {
                browser.destroy();
                renderBrowsers.delete(obj.remoteId);
            }
            return;
        }
        if (browser == null)
        {
            renderBrowsers.set(obj.remoteId, mp.browsers.newHeadless(serverData.Url, 1920, 1080, false));
        }
        if (browser.url !== serverData.Url)
        {
            browser.url = serverData.Url;
        }
        browser.inputEnabled = false;
        RenderThings(render, browser)

    })
}
function RenderThings(render, browser)
{
    mp.game.ui.setTextRenderId(render); //Set render ID of render target
    mp.game.graphics.set2dLayer(4); //Only layer 4 works
    if (browser && mp.browsers.exists(browser)) {
        mp.game.graphics.drawSprite(browser.headlessTextureDict, browser.headlessTextureName, 0.5, 0.5, 1, -1, 0, 255, 255, 255, 255, true);
        //mp.game.graphics.drawSprite(test.headlessTextureDict, test.headlessTextureName, 0.5, 0.5, 1, 1, 0, 255, 255, 255, 100, true);
    }


    mp.game.ui.setTextRenderId(1); //Do not forget to reset the render ID. 1 is always the default render target the game uses
}

function CreateRenderTarget(name, model)
{
    if(!mp.game.ui.isNamedRendertargetRegistered(name))
        mp.game.ui.registerNamedRendertarget(name, false); //Register render target
    if(!mp.game.ui.isNamedRendertargetLinked(mp.game.joaat(model)))
        mp.game.ui.linkNamedRendertarget(mp.game.joaat(model)); //Link it to all models
    if(mp.game.ui.isNamedRendertargetRegistered(name))
        return mp.game.ui.getNamedRendertargetRenderId(name); //Get the handle
    return -1;
}


Вуаля у нас есть телевизор, но есть несколько нюансов, о которых вам нужно знать.

1. Это качество изображений на объектах, на большинстве объектов качество хромает и это не поправить об этом сказал сам Георг (Владелец рейджа)
2. К сожалению данный браузер нельзя синхронизировать в явном нам понимании. Так что придется пользоваться прямыми трансляциями это единственный известный мне вариант.
3. Все объекты на которых можно рендерить можно найти тут => https://wiki.rage.mp/index.php?title=Render_Targets
4. Есть нюансы при использовании, на одном объекте одного типа можно назначить только один браузер
То есть если я создам два телевизора prop_x17dlc_monitor_wall_01a, и задам им разные ссылки рендер будет навешивать один и тот же браузер на каждый из них при пуше новой ссылки на один из телевизоров.

Далее по функционалу кода.

createobj - Создаст объект телевизора
updaterender - Команда не описывает её действия, но тем не менее дает возможность отключить/включить рендер данного браузера.
pushurl - Задаст новую ссылку на рендер для выбранного командой объекта. (Над каждым телевизором будет видеть информация о нем, видно на скрине)
removeobj - Удаляет телевизор

Вроде бы все код работает 100 из 100, если будут проблемы или будут предложения по улучшению прошу в комментарии

P.s И да если это может идти в конкурс который вроде еще не закончился было бы здорово)0|

UPD: Если у вас браузер перевернут, на клиенте в функции RenderThings замените строчку

mp.game.graphics.drawSprite(browser.headlessTextureDict, browser.headlessTextureName, 0.5, 0.5, 1, -1, 0, 255, 255, 255, 255, true);
На это mp.game.graphics.drawSprite(browser.headlessTextureDict, browser.headlessTextureName, 0.5, 0.5, 1, 1, 0, 255, 255, 255, 255, true);

И все должно быть гуд
 
Последнее редактирование:

MaryDay

Специалист
14 Мар 2021
174
52
92
Еще бы научится темы делать было вообще круто)0
 

kiraz

Специалист
17 Апр 2023
390
131
83
Харош братан, продолжай в том же духе!
 

m0v1l3

Специалист
29 Сен 2020
461
68
95
Это идёт в основной ветке? Если так, то всё шикарно
 

MaryDay

Специалист
14 Мар 2021
174
52
92
Это идёт в основной ветке? Если так, то всё шикарно
Если я тебя правильно понял то да. Но кстати надо учесть что бывают краши, мб это из за моего клиент сайда или же это из за рендера. Я честно говоря не тестил не с кем, но если у вас все будет гуд буду рад скрину.
 

Walter

Специалист
15 Сен 2020
185
51
89
На altv я уже давно это реализовал...
 

Walter

Специалист
15 Сен 2020
185
51
89
+- да , не особо
 

m0v1l3

Специалист
29 Сен 2020
461
68
95
Если трек не останавливать или что то в этом роде, он после удаления работает тоже, щас на всю громкость х#$рит
 

Vermilion

Мастер
29 Сен 2021
913
677
151
34
Рендер желательно удалять, если нет активных браузеров
 

m0v1l3

Специалист
29 Сен 2020
461
68
95
Только единственное что, проблема, экран будто перевёрнут чтоли

 

MaryDay

Специалист
14 Мар 2021
174
52
92
Upd Добавил новый пункт, и пофиксил недочет при удалении объекта
 
Реакции: m0v1l3

m0v1l3

Специалист
29 Сен 2020
461
68
95
Обсудили моменты, красавчик
 
Реакции: MaryDay