Hello everyone! It's been 2 months and a number of _not that big_ updates released since our major RAGE Multiplayer 0.4 update was announced (with which we've enjoyed a major increase in the amount of concurrent players online, thanks for that! ), so today, the development team is happy to share another 0.4 development update!
Before starting: the 0.4 testing versioning:
- 0.4a - basic 0.4 update, including multiplayer core improvements such as new streamer and most of C#/JS scripting enhancements, new UI
- 0.4b - synchronization update covering most of the flaws existed ever (almost every of player animations synchronized? yeh, right! client-side scripted animations synchronized? yes!). Examples below don't show all improvements, but some trivial cases:
climbing ladder / fall / ragdoll synchronization
cover / cover shooting / reloading weapon while running / combat roll synchronization
- 0.4c - client-side C# API release
- 0.4d - partial p2p introduction and some bonus feature
- 0.4 Stable - 0.4 ending update featuring stability improvements and not released yet features
0.4a: General Updates
- Major client-side scripting refactoring
- Part of game limits adjusted (more content could be stored in dlc packs!)
- Networking improvements made to implement *cheap* NPC traffic in future releases
- Original bike melee from GTA Online has been added into the game
- Client-side packages encryption
- Chromium has been updated to 67
- NodeJS has been updated to 10.6.0 (V8: 6.7.288.46)
- Compression of resources (less client-side resources download time, less drive space taken!)
- Added screenshots:// scheme to access screenshots in CEF
- Reimplemented state-of-art client-/server-side streamer tailored for the game's needs and limits
- Grand Theft Auto V's character system has been disabled that allows you to get rid of stats, but also it fixes some game glitches
0.4a: UI Updates
- Completely new launcher UI with fresh design useful features such as all country flags added!
- Game menu's alternative trigger key is disabled now
- New chat with highly requested features such as scrolling and message history
- Main menu: disconnect button
- Main menu: fixed server list visual issues
- Game pause menu: removed useless tabs
0.4a: Stability / Performance Updates
- Initial loading optimizations for multiple cases: a) lots of players joining b) lots of entities spawned
- JS runtime optimizations
- Optimized shared data
- Optimized CEF rendering
- Optimized nametag rendering
- Fixed Windows 7-related issues
- Fixed server-side native triggers
- Fixed several server-side C# functions
- Fixed client-side peds-related crash
- Improved client's threading model
- Fixed takeScreenshot paths
- Optimized 3d text label rendering
- Drastically improved performance of triggers containing really huge data
- Improved JS API memory management
- Fixed vehicle number plate value in vehicle constructor being ignored for existing players
- Fixed some face features not applying well when not set using SetFaceFeature
- Fixed recently added clothes drawables not working
- Fixed game crashes in specific game locations
- Fixed vehicle.repair() keeping exploded vehicles not usable
- Fixed heavy vehicles sounds
- Fixed waypoint events
- Fixed vehicle customization not setting correctly for connected players
- Improved updater downloading performance
- Fixed game when crash large amount of players/peds streams in
- Fixed disabled game menu input issue
- Server-side entity streaming performance has been improved
- Other miscellaneous stability improvements and API fixes
0.4a: API Updates
- Internal wrappers initially created for C# were moved into the server core to improve stability, supportability and make it possible to be used by different APIs (e.g., it could be imported directly into any language that supports C interoperability).
Code
// a short example of using Player::Spawn at LuaJIT (considering you have basic LuaJIT hosting plugin)@@@WCF_PRE_LINEBREAK@@@local ffi = require("ffi")@@@WCF_PRE_LINEBREAK@@@@@@WCF_PRE_LINEBREAK@@@ffi.cdef[[@@@WCF_PRE_LINEBREAK@@@void SpawnPlayer(unsigned short playerId, float x, float y, float z, float heading);@@@WCF_PRE_LINEBREAK@@@]]@@@WCF_PRE_LINEBREAK@@@@@@WCF_PRE_LINEBREAK@@@ffi.C.SpawnPlayer(playerId, 0.0, 0.0, 0.0, 0.0)
- Server-side facial decorations
- Client-/server-side weapon components API
Code
// tints@@@WCF_PRE_LINEBREAK@@@player.setWeaponTint(weapon, tint);@@@WCF_PRE_LINEBREAK@@@let tint = player.getWeaponTint(weapon);@@@WCF_PRE_LINEBREAK@@@@@@WCF_PRE_LINEBREAK@@@// weapon attachments@@@WCF_PRE_LINEBREAK@@@player.addWeaponAttachment(weapon, attachment); // attachment is attachment hash or an array of hashes@@@WCF_PRE_LINEBREAK@@@player.removeWeaponAttachment(weapon, attachment);@@@WCF_PRE_LINEBREAK@@@player.hasWeaponAttachment(weapon, attachment);
- Server-side entity attachments:
Code
entity.attachTo(targetEntity, bone, positionOffset, rotationOffset);@@@WCF_PRE_LINEBREAK@@@entity.attachment@@@WCF_PRE_LINEBREAK@@@entity.attachedTo@@@WCF_PRE_LINEBREAK@@@entity.attachedEntities
- Blip API enhancements: attachments, radius functionality:
Code
blip.radius = 10; // set radius@@@WCF_PRE_LINEBREAK@@@@@@WCF_PRE_LINEBREAK@@@mp.blips.new(1, [0.0, 0.0, 0.0], @@@WCF_PRE_LINEBREAK@@@{@@@WCF_PRE_LINEBREAK@@@ radius: 20 // set radius in constructor@@@WCF_PRE_LINEBREAK@@@});@@@WCF_PRE_LINEBREAK@@@@@@WCF_PRE_LINEBREAK@@@mp.blips.newAttached(1, entity, // attached blips@@@WCF_PRE_LINEBREAK@@@{@@@WCF_PRE_LINEBREAK@@@ alpha: 100@@@WCF_PRE_LINEBREAK@@@});
- 0.4d+: Client-to-client triggers (if p2p connection is established, then delivered directly, otherwise the server is used):
Code
// client 2@@@WCF_PRE_LINEBREAK@@@mp.events.add("private_message", (player, msg) =>@@@WCF_PRE_LINEBREAK@@@{@@@WCF_PRE_LINEBREAK@@@ mp.gui.chat.push(`${player.name} [${player.remoteId}]: ${msg}`);@@@WCF_PRE_LINEBREAK@@@});@@@WCF_PRE_LINEBREAK@@@@@@WCF_PRE_LINEBREAK@@@// client 1@@@WCF_PRE_LINEBREAK@@@let receiver = mp.players.atRemoteId(playerId);@@@WCF_PRE_LINEBREAK@@@@@@WCF_PRE_LINEBREAK@@@if(mp.players.local.p2pAllowed) // check if the player (local player in that case) allows p2p connections@@@WCF_PRE_LINEBREAK@@@{@@@WCF_PRE_LINEBREAK@@@ if(receiver.connected) // check if direct client-to-client connection is established@@@WCF_PRE_LINEBREAK@@@ {@@@WCF_PRE_LINEBREAK@@@ receiver.call("private_message", ["hello beast"]);@@@WCF_PRE_LINEBREAK@@@ }@@@WCF_PRE_LINEBREAK@@@}
- Asynchronous evented triggers answers:
Code
// clientside@@@WCF_PRE_LINEBREAK@@@mp.events.add("this_event_returns_something", (argument1) =>@@@WCF_PRE_LINEBREAK@@@{@@@WCF_PRE_LINEBREAK@@@ return [argument1*10, argument1*100];@@@WCF_PRE_LINEBREAK@@@});@@@WCF_PRE_LINEBREAK@@@@@@WCF_PRE_LINEBREAK@@@// serverside@@@WCF_PRE_LINEBREAK@@@player.call("this_event_returns_something", [5], (player, argument1, argument2) =>@@@WCF_PRE_LINEBREAK@@@{@@@WCF_PRE_LINEBREAK@@@ console.log(argument1, argument2); // 50 500@@@WCF_PRE_LINEBREAK@@@});
- Game legacy version native identifiers were (re-)added into the game on par with current game update ones. Since it's actually added, but not translated, performance is absolutely same and no overhead has been added (No worries, there's no native collisions):
Code
let maxWantedLevel = mp.game.invoke("0xB89B7DB2727D69D6"); // uses 1.43 hash@@@WCF_PRE_LINEBREAK@@@let maxWantedLevel = mp.game.invoke("0x462E0DB9B137DC5F"); // uses legacy native, that is possible in 0.4
- Client-side `entityDataChange` has been replaced with `mp.events.addDataHandler(name, handler)`
Code
mp.events.add("entityDataChage", (name, value) => { if(name === 'score') { code; } }); // old, wont work in 0.4@@@WCF_PRE_LINEBREAK@@@mp.events.addDataHandler("score", (value) => { code; }); // new
- New: bool OnIncomingConnection(ip, serial, rgscName):
Code
mp.events.add("incomingConnection", (ip, serial, rgscName) =>@@@WCF_PRE_LINEBREAK@@@{@@@WCF_PRE_LINEBREAK@@@ return whitelistedSerials.indexOf(serial) !== -1; // allow connection only in case if "whitelistedSerials" contains our serial@@@WCF_PRE_LINEBREAK@@@});
- Added vehicle body/engine health server-side setters:
- Updated native invoker that supports references and different return values
Code
// mp.game.invoke(native[, returnValueType], arguments)@@@WCF_PRE_LINEBREAK@@@@@@WCF_PRE_LINEBREAK@@@// 0xD75960F6BD9EA49C BOOL GET_PED_LAST_DAMAGE_BONE(Ped ped, int* outBone)@@@WCF_PRE_LINEBREAK@@@// 0x17C07FC640E86B4E Vector3 GET_PED_BONE_COORDS(Ped ped, int boneId, float offsetX, float offsetY, float offsetZ)@@@WCF_PRE_LINEBREAK@@@@@@WCF_PRE_LINEBREAK@@@// this native shows just an example of updated invoker, however in real environment this code could've been implemented using client-side API and especially Player class method@@@WCF_PRE_LINEBREAK@@@const types = mp.game.invokeTypes;@@@WCF_PRE_LINEBREAK@@@@@@WCF_PRE_LINEBREAK@@@let argumentsWithAReference = [player, 0];@@@WCF_PRE_LINEBREAK@@@@@@WCF_PRE_LINEBREAK@@@if(mp.game.invoke("0xD75960F6BD9EA49C", argumentsWithAReference))@@@WCF_PRE_LINEBREAK@@@{ @@@WCF_PRE_LINEBREAK@@@ let boneCoords = mp.game.invoke("0x17C07FC640E86B4E", @@@WCF_PRE_LINEBREAK@@@ types.Vector3,@@@WCF_PRE_LINEBREAK@@@ [player, argumentsWithAReference[1], 0, 0, 0]);@@@WCF_PRE_LINEBREAK@@@ @@@WCF_PRE_LINEBREAK@@@ mp.gui.chat.push(`Bone: ${argumentsWithAReference[1]}; ${boneCoords.x}, ${boneCoords.y}, ${boneCoords.z}`);@@@WCF_PRE_LINEBREAK@@@}
- Objects/ped/markers/checkpoints/pickups got streaming API:
Code
mp.objects.new(model, position,@@@WCF_PRE_LINEBREAK@@@{@@@WCF_PRE_LINEBREAK@@@ streamDistance: streamDistance // pass stream distance as an additional param on creation@@@WCF_PRE_LINEBREAK@@@});@@@WCF_PRE_LINEBREAK@@@@@@WCF_PRE_LINEBREAK@@@object.streamDistance = 300; // or set it later@@@WCF_PRE_LINEBREAK@@@@@@WCF_PRE_LINEBREAK@@@object.streamDistance = 5000; // make the object globally visible@@@WCF_PRE_LINEBREAK@@@@@@WCF_PRE_LINEBREAK@@@object.notifyOnStreamingUpdate = true; // makes it calling entityStreamIn/Out; false by default@@@WCF_PRE_LINEBREAK@@@@@@WCF_PRE_LINEBREAK@@@object.hidden = true; // hide entity from the world
- JS setVarible got support of setting variables from an object (which is more optimized way, by the way):
- Added "dummy" entities that allow you to add your own entities (for example a server-side fire, particle or virtual entities like ATM). Here's a really quick example of server-side static peds - a highly asked feature :
Code
// client-side@@@WCF_PRE_LINEBREAK@@@function initializeStaticPeds()@@@WCF_PRE_LINEBREAK@@@{@@@WCF_PRE_LINEBREAK@@@ mp.dummies.forEachByType(1337, (entity) => // loop though dummy entities with "dummy" id 1337@@@WCF_PRE_LINEBREAK@@@ {@@@WCF_PRE_LINEBREAK@@@ if(!entity.pedInstance)@@@WCF_PRE_LINEBREAK@@@ {@@@WCF_PRE_LINEBREAK@@@ entity.pedInstance = mp.peds.new(entity.getVariable("position"), entity.getVariable("heading"), (function(ped)@@@WCF_PRE_LINEBREAK@@@ {@@@WCF_PRE_LINEBREAK@@@ ped.taskPlayAnim(this.getVariable("animationDict"), this.getVariable("animation"), 8.0, 1.0, -1, this.getVariable("animationFlag"), 1.0, true, true, true);@@@WCF_PRE_LINEBREAK@@@ }).bind(entity), entity.dimension);@@@WCF_PRE_LINEBREAK@@@ @@@WCF_PRE_LINEBREAK@@@ entity.pedInstance.parentEntity = entity;@@@WCF_PRE_LINEBREAK@@@ }@@@WCF_PRE_LINEBREAK@@@ });@@@WCF_PRE_LINEBREAK@@@}@@@WCF_PRE_LINEBREAK@@@@@@WCF_PRE_LINEBREAK@@@// server-side@@@WCF_PRE_LINEBREAK@@@function addStaticPed(model, position, heading, animationDict, animationFlag, animation, dimension)@@@WCF_PRE_LINEBREAK@@@{@@@WCF_PRE_LINEBREAK@@@ let entity = mp.dummies.new(1337, // dummy entity type@@@WCF_PRE_LINEBREAK@@@ dimension,@@@WCF_PRE_LINEBREAK@@@ { // initial shared variables@@@WCF_PRE_LINEBREAK@@@ heading: heading,@@@WCF_PRE_LINEBREAK@@@ animationDict: animationDict,@@@WCF_PRE_LINEBREAK@@@ animationFlag: animationFlag,@@@WCF_PRE_LINEBREAK@@@ animation: animation@@@WCF_PRE_LINEBREAK@@@ });@@@WCF_PRE_LINEBREAK@@@ @@@WCF_PRE_LINEBREAK@@@ entity.playAnimation = function(dict, anim) { this.setVariable({ animationDict: dict, animation: animation }); };@@@WCF_PRE_LINEBREAK@@@ @@@WCF_PRE_LINEBREAK@@@ return entity;@@@WCF_PRE_LINEBREAK@@@}
0.4a: C# API Updates
- Added: unique object instancing that is useful to compare different objects with same NetHandles
- Updated: model enums are up to date now
- Changes: Value type arguments are now passed by read-only reference to avoid unnecessary heap allocations. readonly-ref.md (Github)
- Fixes: Resolved runtime assembly issues, bridge should be fully standalone.
- Fixes: The bridge now has its own Newtonsoft.Json to avoid version conflicts with the user-loaded (newer/older) assembly.
- Fixes: Dynamic type no longer relies on an older Microsoft.CSharp.dll assembly which was a workaround.
-
Added: Methods to register Commands at runtime using
NAPI.Command.Register
andNAPI.Command.Unregister
- Added: Method and property to Client to Block parsing commands
-
Added: Methods to invoke RemoteEvents and Commands using
NAPI.RemoteEvent.Invoke
andNAPI.Command.Invoke
-
Added: Ability to register RemoteEvents at runtime using
NAPI.RemoteEvent.Register
andNAPI.RemoteEvent.Unregister
- Updated: Bootstrapper now relies on .NET Core 2.1.0
- Important: Bridge's framework update now targets netcoreapp2.1, make sure to set your target framework to .NET Core 2.1 in your projects for the resource to function properly, this framework update brings a lot of performance improvements over .NET Core 2.0 as well as the missing features for EF Core importantly.
- Updated: Overall bridge performance improvements and optimizations. most evidently, ClientEvent Triggers now perform at least 2 times faster than they did before.
- Updated: Allow Instantiating private ctors (fool-proofing)
- Updated: Commands, ServerEvents and RemoteEvents should no longer require a public (& non-static) access modifier. for example
- Removed: The unable to locate .NET Core SDK message, the bridge is self-contained and does not require any SDKs to be installed.
- Fixed: VehicleSirenToggle event
- Fixed: Vehicle Trailer API
- Added: Driver property to Vehicle object (OOP)
- Added: Commands Attributes, this should be an alternative to the current ones. Here's an example of usage and a list of available attributes
- Added: RemainingText parameter attribute to Commands, this should replace GreedyArg. Here's an example of usage
- Removed: NativeHashes enum (obsolete)
- Added: Disabling default server behaviour event attributes: [DisableDefaultChat], [DisableDefaultOnConnectSpawn] and [DisableDefaultOnDeathRespawn], example of usages can be seen, as following on OnChatMessage, OnPlayerDeath and OnPlayerConnected.
- Added: GetAllPlayers to ColShape object (OOP)
-
Added: Included Windows-1251 (Cyrillic) Encoding by default
Encoding.GetEncoding("Windows-1251")
- Fixed: Cast exceptions and other bugs reported by users.
- Added: As much as possible fool-proofing to avoid devs falling in pitfalls of mistakes
- Added: ConsoleOutput overloads with the ability to output colorful text on console.. examples of usages: here
-
Updated: NAPI.Log.Exception now has a customizable file param, example usage:
NAPI.Log.Exception("Ouch, I've crashed!", "server_ouches.txt")
- Added: GetServerPassword method
-
Added: New server events such as
VehicleDeathEx
with additional reason and killer params - Added: A Remote Console that can interact with the server directly which supports multiple kinds of input. very useful for development and testing without having to in-game. You can read the documentation here
- Fixed: A couple of memory leaks in ClientEvent triggers
- Fixed: Vehicle mods API
- Fixed: Clean up EntityData after deletion
- Added: Default resource template creation for an easy resource creation using the guides as following: Setting up a dev env using Visual Studio and Setting up a dev env using Visual Studio Code
*0.4a changelogs are non-final and still are subject to change. Full 0.4b-0.4 Stable changelogs will be posted at its release.