Sign in to follow this  
ragempdev

devblog RAGE Multiplayer 0.3.7 Public Testing

Recommended Posts

RAGE Multiplayer 0.3.7 is another iteration of the 0.4 major features testing backport, this update is to assure the smoothest transition to 0.4.

 

0.3.7 introduces backports of major client-side scripting subsystem improvements, such as C# implementation (.NET Core, just like server-side) bringing new possibilities for C# game mode developers, but enhancements for the JavaScript runtime as well.

 

C#

C# scripts are stored in the /client_packages/cs_packages/ folder. Once a player connects, it collects all the scripts, checks its integrity and compiles into an in-memory assembly. Thanks to a number of compilation-time checks, there's no way to allow C# client-side scripts to maliciously hurt users.

Despite the community concerns, all events and functions are available in C#!

 

Here's a quick peek of basic C# stuff:

 

EVENTS

 

public class EventsExample : RAGE.Events.Script
{
  public EventsExample()
  {
    // this kind of events receives mp.trigger, mp.events.callLocal, but also remote events
    RAGE.Events.AddEvent("remote_triggerable_event", SomeEvent);
    
    RAGE.Events.AddDataHandler("some_data", SomeDataHandler);
    
    RAGE.Events.Tick += Tick;
    RAGE.Events.OnPlayerChat += ChatHandler;
    
    // trigger a js event
    RAGE.Events.CallLocal("eventName", 1, "someString", 1.0f);
  }
  
  public void SomeEvent(object[] args)
  {
  }
  
  public void SomeDataHandler(RAGE.Elements.Entity entity, object value)
  {
  }
  
  public void ChatHandler(string text, RAGE.Events.CancelEventArgs cancel)
  {
    if(text == "cancelme")
    {
    	cancel.Cancel = true;
    }
  }
  
  // known as "render" in JS
  public void Tick(System.Collections.Generic.List<RAGE.Events.TickNametagData> nametags)
  {
  }
}

 

GAME INTERACTION

// trivial game stuff
int interior = RAGE.Game.Interior.GetInteriorFromCollision(0.0f, 0.0f, 0.0f);

// player interaction
RAGE.Elements.Entities.Players.GetAtRemote(1).ClearDecorations();

// player interaction using a game entity handle
RAGE.Game.Ped.ClearPedDecorations(RAGE.Elements.Player.LocalPlayer.Handle);

// ped creation
uint freeroamHash = RAGE.Game.Misc.GetHashKey("mp_m_freemode_01");
RAGE.Elements.Ped ped = new RAGE.Elements.Ped(freeroamHash, new RAGE.Vector3(0.0f, 0.0f, 0.0f), dimension: 5);

 

 

CEF

 

...
  
public void OurEventHandler(object[] args)
{
  RAGE.Chat.Output("Got actually called! {0}", (string)args[0]);
}
  
public void TriggerMe()
{
  	RAGE.Events.Add("eventExample", OurEventHandler);
  
	RAGE.Ui.HtmlWindow wnd = new RAGE.Ui.HtmlWindow("package://index.html");
 	wnd.ExecuteJs("mp.trigger('eventExample', 'yep')");
  
  	// "mp.gui.execute"
  	RAGE.Ui.DefaultWindow.ExecuteJs("test()");
}

 

 

BUILT-IN NATIVEUI

 

using System;
using System.Collections.Generic;

using RAGE.NUI;

