Libraries
59 files
-
rage_utils
By ShrewdSpirit
A bunch of utility functions for rage (cross environment: server, client, browser) that are not easy to implement in JS specially for client and browser! Also you can use this package for projects other than rage.
If you want a new feature in utilities that you think others might use too, submit an issue on github page
Install instructions, features and documentation are all available on npm registery and github page
I highly recommend visiting the linked pages and using npm/yarn for installing
107 downloads
(1 review)0 comments
Updated
-
RageMP-BigData
By noBrain
RageMP-BigData
This plugin was created for experiment and might not be what you are looking for, this is intended to be used for sending big data to clients in chunks to make the size unlimited for the server owners, this will eliminate original rage-mp events limit and will be as fast as them when being used for small data, but i suggest that you use original ones just in case.
This is still experimental and the way it works might change in a future update
GITHUB LINK : https://github.com/safra36/RageMP-BigData
API
for obvious reasons i made this only to go from server-side to client-side and not client-side to server-side, there is a commented code about this and with a bit of knowlegde you can get it to work but it's not recommended since it will basically flood your server if you have many players so stay of it!
Server-Side Functions
/** Send a big data to a player @param player valid muliplayer player object @param eventName the event which is defined on client-side (just a normal event name) @param DataArray It's an array of data like how player.call works, and it supports all types of data (objects, numbers, strings with no effect on the typing!) @callback dataReceived Optional callback triggers when the data is received in full by the client @param retry Optional param which is true by default, pass false to disable auto retry (this will cause the data to be lost, added by request but don't use it!) */ player.callBig(eventName, DataArray, dataReceived, &retry) /** Send a big data to all players @param eventName the event which is defined on client-side (just a normal event name) @param DataArray It's an array of data like how player.call works, and it supports all types of data (objects, numbers, strings with no effect on the typing! */ mp.players.callBig(eventName, DataArray) /** Set a big shared variable on players @param name name of the data @param data any type of data @callback dataReceived Optinal callback triggers when the data is received in full by the client @param retry Optional param which is true by default, pass false to disable auto retry (this will cause the data to be lost, added by request but don't use it!) */ player.setBigVariable(name, data, dataReceived, &retry) /** Get a previously set shared data on the client @param name name of the data */ player.getBigVariable(name) /** Set a big private data on client which is only set on a certain client, access it on server-side with player.privateData[dataName] You can use player.pdata.name instead from 0.0.3 @param name name of the data @param data any type of data @callback dataReceived Optinal callback triggers when the data is received in full by the client @param retry Optional param which is true by default, pass false to disable auto retry (this will cause the data to be lost, added by request but don't use it!) */ player.setPrivateData(name, data, dataReceived, &retry) /** Delete private data on server-side and client-side @param name name of the data */ player.deletePrivateData(name) Server-Side Variables
/** * Setter * Sets private data on client like setPrivateData but without optional retry * Use with try catch, it can only be set if there is no other pending data on the target name (throw error if there is a pending data) */ player.pdata.dataName = value /** * Getter * Get private data which was set, must be used with await since the data may take time to reach client; */ var data = await player.pdata.dataName; Server-Side Events
/** Detemine if a data has been fully received by the client @param player playerObject which has sent this signal @param id Id of the data sending session @param eventName Name of the even you have been called on the client previously using callBig */ mp.events.add('DataSender:End', (player, id, eventName) => {}) /** This will be called when the sent data was failed (there is an auto retry to put the data on player for sure but see this as a notification) @param id Id of the data sending session @param dataName Name of the data you have been set on the client @param errorCode -1 Means the data could not be parsed on client, -2 means there was some data chunks lost on the send proccess */ mp.events.add('DataSender:Failed', (id, dataName, errorCode) => {}) Client-Side Functions
/** Get a shared variable of a player @param name data name that was set on the player */ player.getBigVariable(name) Client-Side Variables
You can get client private data using mp.players.local.privateData[dataName] Client-Side Events
/** Get notified when a shared data get's updated on server-side @param dataName shared data name @param entityId id of the entity which this it's shared data has been updated (currently it's only a player) @param type get type of entity which is updated (player, object, vehicle, ped but currenly it's only player) @param oldData previously set data if it's forst time then it's undefined @param newData the latest data has been set on this name */ mp.events.addBigDataHandler(dataName, (entityId, type, oldData, newData) => {}) /** Get notified when a shared data get's updated on server-side @param dataName private data name @param oldData previously set data if it's forst time then it's undefined @param newData the latest data has been set on this name */ mp.events.addPrivateDataHandler(dataName, (oldData, newData) => {}) Example (BigData Event Sample)
Server-Side
// Big data is an array of rage-mp cloths (something around 15MB of data) and other ones are regular data (can be big data as well) player.callBig('GetBigData', [BigData, 'Some Other Test Arguments', 3]); Client-Side
mp.events.add('GetBigData', (BigJSONData, args1, argg2) => { mp.gui.chat.push(`Data: ${BigJSONData['Tops']['Male']['NONE'][0].name} - Type: ${typeof(BigJSONData)}`); mp.gui.chat.push(`Data: ${args1} - Type: ${typeof(args1)}`); mp.gui.chat.push(`Data: ${argg2} - Type: ${typeof(argg2)}`); }) Results
Benchmark
Well, the time it takes to transfer the data really depends on player network speed, data chunk size and the size of the data it self. For testing, i sent a very big json file contaning all rage-mp clothing with their torsos and names and prices (which i use on server-side my self), the file is something around 15MB, it took something about ~3s to transfer the whole data to the client, this is a beta version of the library but any help is accepted for optimizations.
Installation
Copy all the files to your packages/client-packages Make sure to add the client-side file to your index.js Enjoy! Known Issues
If your data fails and you set a new data which does not fail, the old data is probably gonna replace the new data over retry
104 downloads
-
Iris: An Interaction Library
By rootcause
Iris is a raycast based interaction system with two components: the core library and a basic interaction UI which can be reimplemented by server developers to fit their needs, making it highly customizable.
Installing
Put the files you downloaded in their respective places Add require("iris") to client_packages/index.js (Optional) Add require("iris-ui") to client_packages/index.js or build your own UI to handle interactions with
Clientside API
The library defines a global object named Iris that can be used to interact with the library. Here are its members:
Constants
The Iris global object has a property called SearchType which acts as an enum to avoid magic values in code:
Iris.SearchType.Invalid // 0 Iris.SearchType.EntityType // 1 Iris.SearchType.EntityModel // 2 Iris.SearchType.EntityHandle // 3 Iris.SearchType.NumSearchTypes // 4
Functions
/** * Creates an interaction. * @param {number} searchType * @param {number} target * @param {object} interaction Must have a `name` property. `order` (number) is also an optional property to display the interaction above/below other interactions. * @returns {number} The interaction ID which can be used with `getInteraction` and `removeInteraction` functions. */ Iris.createInteraction(searchType, target, interaction); /** * Returns the interaction with the specified ID. * @param {number} interactionId * @returns {object|undefined} The interaction object if found, `undefined` otherwise. */ Iris.getInteraction(interactionId); /** * Removes the interaction with the specified ID. * @param {number} interactionId * @returns {boolean} `true` if the removal is successful, `false` otherwise. */ Iris.removeInteraction(interactionId); /** * Returns whether the library is scanning for interactions or not. * @returns {boolean} */ Iris.isActive(); /** * Sets the interaction scanning status of the library. * @fires `iris::stateChange` clientside event with the first argument being the new scanning status. * @param {boolean} value */ Iris.setActive(value); /** * Returns the distance used for the interaction scanning raycast. * @returns {number} */ Iris.getRaycastDistance(); /** * Sets the distance used for the interaction scanning raycast. * @param {number} newDistance */ Iris.setRaycastDistance(newDistance); /** * Returns the flags used for the interaction scanning raycast. Refer to: https://wiki.rage.mp/index.php?title=Raycasting::testPointToPoint * @returns {number} */ Iris.getRaycastFlags(); /** * Sets the flags used for the interaction scanning raycast. Refer to: https://wiki.rage.mp/index.php?title=Raycasting::testPointToPoint * @param {number} newFlags */ Iris.setRaycastFlags(newFlags); /** * Returns the handle of the last entity that was hit by the interaction scanning raycast. * @returns {number} */ Iris.getLastEntityHandle();
Events
The library uses RAGEMP's clientside events.
/** * iris::stateChange is called when scanning for interactions is enabled/disabled. * @param {boolean} newState `true` if scanning, `false` otherwise. */ mp.events.add("iris::stateChange", function(newState) { // your code here }); /** * iris::focusChange is called when the entity detected by the interaction scanner changes. * @param {object} focusChangeContext * @param {number} focusChangeContext.newEntityHandle * @param {number} focusChangeContext.oldEntityHandle * @param {number|undefined} focusChangeContext.newEntityType * @param {number|undefined} focusChangeContext.newEntityModel * @param {object[]|undefined} focusChangeContext.interactions The available interactions for the new entity. * @param {object|undefined} focusChangeContext.raycastResult The raycast result that was responsible for calling this event, set only if the `focusChangeContext.newEntityHandle` is valid. Refer to: https://wiki.rage.mp/index.php?title=Raycasting::testPointToPoint */ mp.events.add("iris::focusChange", function(focusChangeContext) { // your code here });
Example Script
// https://wiki.rage.mp/index.php?title=Entity::getType const ENTITY_TYPE_VEHICLE = 2; const ENTITY_TYPE_OBJECT = 3; // Create some interactions // "eventName" and "selectedFn" properties only work with the default iris-ui script, they're intended to show two simple ways to handle interactions. const myVehicleInteraction = Iris.createInteraction(Iris.SearchType.EntityType, ENTITY_TYPE_VEHICLE, { name: "Generic vehicle interaction (get remoteId)", eventName: "my_custom_event_name" }); const myObjectInteraction = Iris.createInteraction(Iris.SearchType.EntityType, ENTITY_TYPE_OBJECT, { name: "Generic object interaction (get handle)", selectedFn: function(entityHandle) { mp.gui.chat.push(`This object's handle is: ${entityHandle}`); } }); const adderOnlyInteraction = Iris.createInteraction(Iris.SearchType.EntityModel, mp.game.joaat("adder"), { name: "Adder only interaction", eventName: "adder_option_clicked", order: 99 // make it the top option }); // Liquor store example (non-functional) const mp_m_shopkeep_01 = mp.game.joaat("mp_m_shopkeep_01"); mp.peds.new(mp_m_shopkeep_01, new mp.Vector3(-2966.05, 391.43, 15.05), 90.0, 0); // Options for the shopkeeper Iris.createInteraction(Iris.SearchType.EntityModel, mp_m_shopkeep_01, { name: "Ask about his day"}); Iris.createInteraction(Iris.SearchType.EntityModel, mp_m_shopkeep_01, { name: "Pay for items" }); Iris.createInteraction(Iris.SearchType.EntityModel, mp_m_shopkeep_01, { name: "Threaten" }); // Options for various items inside the store Iris.createInteraction(Iris.SearchType.EntityModel, mp.game.joaat("v_ret_ml_sweetego"), { name: "Add EgoChaser to cart ($5)" }); Iris.createInteraction(Iris.SearchType.EntityModel, mp.game.joaat("v_ret_ml_sweet4"), { name: "Add Sweet Nothings to cart ($2)" }); Iris.createInteraction(Iris.SearchType.EntityModel, mp.game.joaat("v_ret_ml_sweet3"), { name: "Add P's & Q's to cart ($1)" }); Iris.createInteraction(Iris.SearchType.EntityModel, mp.game.joaat("v_ret_ml_beeram"), { name: "Add A. M. Beer (6-pack) to cart ($12)" }); Iris.createInteraction(Iris.SearchType.EntityModel, mp.game.joaat("v_ret_ml_beerdus"), { name: "Add Dusche Gold (6-pack) to cart ($14)" }) // Event handlers function handleGetVehicleRemoteId(entityHandle) { const vehicle = mp.vehicles.atHandle(entityHandle); if (vehicle) { mp.gui.chat.push(`This vehicle's remoteId is: ${vehicle.remoteId}`); } } function handleAdderClick() { mp.gui.chat.push("You found the adder exclusive interaction... aaand it's gone."); Iris.removeInteraction(adderOnlyInteraction); Iris.setActive(false); } // Register event handlers mp.events.add({ "my_custom_event_name": handleGetVehicleRemoteId, "adder_option_clicked": handleAdderClick });
Source code is also available on GitHub: https://github.com/root-cause/ragemp-iris
100 downloads
(2 reviews)0 comments
Updated
-
Blip Info API
By rootcause
This resource adds the blip information feature that exists for (mainly) adversary modes in GTA Online.
Installing
Put the files you downloaded in their respective places Add require('blip-info') to client_packages/index.js All done
API (Clientside)
This library extends the mp.Blip prototype so these functions are available for every blip created using mp.blips.new.
/** * Attaches data to the blip. * It's recommended that you use the BlipInfoBuilder class that comes with the library to build the info object. */ blipMp.setInfo(infoObject); /** * Removes the data attached to the blip. */ blipMp.resetInfo(); BlipInfoBuilder isn't documented here but it has JSDoc comments, the example script shows how it can be used as well.
Example Script
const BlipInfoBuilder = require("./blip-info/BlipInfoBuilder"); // example blip data const garageData = [ { name: "Garage: 0120 Murrieta Heights", description: "With good access to the major roadways in and out of Los Santos, this spacious garage is perfect for the man or woman who might need to leave town in a hurry. Or is obsessed with cars.", position: new mp.Vector3(963.4199, -1022.1301, 39.8475), textureDict: "dyn_mp_24", textureName: "dyn_mp_24", slots: 10, price: 150000 }, { name: "Garage: Unit 14 Popular St", description: "If you're an individual who likes to keep their business private, look no further than this secluded garage in East Los Santos.", position: new mp.Vector3(895.9359, -888.7846, 26.2485), textureDict: "dyn_mp_25", textureName: "dyn_mp_25", slots: 6, price: 77500 }, { name: "Garage: Unit 2 Popular St", description: "Spacious garage in prime East Los Santos. Panoramic views of urban blight, walking distance to gang members.", position: new mp.Vector3(817.4532, -924.8551, 25.2430), textureDict: "dyn_mp_26", textureName: "dyn_mp_26", slots: 10, price: 142500 }, { name: "Garage: 331 Supply St", description: "Newly renovated garage with excellent square footage and direct road access. What better place to keep brand-new vehicles than the neighborhood with the highest crime rate in Los Santos?", position: new mp.Vector3(759.2387, -755.3151, 25.9151), textureDict: "dyn_mp_27", textureName: "dyn_mp_27", slots: 10, price: 135000 }, { name: "Garage: Unit 1 Olympic Fwy", description: "A good-sized garage in a quiet location within walking distance of the train for those days when you feel extra guilty about your 6-car carbon footprint.", position: new mp.Vector3(842.1298, -1165.0754, 24.3046), textureDict: "dyn_mp_28", textureName: "dyn_mp_28", slots: 6, price: 70000 }, { name: "Garage: 0754 Roy Lowenstein Blvd", description: "Located just a few brain-melting steps away from an electrical substation, you'll never have to worry losing power or reaching old age again at this garage in East Los Santos.", position: new mp.Vector3(528.8805, -1603.0293, 28.3225), textureDict: "dyn_mp_29", textureName: "dyn_mp_29", slots: 2, price: 29500 }, { name: "Garage: 12 Little Bighorn Ave", description: "Affluent on the inside, effluent on the outside! This garage offers panoramic views of the Los Santos waterways.", position: new mp.Vector3(569.9441, -1570.2930, 27.5777), textureDict: "dyn_mp_30", textureName: "dyn_mp_30", slots: 2, price: 32000 }, { name: "Garage: Unit 124 Popular St", description: "Calling all bargain hunters! In today's economy, it's all about desirable properties in undesirable areas. East Los Santos? We prefer to call it 'South of Vinewood'! Plus if the economy keeps tanking, you can go live in it!", position: new mp.Vector3(727.7570, -1189.8367, 23.2765), textureDict: "dyn_mp_31", textureName: "dyn_mp_31", slots: 2, price: 25000 } ]; const seaRaceData = [ { name: "Los Santos Port", position: new mp.Vector3(621.7491, -2136.7981, 0.0), textureDict: "spsearaces", textureName: "lossantos", recordTime: "01:23.456", recordHolder: "sea_racing_pro" }, { name: "El Gordo", position: new mp.Vector3(3447.7471, 5192.9956, 0.0), textureDict: "spsearaces", textureName: "southcoast", recordTime: "00:00.123", recordHolder: "speed0fl1ght" }, // lets say this one doesn't have a record yet { name: "Power Station", position: new mp.Vector3(3063.1135, 639.8550, 0.0), textureDict: "spsearaces", textureName: "northcoast" }, // this one doesn't have a record yet as well and has a cash bonus { name: "Lago Zancudo", position: new mp.Vector3(198.1107, 3620.3972, 27.3487), textureDict: "spsearaces", textureName: "canyon", cashMultiplier: 2.5 } ]; // event handlers function onLocalPlayerReady() { // example 1: garage blips for (const garage of garageData) { // request the texture dict mp.game.graphics.requestStreamedTextureDict(garage.textureDict, false); // create the blip garage.blip = mp.blips.new(369, garage.position, { shortRange: true }); // set garage info (using plain object) garage.blip.setInfo({ // header title: garage.name, textureDict: garage.textureDict, textureName: garage.textureName, // data components: [ { type: 0, title: "Capacity", value: `${garage.slots} vehicles` }, { type: 0, title: "Price", value: `~g~$${garage.price}` }, { type: 4 }, { type: 5, value: garage.description } ] }); // with BlipInfoBuilder it'd look like this: /* const info = new BlipInfoBuilder() .setTitle(garage.name) .setTexture(garage.textureDict, garage.textureName) .addComponent("Capacity", `${garage.slots} vehicles`) .addComponent("Price", `~g~$${garage.price}`) .addDividerComponent() .addDescriptionComponent(garage.description) .build(); garage.blip.setInfo(info); */ } // example 2: sea races mp.game.graphics.requestStreamedTextureDict("spsearaces", false); for (const race of seaRaceData) { // create the blip race.blip = mp.blips.new(316, race.position, { shortRange: true }); // set race info (using BlipInfoBuilder) const info = new BlipInfoBuilder() .setTitle(race.name) .setTexture(race.textureDict, race.textureName) .addComponentWithIcon("Type", "Sea Race", 13, 1, false); if (race.cashMultiplier) { info.setCashText(`${race.cashMultiplier}x`); } if (race.recordHolder && race.recordTime) { info.addComponentWithPlayerName("Record Holder", race.recordHolder); info.addComponent("Record Time", race.recordTime); } race.blip.setInfo(info.build()); } } function onLocalPlayerQuit(player) { if (player !== mp.players.local) { return; } // garage clean up for (const garage of garageData) { // unload the texture mp.game.graphics.setStreamedTextureDictAsNoLongerNeeded(garage.textureDict); // remove blip if (garage.blip) { garage.blip.resetInfo(); garage.blip.destroy(); } } // sea race clean up // unload the texture mp.game.graphics.setStreamedTextureDictAsNoLongerNeeded("spsearaces"); // remove blips for (const race of seaRaceData) { if (race.blip) { race.blip.resetInfo(); race.blip.destroy(); } } } // register event handlers mp.events.add({ "playerReady": onLocalPlayerReady, "playerQuit": onLocalPlayerQuit });
Credits
glitchdetector - for their research
Source code is also available on GitHub: https://github.com/root-cause/ragemp-blip-info
96 downloads
(1 review)0 comments
Submitted
-
Zone API
By rootcause
This resource adds 3 functions to the serverside mp.world object that provides zone name and type information.
Serverside API
/** * Returns the name of the area/zone at specified coords, ignores heights. * @param {object} coords An object with "x" and "y" properties. * @return {string} Zone name. */ mp.world.getNameOfZone2D(coords); /** * Returns the name of the area/zone at specified coords. * @param {object} coords An object with "x", "y" and "z" properties, such as mp.Vector3. * @return {string} Zone name. */ mp.world.getNameOfZone3D(coords); /** * Returns the type of the area/zone at specified coords. * @param {object} coords An object with "x" and "y" properties. * @return {string} Zone type, either "city" or "countryside". */ mp.world.getTypeOfZone(coords);
Example
const coords = new mp.Vector3(1823.961, 4708.14, 42.4991); // Grapeseed Bunker console.log(`Name 2D: ${mp.world.getNameOfZone2D(coords)}`); // Expected output: Grapeseed console.log(`Name 3D: ${mp.world.getNameOfZone3D(coords)}`); // Expected output: Grapeseed console.log(`Zone Type: ${mp.world.getTypeOfZone(coords)}`); // Expected output: countryside
Notes
Available on GitHub: https://github.com/root-cause/ragemp-zone-api N.O.O.S.E area returns Tataviam Mountains instead. There might be other areas with inaccuracies, feel free to share a fix in comments/send a pull request.94 downloads
(3 reviews)0 comments
Updated
-
[C# Server-Side] Events+Commands at Runtime
By robearded
Github page: https://github.com/robertnisipeanu/ragemp-server-events
ragemp-server-events
OOP Implementation of the RAGEMP server events (so you don't have to use [Command] or [ServerEvent] annotations). It allows you to add event handlers and commands at runtime.
How to use
Copy /client_packages/cs_packages/CustomCommands.cs to your server client resources (server-files/client_packages/cs_packages).
From folder 'server' import Delegates.cs and Events.cs into your server-side project.
Add using robearded; at the top of the files where you want to use my API.
Use Events.*EventName* += EventHandler; to add an event handler and Events.AddCommand("*commandName*", CommandHandler); to add a command handler.
Added events
OnPlayerReady(Client client) -> This event is not available by default on the C# API If any other events will be custom implemented they will be added here ^
Example
You can find an example inside the 'example' folder.
Need help?
Please do not contact me if you didn't followed the above steps, I'm not gonna tell you again the steps in private when you have them here.
If you need any other help, feel free to contact me on Discord at @rumble06#4127 or on RAGE.MP Forums at https://rage.mp/profile/45121-robearded/
92 downloads
(2 reviews)0 comments
Updated
-
[DISCONTINUED] Ajcom
By ShrewdSpirit
This library is discontinued and lacks some features. I'm working on a new remote call library which is faster and more secure
Asynchronous Javascript Communication is a module to allow easy communication between server, client and CEF/browser. This module lets you call server handlers from clients (and vice versa) without dealing with adding and managing custom event handlers.
You can easily call a handler and get your callback called as soon as everything is returned from the handler in a promise like way! Let's see how it works in action:
// server side const ajcom = require("./ajcom") ajcom.register("getServerName", hCtx => { return mp.config.name }) // client side const ajcom = require("./[package name]/ajcom.js") mp.events.add("guiReady", () => { ajcom.callServer("getServerName").then((ctx, serverName) => { mp.gui.chat.push(`Welcome to ${serverName} ragemp server!`) }) }) That's all! Not convinced yet? See how the above code is done without ajcom:
// server side mp.events.add("getServerName", (player) => { player.call("gotServerName", [mp.config.name]) }) // client side mp.events.add("gotServerName", (serverName) => { mp.gui.chat.push(`Welcome to ${serverName} ragemp server!`) }) mp.events.add("guiReady", () => { mp.events.callRemote("getServerName") }) See? It eases the event handling mess. But there's a lot more to ajcom. You can easily handle errors happening on handler's side or any of the callbacks, set delays and other stuff. The full documentation is available here
Please post your questions and issues to the forum post
Github repo
84 downloads
- module
- communication
- (and 1 more)
-
Colshape Handler
By nns
Simple CommonJS singleton module to handle colshape entering and exiting.
Copy the Colshapes folder inside packages inside your packages folder. See the Examples folder for an example.
Simply create your colshape like this:
const colshape = mp.colshapes.newSphere(34, 15, 69, 15, 0) colshape.name = 'example' and then pull in the colshapeHandler singleton to add it to the array the following:
const colshapeHandler = require('../Colshapes/index').getInstance() colshapeHandler.addColshape('example') If a player enters the specified colshape, the colshape name will be pushed towards a colshapes array as a player property, like this. Definition of this is inside the "playerJoin" event in the Colshapes\index.js. The specified colshape name will then be removed from the array again if the player exits the colshape.
player.colshapes = [];
83 downloads
(0 reviews)0 comments
Submitted
-
Headblend Palette Color Sync
By rootcause
This resource adds serverside API to set head blend palette colors. Head blend palette colors are used for crew colored clothing in GTA Online. (example here)
Installing
Put the files you downloaded in their respective places Add require('palette-sync') to client_packages/index.js All done
API (Serverside)
This resource adds 4 functions to the mp.Player prototype:
/** * Sets the specified head blend palette color for the player. **Make sure `player.setCustomization` is called beforehand to avoid issues.** * @param {number} paletteIndex * @param {number} red * @param {number} green * @param {number} blue * @throws If `paletteIndex` is less than 0 or higher than 3. * @throws If `red`, `green` or `blue` is not an integer between 0 to 255. */ player.setHeadBlendPaletteColor(paletteIndex, red, green, blue); /** * Sets the head blend palette colors for the player. This function should be used to update multiple palette colors at once. **Make sure `player.setCustomization` is called beforehand to avoid issues.** * @param {Array<[number, number, number, number]>} colors 2-dimensional array where each element has palette index, red, green and blue color data such as `[[0, 255, 0, 0], [3, 0, 255, 0]]`. * @throws If `colors` is not an array. * @throws If any `paletteIndex` is less than 0 or higher than 3. * @throws If any `red`, `green` or `blue` is not an integer between 0 to 255. */ player.setHeadBlendPaletteColors(colors); /** * Returns the specified head blend palette color for the player. * @param {number} paletteIndex * @throws If `paletteIndex` is less than 0 or higher than 3. * @returns {Object} An object with `red`, `green` and `blue` properties, ranging from 0 to 255. */ player.getHeadBlendPaletteColor(paletteIndex); /** * Returns the head blend palette colors for the player. * @returns {Array<Object>} An array of objects where each element has `red`, `green` and `blue` properties, ranging from 0 to 255. */ player.getHeadBlendPaletteColors();
Example (Serverside)
// EXAMPLE: Getting a specific color of the player mp.events.addCommand("mycolor", (player, _, index) => { index = Number(index); const paletteColor = player.getHeadBlendPaletteColor(index); player.outputChatBox(`paletteIndex #${index} - red: ${paletteColor.red}, green: ${paletteColor.green}, blue: ${paletteColor.blue}`); }); // EXAMPLE: Getting all colors of the player mp.events.addCommand("mycolors", (player) => { const paletteColors = player.getHeadBlendPaletteColors(); paletteColors.forEach((item, index) => { player.outputChatBox(`paletteIndex #${index} - red: ${item.red}, green: ${item.green}, blue: ${item.blue}`); }); }); // EXAMPLE: Setting one color mp.events.addCommand("setcolor", (player, _, index, r, g, b) => { index = Number(index); r = Number(r); g = Number(g); b = Number(b); player.setHeadBlendPaletteColor(index, r, g, b); }); // EXAMPLE: Setting multiple colors at once mp.events.addCommand("randomcolors", (player) => { let data = []; // the game has 4 palette colors for (let i = 0; i < 4; i++) { data.push([ i, // palette index Math.floor(Math.random() * 256), // random red Math.floor(Math.random() * 256), // random green Math.floor(Math.random() * 256), // random blue ]); } player.setHeadBlendPaletteColors(data); });
Notes
The game doesn't seem to like it when you set palette color(s) of a ped that doesn't have headblend data, it's recommended that you do color changes after using Player::setCustomization Crew t-shirt palette indices: 0 - sleeve color, 1 - no difference, 2 - collar color, 3 - main color Crew jacket palette indices: 0, 1, 2 - no difference, 3 - main color
Source code is also available on GitHub: https://github.com/root-cause/ragemp-palette-sync
21 downloads
(1 review)0 comments
Updated
