Releases: shr0x/ragemp-rp-gamemode
v0.0.7-b1
Version 0.0.7 (QoL)
Additional
[+] Added /do to describe a rp action.
[+] Added /s(hout) to shout out a message.
[+] Added /w(hisper) to whisper another player (/w [target] [message]).
[+] Added /admins to list all online admins. (for level 1 admin)
[+] Added /givecash (/givemoney) [player] [amount].
[+] Added /goto for level 1 admins & a bunch of admin teleport locations.
[+] Added /gethere for level 1 admins to teleport a player to their position.
[+] Added chat module with various chat methods (see below).
[+] Added in-vehicle interaction, you can now interact with the vehicle you're in by pressing G.
[+] Added player nametags.
[+] Added player.setEmoteText(color: array4d, text: string, timeout: number /*seconds*/);
[+] Added DynamicPoint.createBlip(sprite: number, position Vector3, ...options);
[+] Added DynamicPoint.destroyBlip();
[+] Added player-crawling, not being used currently but it might in future.
[+] Added DynamicPoint.createMarker(type: number, position: Vector3, scale: number, ...options);
[+] Added DynamicPoint.destroyMarker();
[+] Added new interactive progress bar for inventory.
[+] Added Client.isDead (get) -> Returns true if a player is in death state, false if not.
[+] Added player-attachments with slightly changes and a bunch of attachments which may come handy to you for your creative content. (Credits: https://rage.mp/files/file/144-efficient-attachment-sync/)
--->player.addAttachment(name:string, attach:boolean);
[+] Added player.character.cash property (get/set)
[+] Added player.giveMoney(amount: number, logMessage?:string);
[+] (UI) Added player cash to HUD.
[+] (UI) Added a way to exit the interaction menu when in the first page.
[+] (UI) Added native menu.
[+] (UI) Added interactive button, supports progress bar & input.
[+] (UI) (WIP) Added player settings menu, to change account password, manage display settings & keybindings.
Changes:
[/] Few changes on creator icons.
[/] Increased size of radial menu.
[/] Players can no longer open inventory or use quick slots while they're in injured state.
[/] Updated draw distance for interactable NPC text label.
[/] Moved some inventory exported enums to shared folder.
[/] You can now press ESC(escape) to close most of the pages that you're allowed to.
New
Radial Menu Changes
Now it has a center button to exit the menu if in first page.
Interaction UI
Example
//Example of how to show a button
const buttonData: RageShared.Interfaces.IInteractButton = {
button: "Esc",
autoStart: false,
time: 0,
count: 0,
image: "default",
rarity: 0,
header: "Hello World",
description: "This is a description"
};
RAGERP.cef.emit(player, "hud", "showInteractionButton", buttonData);
//Example of how to hide it
RAGERP.cef.emit(player, "hud", "showInteractionButton", null);
Player emotes
Creates a player emote text-label above their head.
Example
player.setEmoteText([255, 255, 255, 255], "Hello world", 7);
Chat methods
RAGERP.chat.sendNearbyMessage(position: Vector3, radius: number, message: string);
RAGERP.chat.sendSyntaxError(player: PlayerMp, message: string);
//color must be 32-bit hex (eg 0x00AA00AA)
RAGERP.chat.sendAdminWarning(color: number, message: string, level: number = ADMIN_LEVEL_ONE);
/* Sends a syntax error message */
RAGERP.chat.sendSyntaxError(player: PlayerMp, message: string);
//Example
RAGERP.commands.add({
name: "message",
run: (player: PlayerMp, text: string) => {
if (!text.length) return RAGERP.chat.sendSyntaxError(player, "/message [text]"); //returns "Usage: /message [text]"
//do what you want
}
});
Player Crawling (client-side only)
import {Client} from './path/to/classes/Client.class.ts';
//enable or disable player-crawling animation for local player.
Client.toggleCrawling();
Native Menu (currently, server-side only)
Native menu will make your job easier as developer to create stuff for players to quickly interact with.
Currently it supports 3 button types, default button, a string list switcher (left and right) and a checkbox.
//initialize a new native menu:
new NativeMenu(player: PlayerMp, id: number, header: string, desc: string, items: Array<[]>);
//A promise awaiting the response of item data that player has selected in native menu
nativemenu.onItemSelected(player).then((data) => {
//do what you want
});
//destroy a menu for given player
nativemenu.destroy(player);
//example
RAGERP.commands.add({
name: "testnativemenu",
adminlevel: RageShared.Enums.ADMIN_LEVELS.LEVEL_SIX,
run: async (player: PlayerMp) => {
const items = [
{ name: "test", type: RageShared.Enums.NATIVEMENU_TYPES.TYPE_DEFAULT, uid: 0 },
{ name: "test 2", type: RageShared.Enums.NATIVEMENU_TYPES.TYPE_DEFAULT, uid: 1 },
{ name: "test 3", type: RageShared.Enums.NATIVEMENU_TYPES.TYPE_DEFAULT, uid: 2 }
]
player.nativemenu = new NativeMenu(player, 0, "Hello World", "This is a description", items);
player.nativemenu.onItemSelected(player).then((res) => {
if (!res) return player.nativemenu?.destroy(player);
const data = RAGERP.utils.parseObject(res);
console.log("onItemSelected called, with result: ", data);
switch (data.listitem) {
case 0: {
console.log("player selected the first item in native menu");
return;
}
default: {
return console.log(`player selected index ${data.listitem} | name: ${data.name} | uid: ${data.uid}`);
}
}
});
}
});
Settings
Settings menu is currently done only in UI and is not connected with backend, however here's a screenshot of how it looks like, in this menu you'll be able to cchange your account's password, display settings and keybinding.
Inventory progress bar
Inventory progress bar will allow you to show players an interactive progress bar which they can cancel at any time
An example would be when they're using an item, such as when they're eating, you can create a new progress bar with the given item, animation and time which player can cancel when they have to by pressing ESC
interface IUsingItemData {
item: RageShared.Inventory.Interfaces.IBaseItem;
animDict?: string;
animName?: string;
flag?: number;
attachObject?: string;
}
/*
* @param {PlayerMp} player - The player interacting with the item.
* @param {string} description - The description of the progress bar.
* @param {number} time - The duration of the progress bar in seconds.
* @param {IUsingItemData} data - The data related to the item being used.
* @param {() => void} onFinish - Callback function to execute when the progress bar finishes.
*/
player.character.inventory.startUsingItem(player: PlayerMp, description: string, time: number, data: IUsingItemData, handler: () => void)
//example (NOTE: this item does not exist, its just an example)
const items = player.character.inventory.getItemsInCategoryByType([RageShared.Inventory.Enums.INVENTORY_CATEGORIES.POCKETS], RageShared.Inventory.Enums.ITEM_TYPES.ITEM_TYPE_BURGER);
if (!items.length) return;
const actionData = {
item: items[0],
animDict: "mp_player_inteat@burger",
animName: "mp_player_int_eat_burger",
flag: 49,
attachObject: "item_hamburger"
}
player.character.inventory.startUsingItem(player, "Press ESC to cancel this action", 5, actionData, async () => {
console.log("Player has finished eating a burger!");
});
v0.0.6-R2
R2 - Hotfix
What's Changed
-
Fixed issues with death timer being stuck as 0 after one time of it happening.
-
Fixed inventory clothes not allowing the player to spawn in properly.
-
Fixed ammo item object models, they are no longer sticky bombs.
-
Added new entity outline feature for vehicle interaction.
-
Added admin chat.
-
Added noclip (requires you to be an admin, F5 to enable disable)
-
Misc changes & code optimization
This hotfix was pulled from 0.0.7 which will be released soon with some awesome updates, see this full changelog here:
v0.0.6
This update is focused on the frontend to make your way of creating pages easier.
CEF Updates
It is now way easier to create pages in our frontend, check the video below
https://www.youtube.com/watch?v=Q-RpLBSZNlQ
Death System
-> Default game 'death' system is disabled.
-> Once a player dies they go into injury state.
-> Player has to wait 30 seconds and then they can press E to accept death
-> Once they press E they respawn at the closest hospital based on their position.
Other changes
[+] Added /ah(elp) to list all available admin commands.
[+] Added 6 admin levels.
[+] Added /revive to revive an injured player
[+] Added /giveclothes to give a target player inventory clothes
[+] Added /giveitem to give a target player inventory item
[+] Added mp.players.getPlayerByName(stringornumber), gets a player by their name or by their id, if there's no player it returns undefined.
Git Changes
- docs: change links to file by @exodie in #6
- 0.0.5 by @shr0x in #7
- 0.0.5 by @shr0x in #8
- 0.0.5 by @shr0x in #9
- disabled dev stuff by @shr0x in #10
- chore: update scripts cef paths by @exodie in #11
- 0.0.5 by @shr0x in #12
- Account relation fixes & first time spawn fixes by @shr0x in #13
- 0.0.6 by @shr0x in #17
Full Changelog: v0.0.4...v0.0.6
v0.0.5-RC2
RC2
Frontend rework
Our frontend app now uses createContext for globally page setting which will make it easier later on to be able to set pages ('components') from inside other components.
Example of using page setter/getter
import { FC, useCallback } from "react";
import { usePage } from "./PageContext";
export const MyComponent: FC = () => {
const {page, setPage} = usePage();
const handleClick = useCallback(() => {
//check whether the page is or not 'auth' and if its not then set it!
if (page !== "auth") setPage("auth")
}, [])
return <button onClick={() => handleClick()}>CLICK ME</button>
}
We are now using shared data in frontend also! Shared data is quite useful when you want to keep track of what you're doing, like what kind of data you're using, instead of having them declared in both parts, shared and frontend we are now declaring them only in the shared folder. Eventually every interface that's being exported from the modules and used more than once will be moved to shared folder.
Events
Instead of creating 'new files' to store events added with EventManager we're now creating events inside store class.
This change requires you that everytime you create a new store you make sure 'createEvents' method is there as a public method.
Before:
import { useEffect } from "react";
import MyStore from "stores/MyStore";
import EventManager from "utils/EventManager.util";
export const InitMyStoreEvents = (store: MyStore) => {
return useEffect(() => {
EventManager.addHandler("pagename", "setdata", (data: number) => store.setData(data));
EventManager.stopAddingHandler("pagename");
return () => EventManager.removeTargetHandlers("pagename");
}, [store]);
};
After:
import { makeObservable, observable, action } from "mobx";
import EventManager from "utils/EventManager.util";
class MyStore {
@observable
mydata: number = 0;
constructor(){
makeObservable(this);
}
@action.bound
setData(data: number) {
this.mydata = data;
}
public createEvents() {
EventManager.addHandler("pagename", "setdata", (data: number) => this.setData(data));
EventManager.stopAddingHandler("pagename");
}
}
Make sure the newly created store is included in the main App.tsx
inside the primary used useEffect
const myStore = useLocalObservable(() => new MyStore());
const myOtherCoolStore = useLocalObservable(() => new MyOtherCoolStore());
useEffect(() => {
const stores = [
{ store: myStore, event: "myStore" },
{ store: myOtherCoolStore, event: "myOtherCoolStore" },
];
stores.forEach(({ store, event }) => {
//this will call our created createEvents method to initialize events that can be called form backend
store.createEvents();
return () => EventManager.removeTargetHandlers(event);
});
}, [myStore, myOtherCoolStore])
Shared data changes
Shared data now exports namespaces, interfaces and enums instead of declaring them. This mainly was done because we're now using shared data in frontend like interfaces and enums and using declared enum is not possible since frontend wouldn't know what that enum really is when building, but importing them let's the frontend know what their values are.
Other Fixes
[/] Fixed errors when creating a second or third character due to database relations being described wrongly.
[/] Fixed an issue with things not working correctly after creating a character for the first time (like inventory or hud wasn't updating)
[/] Fixed chat input image tripping when a suggested command was displayed.
[/] Fixed item swapping causing issues with items equipped in quick use.
What's Changed
- chore: update scripts cef paths by @exodie in #11
- 0.0.5 by @shr0x in #12
- Account relation fixes & first time spawn fixes by @shr0x in #13
Full Changelog: v0.0.5-RC1...v0.0.5-RC2
v0.0.5-RC1
Backpacks
Backpacks provide further slots for players in their inventory, a player can open a backpack at anytime using the modal menu.
Comes with two levels and 24 slots max, level 1 has 12 and level two has 24.
You can drop them, equip them and manage their inside items just as you would in the pockets category.
Other changes
Additionals
[+] Vehicle system
[+] Chat now suggest commands when typing them, pressing TAB would auto fill them.
[+] Ammunition system, if you have a pistol and you have 100 pistol ammo, those ammo will be automatically loaded to the pistol.
[+] Wearing a mask in inventory changes player's name to Stranger_Hashpart, hashpart comes from item generated UUID.
[+] Added /me & /b commands.
[+] Chat now support colors used on player.outputChatBox.
[+] Added area and street names now being displayed on the hud.
[+] Added player death and injury state (along with CEF update), player must wait at least 30 seconds and then he can press E to accept death.
Fixes
[*] Fixed an issue with item dropping not storing the item hash properly making you unable to pick a dropped inventory item.
[*] Fixed an issue with items conflicting with quick use not allowing you to move them.
[*] Fixed an issue with dragging ground items to clothes, the system was not actually giving you the item but instead it was completely deleting it.
[*] Fixed an issue with being unable to drop items from backpacks.
[*] Fixed some errors popping up when leaving a vehicle.
Changes
[/] Character entity is now linked with account entity.
[/] Character creator uses [key]:number instead of [string]:number for face features.
[/] Changed chat font family and font size.
[/] Tweak changes on speedometer and character spawn selection.
Code Additions/Changes
[+] Added CommandRegistry.reloadCommands(player); to resend player commands to cef which then can be used as suggested commands in the chat.
[+] Player data now saves on the database everytime they quit the server.
[+] Cef events now support event registering to make your code writting easier.
[+] Rewrote inventory item drop code, simplified and it uses a map to store data instead of an object with keys and data.
[+] Added ChracterEntity.setStoreData(player, key, value); to update CEF store data for given player.
For developers:
Package Updates
tsconfig-paths-webpack-plugin
4.0.1 > 4.1.0
We're now using paths, currently only for server-side.
- Paths are a way to simplify imports and make the code looks neater
Paths are specified at server's ts configuration file, you can change them however you want but personally I prefer using '@'
"paths": {
"@api": [
"./api/index.ts"
],
"@assets/*": [
"./assets/*"
],
"@classes/*": [
"./classes/*"
],
"@events/*": [
"./serverevents/*"
],
"@modules/*": [
"./modules/*"
],
"@entities/*": [
"./database/entity/*"
],
"@commands/*": [
"./commands/*"
],
"@prototype/*": [
"./prototype/*"
],
"@shared/*": [
"../shared/*"
]
}
Vehicle System
import {RAGERP} from '@api';
//Vehicle types:
const enum VEHICLETYPES {
NONE = 0,
OWNED = 1, //player owned vehicle
FACTION = 2, //faction owned vehicle
RENTAL = 3, //rented vehicle
JOB = 4, //job vehicle
ADMIN = 5 //admin spawned vehicle
}
//vehicle data
interface IVehicleData {
locked: boolean; //saves vehicle lock state
engine: boolean; //saves vehicle engine state
numberplate: string; //saves vehicle number plate
fuel: number; //saves vehicle fuel
sqlid: number | null; //saves vehicle sql id
faction: string | null; //saves vehicle faction (for future update)
keyhole: string | null; //saves vehicle unique key hole (for future update)
owner: number | null; //saves vehicle owner sqlid
ownerName: string | null; //saves vehicle owner name
trunkState: boolean; //saves vehicle trunk state
hoodState: boolean; //saves vehicle hood state
primaryColor: Array3d; //saves vehicle primary color
secondaryColor: Array3d; //saves vehicle secondary color
inventory: any | null; //saves vehicle inventory (for future update)
price: number; //saves vehicle price
impoundState: number; //saves vehicle impound state (for future update)
}
//vehicle mods
interface IVehicleMods {
tunningMods: { [key: number]: number }; //saves vehicle tunning mods provide by ragemp api
plateColor: number; //saves vehicle plate color mod
wheelType: number; //saves vehicle wheel type
wheelMod: number; //saves vehicle wheel index
neonColor: Array3d | null; //saves vehicle neon color
hasNeon: boolean; //saves whether the vehicle has a neon or not
primaryColorType: number; //saves primary vehicle color type
secondaryColorType: number; //saves secondary vehicle color type
smokecolor: { r: number; g: number; b: number }; //saves vehicle smoke color
interiorcolor: number; //saves vehicle interior color
dashboardcolor: number; //saves vehicle dashboard color
dirtlevel: number; //saves vehicle dirt level
windows: { 0: boolean; 1: boolean; 2: boolean; 3: boolean }; //saves vehicle window state (whether they're open or closed)
}
//creating a vehicle
const vehicle = RAGERP.entities.vehicle(
type: RageShared.Vehicle.Enums.VEHICLETYPES,
model: string | number,
position: Vector3,
heading: number,
dimension: number,
data: IVehicleData = defaultVehicleData,
mods: IVehicleMods | null = null
)
//accessing created game vehicle
vehicle._vehicle;
//setting vehicle data
/*
* Once typed, vscode should prompt the values you can set to data and their key data type.
*/
vehicle.setData(key, value);
//Getting vehicle data
/*
* Once typed, vscode should prompt the key names you can get data from.
*/
vehicle.getData(key);
//destroy created vehicle
vehicle.destroy();
//Setting vehicle mods
vehicle.setMod(key, value); //similar to setData but for mods
//Getting vehicle mods
vehicle.getMod(key); //similar to getData but for mods.
vehicle.getType(); //gets vehicle type
vehicle.getModelName(player); //gets vehicle model name
vehicle.getPassengers(modelHash); //gets how many seats the vehicle has
vehicle.getFaction(); //gets vehicle faction (for future faction update)
vehicle.getOwner(); //gets vehicle owner name (if any)
vehicle.getSQL(); //gets vehicle sql id
vehicle.createMods(); //create vehicle mods
vehicle.insertVehicle(vehicle: VehicleMp, modelName:string, price: number); //insert a vehicle to the database
vehicle.saveVehicle(vehicle: VehicleMp); //save a vehicle to the database
vehicle.isWindowedVehicle(class: number); //check whether vehicle is windowed ornot
//Static methods
Vehicle.at(id: number); //find a vehicle by ragemp vehicle api id
Vehicle.atSQL(id: number); //find a vehicle by sql id
Vehicle.isInWorld(id: number); //check whether vehicle is in world
Vehicle.getNearest(player: PlayerMp, radius: number); //get nearest vehicle based on player position and radius
CEF Event Manager Updates
*You can now describe the events you add on frontend at RageShared.Interfaces.IncomingCEFEvents
register<P extends keyof RageShared.Interfaces.IncomingCEFEvents, K extends keyof RageShared.Interfaces.IncomingCEFEvents[P]>(
page: P,
pointer: K,
handler: (player: PlayerMp, data: EventData<P, K>) => void | EventHandler | EventHandlerAsync
): void;
register(page: string, pointer: string, handler: EventHandler | EventHandlerAsync): void;
Example of currently registered events which are fired from frontend to backend
interface IncomingCEFEvents {
inventory: {
onMoveItem: (player: PlayerMp, data: StringifiedObject<RageShared.Interfaces.Inventory.IMoveItem>) => void;
onUseItem: (player: PlayerMp, data: StringifiedObject<RageShared.Interfaces.Inventory.IUseItem>) => void;
onGiveItem: (player: PlayerMp, data: StringifiedObject<{ playerId: number; item: RageShared.Interfaces.Inventory.IInventoryItem; source: { slot: string } }>) => void;
onDropItem: (player: PlayerMp, data: StringifiedObject<RageShared.Interfaces.Inventory.IDropItem>) => void;
onSplitItem: (player: PlayerMp, data: StringifiedObject<RageShared.Interfaces.Inventory.ISplitItem>) => void;
confirmItemDrop: (player: PlayerMp) => void;
onCancelItemDrop: (player: PlayerMp) => void;
onOpenItem: (player: PlayerMp, data: StringifiedObject<RageShared.Interfaces.Inventory.IOpenItem>) => void;
};
auth: {
register: (player: PlayerMp, data: StringifiedObject<{ username: string; email: string; password: string; confirmPassword: string }>) => void;
loginPlayer: (player: PlayerMp, data: StringifiedObject<{ username: string; password: string }>) => void;
};
}
By doing this you make your job easier when registering a CEF event by knowing what data that event you're registering will receive to make your or anyone else you working with code faster, however this is an optional feature, adding raw events is also supported.
Here's an example how helpful this actually is:
Shared folder & re-structure
Shared folder has now a better structured files in it, depending on the entities we use scriptwise that's how the files are created
shared
├─interfaces
│ ├─cefevents.d.ts // contains CEF related interfaces & enums
│ ├─player.d.ts // contains player related interfaces & enums
...
v0.0.4
Frontend Update
- v0.0.4 frontend app is now built on Vite and no longer uses react-rewired.
What's new
- New inventory system that supports drag and drop, three categories (pockets, clothes & quick use).
->Comes with ability to drop items and pick them up.
->Comes with clothes and weapons as items (total: 108 items).
->Comes with a side-inventory and backpack(WIP)
-> Read more here
What's Changed
- Chat now 'suggest' commands when typing them.
- Changed font-family for chat messages.
- Misc updates on inventory code and added JSDocs to inventory class.
- Added new keybind manager to make it easy to bind keys for players readmore about keybinds here
Other changes
Full Changelog: 0.0.3...v0.0.4
0.0.3
Added New Interaction Menu (client-side only)
import { InteractionMenu } from './classes/InteractMenu.class';
mp.events.add("client::interaction:showMenu", async () => {
const data = {
isActive: true,
items: [
{ type: 0, id: 0, text: "Whatever" },
{ type: 0, id: 1, text: "Whatever 1" },
{ type: 0, id: 2, text: "Whatever 2" }
]
};
const response = await InteractionMenu.new(data);
mp.console.logInfo(`Response is: ${response}`);
InteractionMenu.closeMenu();
});
Full Changelog: 0.0.2...0.0.3
0.0.2
Full Changelog: 0.0.1-a1...0.0.2
0.0.1-a1
Initial release
This is the very first release of this gamemode, currently it's more likely to come handy as a boilerplate, however plenty features are planned to be added so keep an eye out to keep yourself up to date.
What completed this release:
Full Changelog: https://github.com/shr0x/ragemp-rp-framework/commits/0.0.1-a1