public class MenuExample
        : RAGE.Events.Script
{
    private bool ketchup = false;
    private string dish = "Banana";
    private MenuPool _menuPool;

    public void AddMenuKetchup(UIMenu menu)
    {
        var newitem = new UIMenuCheckboxItem("Add ketchup?", ketchup, "Do you wish to add ketchup?");
        menu.AddItem(newitem);
        menu.OnCheckboxChange += (sender, item, checked_) =>
        {
            if (item == newitem)
            {
                ketchup = checked_;
                Notify("~r~Ketchup status: ~b~" + ketchup);
            }
        };
    }

    public void AddMenuFoods(UIMenu menu)
    {
        var foods = new List<dynamic>
        {
            "Banana",
            "Apple",
            "Pizza",
            "Quartilicious",
            0xF00D, // Dynamic!
        };
        var newitem = new UIMenuListItem("Food", foods, 0);
        menu.AddItem(newitem);
        menu.OnListChange += (sender, item, index) =>
        {
            if (item == newitem)
            {
                dish = item.IndexToItem(index).ToString();
                Notify("Preparing ~b~" + dish + "~w~...");
            }

        };
    }

    public void AddMenuCook(UIMenu menu)
    {
        var newitem = new UIMenuItem("Cook!", "Cook the dish with the appropiate ingredients and ketchup.");
        newitem.SetLeftBadge(UIMenuItem.BadgeStyle.Star);
        newitem.SetRightBadge(UIMenuItem.BadgeStyle.Tick);
        menu.AddItem(newitem);
        menu.OnItemSelect += (sender, item, index) =>
        {
            if (item == newitem)
            {
                string output = ketchup ? "You have ordered ~b~{0}~w~ ~r~with~w~ ketchup." : "You have ordered ~b~{0}~w~ ~r~without~w~ ketchup.";
                Notify(String.Format(output, dish));
            }
        };
        menu.OnIndexChange += (sender, index) =>
        {
            if (sender.MenuItems[index] == newitem)
                newitem.SetLeftBadge(UIMenuItem.BadgeStyle.None);
        };
    }

    public void AddMenuAnotherMenu(UIMenu menu)
    {
        var submenu = _menuPool.AddSubMenu(menu, "Another Menu");
        for (int i = 0; i < 20; i++)
            submenu.AddItem(new UIMenuItem("PageFiller", "Sample description that takes more than one line. Moreso, it takes way more than two lines since it's so long. Wow, check out this length!"));
    }

    public void DrawMenu(System.Collections.Generic.List<RAGE.Events.TickNametagData> nametags)
    {
        _menuPool.ProcessMenus();
    }

    public MenuExample()
    {
        _menuPool = new MenuPool();
        var mainMenu = new UIMenu("Native UI", "~b~NATIVEUI SHOWCASE");
      
      	// original NativeUI replicates GTA V "interaction menu", 
      	//changing FreezeAllInput to true makes the player completely frozen
      	// while the menu is active
        mainMenu.FreezeAllInput = true;
      
        _menuPool.Add(mainMenu);
        AddMenuKetchup(mainMenu);
        AddMenuFoods(mainMenu);
        AddMenuCook(mainMenu);
        AddMenuAnotherMenu(mainMenu);
        _menuPool.RefreshIndex();

        RAGE.Events.Tick += DrawMenu;

        mainMenu.Visible = true;
    }

    public static void Notify(string text)
    {
        RAGE.Game.Ui.SetNotificationTextEntry("STRING");
        RAGE.Game.Ui.AddTextComponentSubstringPlayerName(text);
        RAGE.Game.Ui.DrawNotification(false, false);
    }
}

 

Here's how that NativeUI example looks in the game:

image.png

 

General Changes

  • JS: "entityDataChange" event has been replaced with "mp.events.addDataHandler(key, handler)"
  • JS: added mp.events.callLocal
  • Improvements on initial server loading
  • Fix voice chat not getting cleared properly after setting "voice3d" to false
  • Improve voice chat playback thread synchronization mechanism, so it doesn't affect anything else
  • Fix reported voice chat crashes
  • 0.4's game interaction performance improvements backport
  • Fix in-game UI not saving "latest IP connected to" correctly
  • DataStorage UTF-8 support fixes
  • Added a smoother voice chat packet loss handling
  • Fixed reported voice chat stability issues
  • Fixed some specific remote player tasks stuck after finished
  • Added "experimental web platform features" flag to the in-game CEF
  • Fixed key binding issues with isDown param = false

 

 

Downloads

You can download the update using the regular RAGE Multiplayer updater. Open config.xml and set your updater branch to 037_testing. Once you restart the client, it will download the update. We don't recommend to use the testing release build to play on 3rd-party servers.

NOTE: In order to enable the client-side C# API IntelliSense fanciness, you should add the "dotnet/rage-sharp.dll" as a reference. additionally, You can reference "dotnet/Newtonsoft.Json.dll" for the Json functionalities.

 

  • Like 18
  • Take2 1

Share this post


Link to post
Share on other sites
using System;
using RAGE;

namespace rageclient
{
    public class Beast : Events.Script
    {
        public void DoBeastShit()
        {
            RAGE.Chat.Output("Clientside c# is beast");
        }
    }
}

epic sauce code for you all ;)

  • Like 4
  • Mask 2
  • Sad 1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   1 member