Skip to content

Releases: shr0x/ragemp-rp-gamemode

v0.0.7-b1

17 Aug 12:25
d12b138
Compare
Choose a tag to compare

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.
radial

Interaction UI

interaction
interaction2
interaction3

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);

emotes

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}`);
                }
            }
        });
    }
});

menu

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.
settings

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

07 Aug 10:34
3e7418b
Compare
Choose a tag to compare

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

02 Jul 07:08
d314e06
Compare
Choose a tag to compare

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.

death1

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

Full Changelog: v0.0.4...v0.0.6

v0.0.5-RC2

05 Jun 23:53
1d58372
Compare
Choose a tag to compare

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

Full Changelog: v0.0.5-RC1...v0.0.5-RC2

v0.0.5-RC1

02 Jun 16:32
87451df
Compare
Choose a tag to compare

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.

backpack 1

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:

example 1

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
...
Read more

v0.0.4

28 May 04:38
fc647c5
Compare
Choose a tag to compare

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

18 May 12:24
Compare
Choose a tag to compare

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

17 May 12:42
Compare
Choose a tag to compare

Full Changelog: 0.0.1-a1...0.0.2

0.0.1-a1

17 May 04:40
Compare
Choose a tag to compare
0.0.1-a1 Pre-release
Pre-release

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:

  • finished character creation and selection by @shr0x in #1

Full Changelog: https://github.com/shr0x/ragemp-rp-framework/commits/0.0.1-a1