├── docs ├── CNAME ├── assets │ ├── icons.png │ ├── icons@2x.png │ ├── widgets.png │ ├── widgets@2x.png │ └── highlight.css └── .nojekyll ├── .gitignore ├── src ├── ui │ ├── menu │ │ ├── modules │ │ │ ├── index.ts │ │ │ └── ListItem.ts │ │ ├── index.ts │ │ ├── items │ │ │ ├── index.ts │ │ │ ├── panels │ │ │ │ ├── index.ts │ │ │ │ ├── UIMenuStatisticsPanelItem.ts │ │ │ │ ├── AbstractUIMenuPanel.ts │ │ │ │ └── UIMenuStatisticsPanel.ts │ │ │ ├── UIMenuSeparatorItem.ts │ │ │ ├── UIMenuCheckboxItem.ts │ │ │ └── UIMenuListItem.ts │ │ ├── MenuControl.ts │ │ ├── MenuControls.ts │ │ └── MenuSettings.ts │ ├── interfaces │ │ ├── index.ts │ │ ├── IButton.ts │ │ └── IDrawable.ts │ ├── Notification.ts │ ├── index.ts │ ├── Container.ts │ ├── LoadingPrompt.ts │ ├── Rectangle.ts │ ├── Hud.ts │ ├── Fading.ts │ ├── InstructionalButtons.ts │ ├── Sprite.ts │ ├── Effects.ts │ ├── Screen.ts │ └── Text.ts ├── enums │ ├── Gender.ts │ ├── CheckboxStyle.ts │ ├── Alignment.ts │ ├── MenuAlignment.ts │ ├── InputMode.ts │ ├── RopeType.ts │ ├── RagdollType.ts │ ├── Font.ts │ ├── HelmetType.ts │ ├── ForceType.ts │ ├── LoadingSpinnerType.ts │ ├── ClassTypes.ts │ ├── InvertAxis.ts │ ├── Relationship.ts │ ├── NotificationType.ts │ ├── Language.ts │ ├── AnimationFlags.ts │ ├── CameraShake.ts │ ├── LeaveVehicleFlags.ts │ ├── CameraTypes.ts │ ├── Parachute.ts │ ├── CursorSprite.ts │ ├── IntersectOptions.ts │ ├── Weather.ts │ ├── CloudHat.ts │ ├── FiringPattern.ts │ ├── ExplosionType.ts │ ├── Driving.ts │ ├── RadioStation.ts │ ├── MarkerType.ts │ ├── SpeechModifier.ts │ ├── HudComponent.ts │ ├── AudioFlag.ts │ ├── ZoneID.ts │ ├── Checkpoint.ts │ ├── ScreenEffect.ts │ ├── index.ts │ ├── PickupType.ts │ ├── Bone.ts │ ├── BadgeStyle.ts │ └── Blip.ts ├── cfx │ ├── index.ts │ └── StateBagChangeHandler.ts ├── interfaces │ └── Dimensions.ts ├── utils │ ├── Size.ts │ ├── PointF.ts │ ├── Maths.ts │ ├── getUInt32FromUint8Array.ts │ ├── getStringFromUInt8Array.ts │ ├── Crypto.ts │ ├── Point.ts │ ├── LiteEvent.ts │ ├── index.ts │ ├── enumValues.ts │ ├── Quaternion.ts │ ├── Color.ts │ ├── String.ts │ ├── Animations.ts │ ├── Vector2.ts │ └── Vector4.ts ├── weapon │ ├── WeaponLivery.ts │ ├── index.ts │ ├── WeaponGroup.ts │ ├── WeaponLiveryColor.ts │ ├── Mk2WeaponHash.ts │ ├── WeaponTint.ts │ ├── WeaponAsset.ts │ ├── WeaponHudStats.ts │ ├── WeaponDisplayNameByHash.ts │ └── DlcWeaponData.ts ├── hashes │ ├── index.ts │ ├── WeatherTypeHash.ts │ └── WeaponHash.ts ├── weaponComponent │ ├── index.ts │ ├── ComponentAttachmentPoint.ts │ ├── InvalidWeaponComponent.ts │ ├── WeaponComponentHudStats.ts │ ├── DlcWeaponComponentData.ts │ └── WeaponComponent.ts ├── models │ ├── PedBone.ts │ ├── VehicleWheel.ts │ ├── EntityBoneCollection.ts │ ├── PedBoneCollection.ts │ ├── index.ts │ ├── EntityBone.ts │ ├── Prop.ts │ ├── VehicleToggleMod.ts │ ├── VehicleWindow.ts │ ├── VehicleMod.ts │ ├── VehicleDoor.ts │ ├── VehicleWheelCollection.ts │ ├── VehicleWindowCollection.ts │ └── VehicleDoorCollection.ts ├── Pickup.ts ├── index.ts ├── Checkpoint.ts ├── TaskSequence.ts ├── NetworkedScene.ts ├── Events.ts ├── Raycast.ts ├── RelationshipGroup.ts ├── Blip.ts ├── Audio.ts ├── ParticleEffect.ts ├── ParticleEffectAsset.ts ├── Rope.ts └── GameplayCamera.ts ├── .eslintignore ├── examples ├── typescript │ ├── .gitignore │ ├── tslint.json │ ├── fxmanifest.lua │ ├── src │ │ └── index.ts │ ├── tsconfig.json │ ├── package.json │ ├── client.config.js │ └── README.md └── javascript │ ├── .gitignore │ ├── client.config.js │ ├── fxmanifest.lua │ ├── package.json │ ├── src │ └── index.js │ └── README.md ├── typedoc.json ├── .prettierrc ├── .editorconfig ├── tsconfig.json ├── .github ├── actions │ └── bump-package-version.js ├── workflows │ ├── config.yml │ └── publish.yml └── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── .eslintrc.js ├── DEVELOPMENT.md ├── LICENSE ├── package.json ├── CONTRIBUTING.md └── README.md /docs/CNAME: -------------------------------------------------------------------------------- 1 | fivemjs.avarian.dev -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | /lib 3 | .idea 4 | yarn.lock 5 | -------------------------------------------------------------------------------- /src/ui/menu/modules/index.ts: -------------------------------------------------------------------------------- 1 | export { ListItem } from './ListItem'; 2 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | .circleci/ 2 | node_modules/ 3 | lib/ 4 | docs/ 5 | examples/ -------------------------------------------------------------------------------- /examples/typescript/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | dist/ 3 | package-lock.json -------------------------------------------------------------------------------- /src/enums/Gender.ts: -------------------------------------------------------------------------------- 1 | export enum Gender { 2 | Male, 3 | Female, 4 | } 5 | -------------------------------------------------------------------------------- /examples/javascript/.gitignore: -------------------------------------------------------------------------------- 1 | ./dist/ 2 | ./node-modules/ 3 | package-lock.json -------------------------------------------------------------------------------- /src/enums/CheckboxStyle.ts: -------------------------------------------------------------------------------- 1 | export enum CheckboxStyle { 2 | Tick, 3 | Cross, 4 | } 5 | -------------------------------------------------------------------------------- /src/enums/Alignment.ts: -------------------------------------------------------------------------------- 1 | export enum Alignment { 2 | Left, 3 | Centered, 4 | Right, 5 | } 6 | -------------------------------------------------------------------------------- /src/enums/MenuAlignment.ts: -------------------------------------------------------------------------------- 1 | export enum MenuAlignment { 2 | Left = 76, 3 | Right = 82, 4 | } 5 | -------------------------------------------------------------------------------- /src/enums/InputMode.ts: -------------------------------------------------------------------------------- 1 | export enum InputMode { 2 | MouseAndKeyboard = 0, 3 | GamePad = 2, 4 | } 5 | -------------------------------------------------------------------------------- /docs/assets/icons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativewrappers/fivem-client/HEAD/docs/assets/icons.png -------------------------------------------------------------------------------- /typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "entryPoints": ["./src/index.ts"], 3 | "readme": "none", 4 | "out": "docs" 5 | } -------------------------------------------------------------------------------- /docs/assets/icons@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativewrappers/fivem-client/HEAD/docs/assets/icons@2x.png -------------------------------------------------------------------------------- /docs/assets/widgets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativewrappers/fivem-client/HEAD/docs/assets/widgets.png -------------------------------------------------------------------------------- /src/ui/interfaces/index.ts: -------------------------------------------------------------------------------- 1 | export { IDrawable } from './IDrawable'; 2 | export { IButton } from './IButton'; 3 | -------------------------------------------------------------------------------- /docs/assets/widgets@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nativewrappers/fivem-client/HEAD/docs/assets/widgets@2x.png -------------------------------------------------------------------------------- /src/enums/RopeType.ts: -------------------------------------------------------------------------------- 1 | export enum RopeType { 2 | ThickRope = 1, 3 | ThickRope2 = 4, 4 | ThinMetalWire = 5, 5 | } 6 | -------------------------------------------------------------------------------- /src/cfx/index.ts: -------------------------------------------------------------------------------- 1 | export { StateBagChangeHandler } from './StateBagChangeHandler'; 2 | 3 | export default { Entity, Player }; 4 | -------------------------------------------------------------------------------- /src/enums/RagdollType.ts: -------------------------------------------------------------------------------- 1 | export enum RagdollType { 2 | Normal = 0, 3 | StiffLegs = 1, 4 | NarrowLegs = 2, 5 | WideLegs = 3, 6 | } 7 | -------------------------------------------------------------------------------- /src/enums/Font.ts: -------------------------------------------------------------------------------- 1 | export enum Font { 2 | ChaletLondon, 3 | HouseScript, 4 | Monospace, 5 | ChaletComprimeCologne = 4, 6 | Pricedown = 7, 7 | } 8 | -------------------------------------------------------------------------------- /src/enums/HelmetType.ts: -------------------------------------------------------------------------------- 1 | export enum HelmetType { 2 | RegularMotorcycleHelmet = 4096, 3 | FiremanHelmet = 16384, 4 | PilotHeadset = 32768, 5 | } 6 | -------------------------------------------------------------------------------- /src/interfaces/Dimensions.ts: -------------------------------------------------------------------------------- 1 | import { Vector3 } from '../utils'; 2 | 3 | export interface Dimensions { 4 | min: Vector3; 5 | max: Vector3; 6 | } 7 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- 1 | TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "trailingComma": "all", 4 | "singleQuote": true, 5 | "arrowParens": "avoid", 6 | "tabWidth": 2 7 | } -------------------------------------------------------------------------------- /examples/typescript/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["tslint:recommended", "tslint-config-prettier"], 3 | "rules": { 4 | "no-console": false 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/ui/interfaces/IButton.ts: -------------------------------------------------------------------------------- 1 | import { Control } from '../../enums'; 2 | 3 | export interface IButton { 4 | controls: Control[]; 5 | label: string; 6 | } 7 | -------------------------------------------------------------------------------- /src/enums/ForceType.ts: -------------------------------------------------------------------------------- 1 | export enum ForceType { 2 | MinForce, 3 | MaxForceRot, 4 | MinForce2, 5 | MaxForceRot2, 6 | ForceNoRot, 7 | ForceRotPlusForce, 8 | } 9 | -------------------------------------------------------------------------------- /src/enums/LoadingSpinnerType.ts: -------------------------------------------------------------------------------- 1 | export enum LoadingSpinnerType { 2 | Clockwise1 = 1, 3 | Clockwise2, 4 | Clockwise3, 5 | SocialClubSaving, 6 | RegularClockwise, 7 | } 8 | -------------------------------------------------------------------------------- /examples/javascript/client.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | entry: './src/index.js', 3 | output: { 4 | filename: 'index.js', 5 | path: __dirname + '/dist/', 6 | }, 7 | }; 8 | -------------------------------------------------------------------------------- /src/utils/Size.ts: -------------------------------------------------------------------------------- 1 | export class Size { 2 | public width: number; 3 | public height: number; 4 | constructor(w = 0, h = 0) { 5 | this.width = w; 6 | this.height = h; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /src/enums/ClassTypes.ts: -------------------------------------------------------------------------------- 1 | export enum ClassTypes { 2 | Ped, 3 | Prop, 4 | Vehicle, 5 | Entity, 6 | Player, 7 | Vector2, 8 | Vector3, 9 | Vector4, 10 | Quanterion, 11 | } 12 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | indent_style = tab 7 | indent_size = 4 8 | 9 | [*.md] 10 | trim_trailing_whitespace = false 11 | -------------------------------------------------------------------------------- /src/enums/InvertAxis.ts: -------------------------------------------------------------------------------- 1 | export interface InvertAxis { 2 | flags: InvertAxisFlags; 3 | } 4 | 5 | export enum InvertAxisFlags { 6 | None = 0, 7 | X = 1, 8 | Y = 2, 9 | Z = 4, 10 | } 11 | -------------------------------------------------------------------------------- /src/enums/Relationship.ts: -------------------------------------------------------------------------------- 1 | export enum Relationship { 2 | Hate = 5, 3 | Dislike = 4, 4 | Neutral = 3, 5 | Like = 2, 6 | Respect = 1, 7 | Companion = 0, 8 | Pedestrians = 255, 9 | } 10 | -------------------------------------------------------------------------------- /examples/javascript/fxmanifest.lua: -------------------------------------------------------------------------------- 1 | fx_version 'cerulean' 2 | 3 | games { 'gta5' } 4 | 5 | dependency 'webpack' 6 | dependency 'yarn' 7 | 8 | webpack_config 'client.config.js' 9 | 10 | client_script 'dist/index.js' 11 | -------------------------------------------------------------------------------- /examples/typescript/fxmanifest.lua: -------------------------------------------------------------------------------- 1 | fx_version 'cerulean' 2 | 3 | games { 'gta5' } 4 | 5 | dependency 'webpack' 6 | dependency 'yarn' 7 | 8 | webpack_config 'client.config.js' 9 | 10 | client_script 'dist/index.js' 11 | -------------------------------------------------------------------------------- /src/enums/NotificationType.ts: -------------------------------------------------------------------------------- 1 | export enum NotificationType { 2 | Default = 0, 3 | Bubble = 1, 4 | Mail = 2, 5 | FriendRequest = 3, 6 | Default2 = 4, 7 | Reply = 7, 8 | ReputationPoints = 8, 9 | Money = 9, 10 | } 11 | -------------------------------------------------------------------------------- /src/cfx/StateBagChangeHandler.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | export interface StateBagChangeHandler { 3 | (bagName: string, key: string, value: any, reserved: number, replicated: boolean): void; 4 | } 5 | -------------------------------------------------------------------------------- /src/enums/Language.ts: -------------------------------------------------------------------------------- 1 | export enum Language { 2 | American, 3 | French, 4 | German, 5 | Italian, 6 | Spanish, 7 | Portuguese, 8 | Polish, 9 | Russian, 10 | Korean, 11 | Chinese, 12 | Japanese, 13 | Mexican, 14 | } 15 | -------------------------------------------------------------------------------- /src/ui/interfaces/IDrawable.ts: -------------------------------------------------------------------------------- 1 | import { Color, Point, Size } from '../../utils/'; 2 | 3 | export interface IDrawable { 4 | pos: Point; 5 | size?: Size; 6 | color?: Color; 7 | draw(offset?: Size, resolution?: Size): void; 8 | } 9 | -------------------------------------------------------------------------------- /src/weapon/WeaponLivery.ts: -------------------------------------------------------------------------------- 1 | export enum WeaponLivery { 2 | Digital, 3 | Brushstroke, 4 | Woodland, 5 | Skull, 6 | Sessanta, 7 | Perseus, 8 | Leopard, 9 | Zebra, 10 | Geometric, 11 | Boom, 12 | Patriotic, 13 | } 14 | -------------------------------------------------------------------------------- /src/enums/AnimationFlags.ts: -------------------------------------------------------------------------------- 1 | export enum AnimationFlags { 2 | None = 0, 3 | Loop = 1, 4 | StayInEndFrame = 2, 5 | UpperBodyOnly = 16, 6 | AllowRotation = 32, 7 | CancelableWithMovement = 128, 8 | RagdollOnCollision = 4194304, 9 | } 10 | -------------------------------------------------------------------------------- /src/ui/Notification.ts: -------------------------------------------------------------------------------- 1 | export class Notification { 2 | private handle: number; 3 | 4 | constructor(handle: number) { 5 | this.handle = handle; 6 | } 7 | 8 | public hide(): void { 9 | RemoveNotification(this.handle); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/enums/CameraShake.ts: -------------------------------------------------------------------------------- 1 | export enum CameraShake { 2 | Hand, 3 | SmallExplosion, 4 | MediumExplosion, 5 | LargeExplosion, 6 | Jolt, 7 | Vibrate, 8 | RoadVibration, 9 | Drunk, 10 | SkyDiving, 11 | FamilyDrugTrip, 12 | DeathFail, 13 | } 14 | -------------------------------------------------------------------------------- /src/enums/LeaveVehicleFlags.ts: -------------------------------------------------------------------------------- 1 | export enum LeaveVehicleFlags { 2 | None = 0, 3 | Normal = 1, 4 | WarpOut = 16, 5 | SlowerNone = 64, 6 | LeaveDoorOpen = 256, 7 | BailOut = 4096, 8 | BailOut2 = 4160, 9 | PassengerSeatNormal = 262144, 10 | } 11 | -------------------------------------------------------------------------------- /src/ui/menu/index.ts: -------------------------------------------------------------------------------- 1 | export * from './items'; 2 | export * from './modules'; 3 | export { Menu } from './Menu'; 4 | export { MenuControl } from './MenuControl'; 5 | export { MenuControls } from './MenuControls'; 6 | export { MenuSettings } from './MenuSettings'; 7 | -------------------------------------------------------------------------------- /src/enums/CameraTypes.ts: -------------------------------------------------------------------------------- 1 | export enum CameraTypes { 2 | Scripted = 'DEFAULT_SCRIPTED_CAMERA', 3 | Animated = 'DEFAULT_ANIMATED_CAMERA', 4 | Spline = 'DEFAULT_SPLINE_CAMERA', 5 | ScriptedFly = 'DEFAULT_SCRIPTED_FLY_CAMERA', 6 | TimedSpline = 'TIMED_SPLINE_CAMERA', 7 | } 8 | -------------------------------------------------------------------------------- /src/enums/Parachute.ts: -------------------------------------------------------------------------------- 1 | export enum ParachuteLandingType { 2 | None = -1, 3 | Stumbling = 1, 4 | Rolling, 5 | Ragdoll, 6 | } 7 | 8 | export enum ParachuteState { 9 | None = -1, 10 | FreeFalling, 11 | Deploying, 12 | Gliding, 13 | LandingOrFallingToDoom, 14 | } 15 | -------------------------------------------------------------------------------- /src/hashes/index.ts: -------------------------------------------------------------------------------- 1 | export { MaterialHash } from './MaterialHash'; 2 | export { PedHash } from './PedHash'; 3 | export { VehicleHash } from './VehicleHash'; 4 | export { AmmoType, WeaponHash, VehicleWeaponHash } from './WeaponHash'; 5 | export { WeatherTypeHash } from './WeatherTypeHash'; 6 | -------------------------------------------------------------------------------- /src/enums/CursorSprite.ts: -------------------------------------------------------------------------------- 1 | export enum CursorSprite { 2 | Normal = 1, 3 | LightArrow, 4 | OpenHand, 5 | GrabHand, 6 | MiddleFinger, 7 | LeftArrow, 8 | RightArrow, 9 | UpArrow, 10 | DownArrow, 11 | HorizontalDoubleArrow, 12 | NormalWithPlus, 13 | NormalWithMinus, 14 | } 15 | -------------------------------------------------------------------------------- /src/utils/PointF.ts: -------------------------------------------------------------------------------- 1 | export interface PointF { 2 | x: number; 3 | y: number; 4 | z: number; 5 | } 6 | 7 | export class PointF implements PointF { 8 | public static empty(): PointF { 9 | return new PointF(0, 0, 0); 10 | } 11 | constructor(public x: number, public y: number, public z: number) {} 12 | } 13 | -------------------------------------------------------------------------------- /src/ui/menu/items/index.ts: -------------------------------------------------------------------------------- 1 | export * from './panels'; 2 | export { UIMenuItem } from './UIMenuItem'; 3 | export { UIMenuCheckboxItem } from './UIMenuCheckboxItem'; 4 | export { UIMenuListItem } from './UIMenuListItem'; 5 | export { UIMenuSeparatorItem } from './UIMenuSeparatorItem'; 6 | export { UIMenuSliderItem } from './UIMenuSliderItem'; 7 | -------------------------------------------------------------------------------- /src/ui/menu/MenuControl.ts: -------------------------------------------------------------------------------- 1 | export class MenuControl { 2 | private _enabled: boolean; 3 | 4 | constructor(enabled = true) { 5 | this._enabled = enabled; 6 | } 7 | 8 | public get Enabled(): boolean { 9 | return this._enabled; 10 | } 11 | 12 | public set Enabled(value: boolean) { 13 | this._enabled = value; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/ui/menu/modules/ListItem.ts: -------------------------------------------------------------------------------- 1 | import { Crypto } from '../../../utils'; 2 | 3 | export class ListItem { 4 | public readonly id: string = Crypto.uuidv4(); 5 | 6 | public name: string; 7 | public value: unknown; 8 | 9 | constructor(name: string, value: unknown = null) { 10 | this.name = name; 11 | this.value = value; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/enums/IntersectOptions.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * List of possible entity intersections. Used for raycasting. 3 | */ 4 | export enum IntersectOptions { 5 | Everything = -1, 6 | None = 0, 7 | World = 1, 8 | Vehicles = 2, 9 | PedsSimpleCollision = 4, 10 | Peds = 8, 11 | Objects = 16, 12 | Water = 32, 13 | Unk3 = 128, 14 | Foliage = 256, 15 | } 16 | -------------------------------------------------------------------------------- /src/ui/menu/MenuControls.ts: -------------------------------------------------------------------------------- 1 | import { MenuControl } from './MenuControl'; 2 | 3 | export class MenuControls { 4 | public back = new MenuControl(); 5 | public select = new MenuControl(); 6 | public left = new MenuControl(); 7 | public right = new MenuControl(); 8 | public up = new MenuControl(); 9 | public down = new MenuControl(); 10 | } 11 | -------------------------------------------------------------------------------- /examples/javascript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "native-wrapper-example-javascript", 3 | "version": "1.0.1", 4 | "description": "", 5 | "main": "index.js", 6 | "keywords": [], 7 | "author": "", 8 | "license": "ISC", 9 | "dependencies": { 10 | "@citizenfx/client": "^2.0.3970-1", 11 | "@nativewrappers/client": "^1.3.0" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/weaponComponent/index.ts: -------------------------------------------------------------------------------- 1 | export { DlcWeaponComponentData } from './DlcWeaponComponentData'; 2 | export { WeaponComponentHudStats } from './WeaponComponentHudStats'; 3 | export { ComponentAttachmentPoint } from './ComponentAttachmentPoint'; 4 | export { WeaponComponentHash } from './WeaponComponentHash'; 5 | export { InvalidWeaponComponent } from './InvalidWeaponComponent'; 6 | -------------------------------------------------------------------------------- /src/enums/Weather.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * List of weather types. Used for manipulating weather. 3 | */ 4 | export enum Weather { 5 | Unknown = -1, 6 | ExtraSunny, 7 | Clear, 8 | Clouds, 9 | Smog, 10 | Foggy, 11 | Overcast, 12 | Raining, 13 | ThunderStorm, 14 | Clearing, 15 | Neutral, 16 | Snowing, 17 | Blizzard, 18 | Snowlight, 19 | Christmas, 20 | Halloween, 21 | } 22 | -------------------------------------------------------------------------------- /src/models/PedBone.ts: -------------------------------------------------------------------------------- 1 | import { Bone } from '../enums'; 2 | import { EntityBone, Ped } from './'; 3 | 4 | export class PedBone extends EntityBone { 5 | constructor(owner: Ped, boneId: Bone) { 6 | super(owner, GetPedBoneIndex(owner.Handle, Number(boneId))); 7 | } 8 | 9 | public get IsValid(): boolean { 10 | return Ped.exists(this.Owner as Ped) && this.Index !== -1; 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2020", 4 | "module": "es2020", 5 | "moduleResolution": "node", 6 | "declaration": true, 7 | "outDir": "./lib", 8 | "types": ["@citizenfx/client"], 9 | "strict": true, 10 | "strictNullChecks": true 11 | }, 12 | "include": ["src"], 13 | "exclude": ["node_modules", "**/__tests__/*"] 14 | } 15 | -------------------------------------------------------------------------------- /src/utils/Maths.ts: -------------------------------------------------------------------------------- 1 | export abstract class Maths { 2 | public static clamp(num: number, min: number, max: number): number { 3 | return num <= min ? min : num >= max ? max : num; 4 | } 5 | 6 | public static getRandomInt(min: number, max: number): number { 7 | min = Math.ceil(min); 8 | max = Math.floor(max); 9 | return Math.floor(Math.random() * (max - min)) + min; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/weapon/index.ts: -------------------------------------------------------------------------------- 1 | export { DlcWeaponData } from './DlcWeaponData'; 2 | export { WeaponHudStats } from './WeaponHudStats'; 3 | export { WeaponTint } from './WeaponTint'; 4 | export { WeaponGroup } from './WeaponGroup'; 5 | export { WeaponLivery } from './WeaponLivery'; 6 | export { WeaponLiveryColor } from './WeaponLiveryColor'; 7 | export { Weapon } from './Weapon'; 8 | export { WeaponAsset } from './WeaponAsset'; 9 | -------------------------------------------------------------------------------- /examples/javascript/src/index.js: -------------------------------------------------------------------------------- 1 | import * as Cfx from '@nativewrappers/client'; 2 | 3 | RegisterCommand( 4 | 'adder', 5 | async (source, args) => { 6 | const playerCoords = Cfx.Game.PlayerPed.Position; 7 | const vehicle = await Cfx.World.createVehicle(new Cfx.Model('adder'), playerCoords, 4); 8 | Cfx.Game.PlayerPed.setIntoVehicle(vehicle, Cfx.VehicleSeat.Driver); 9 | }, 10 | false, 11 | ); 12 | -------------------------------------------------------------------------------- /examples/typescript/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as Cfx from '@nativewrappers/client'; 2 | 3 | RegisterCommand( 4 | 'adder', 5 | async (source, args) => { 6 | const playerCoords = Cfx.Game.PlayerPed.Position; 7 | const vehicle = await Cfx.World.createVehicle(new Cfx.Model('adder'), playerCoords, 4); 8 | Cfx.Game.PlayerPed.setIntoVehicle(vehicle, Cfx.VehicleSeat.Driver); 9 | }, 10 | false, 11 | ); 12 | -------------------------------------------------------------------------------- /src/ui/menu/items/panels/index.ts: -------------------------------------------------------------------------------- 1 | export { AbstractUIMenuPanel } from './AbstractUIMenuPanel'; 2 | export { UIMenuGridPanel } from './UIMenuGridPanel'; 3 | export { UIMenuColorPanel } from './UIMenuColorPanel'; 4 | export { UIMenuPercentagePanel } from './UIMenuPercentagePanel'; 5 | export { UIMenuStatisticsPanel } from './UIMenuStatisticsPanel'; 6 | export { UIMenuStatisticsPanelItem } from './UIMenuStatisticsPanelItem'; 7 | -------------------------------------------------------------------------------- /src/utils/getUInt32FromUint8Array.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * get uint32 from uint8 array 3 | * 4 | * @param buffer - Uint8Array 5 | * @param start - The beginning of the specified portion of the array 6 | * @param end - The end of the specified portion of the array 7 | */ 8 | export const getUInt32FromUint8Array = (buffer: Uint8Array, start: number, end: number): number => 9 | new Uint32Array(buffer.slice(start, end).buffer)[0]; 10 | -------------------------------------------------------------------------------- /.github/actions/bump-package-version.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | 3 | const newVersion = process.env.RELEASE_VERSION; 4 | if (!newVersion) throw new Error("Couldn't get the new version"); 5 | 6 | let package = fs.readFileSync("package.json", {encoding: 'utf8'}); 7 | package = JSON.parse(package); 8 | package.version = newVersion; 9 | 10 | package = JSON.stringify(package, null, 2); 11 | 12 | fs.writeFileSync("package.json", package); 13 | -------------------------------------------------------------------------------- /src/enums/CloudHat.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * List of cloud hats. Used to change cloud patterns 3 | */ 4 | export enum CloudHat { 5 | Unknown = 1, 6 | Altostratus, 7 | Cirrus, 8 | Cirrocumulus, 9 | Clear, 10 | Cloudy, 11 | Contrails, 12 | Horizon, 13 | HorizonBand1, 14 | HorizonBand2, 15 | HorizonBand3, 16 | Horsey, 17 | Nimbus, 18 | Puffs, 19 | Rain, 20 | Snowy, 21 | Stormy, 22 | Stratoscumulus, 23 | Stripey, 24 | Shower, 25 | Wispy, 26 | } 27 | -------------------------------------------------------------------------------- /examples/typescript/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "paths": { 5 | "*": ["types/*"] 6 | }, 7 | "outDir": "./", 8 | "noImplicitAny": false, 9 | "module": "es6", 10 | "target": "es6", 11 | "allowJs": true, 12 | "lib": ["es2017"], 13 | "types": ["@citizenfx/client", "@nativewrappers/client", "@types/node"], 14 | "moduleResolution": "node" 15 | }, 16 | "include": ["./**/*"], 17 | "exclude": [] 18 | } 19 | -------------------------------------------------------------------------------- /examples/typescript/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "native-wrappers-client-example-typescript", 3 | "version": "1.0.1", 4 | "description": "", 5 | "main": "index.js", 6 | "author": "", 7 | "license": "ISC", 8 | "dependencies": { 9 | "@citizenfx/client": "^2.0.3970-1", 10 | "@types/node": "^12.0.12", 11 | "@nativewrappers/client": "^1.3.0" 12 | }, 13 | "devDependencies": { 14 | "ts-loader": "^6.0.4", 15 | "typescript": "^3.3.3333" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/weapon/WeaponGroup.ts: -------------------------------------------------------------------------------- 1 | export enum WeaponGroup { 2 | Unarmed = 2685387236, 3 | Melee = 3566412244, 4 | Pistol = 416676503, 5 | SMG = 3337201093, 6 | AssaultRifle = 970310034, 7 | DigiScanner = 3539449195, 8 | FireExtinguisher = 4257178988, 9 | MG = 1159398588, 10 | NightVision = 3493187224, 11 | Parachute = 431593103, 12 | Shotgun = 860033945, 13 | Sniper = 3082541095, 14 | Stungun = 690389602, 15 | Heavy = 2725924767, 16 | Thrown = 1548507267, 17 | PetrolCan = 1595662460, 18 | } 19 | -------------------------------------------------------------------------------- /examples/javascript/README.md: -------------------------------------------------------------------------------- 1 | ## fivem-js Javascript Example 2 | 3 | This example compiles a JavaScript webpack project that you can use in your FiveM server. It allows a player to spawn an Adder vehicle at their current location and sets the player into the vehicle. 4 | Thanks to the [`yarn` and `webpack` resources](https://github.com/citizenfx/cfx-server-data/tree/master/resources/%5Bsystem%5D/%5Bbuilders%5D), dependencies will be installed and the project will be automagically compiled on resource start. 5 | -------------------------------------------------------------------------------- /src/utils/getStringFromUInt8Array.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * get string from uint8 array 3 | * 4 | * @param buffer - Uint8Array 5 | * @param start - The beginning of the specified portion of the array 6 | * @param end - The end of the specified portion of the array 7 | */ 8 | export const getStringFromUInt8Array = (buffer: Uint8Array, start: number, end: number): string => 9 | String.fromCharCode(...buffer.slice(start, end)) 10 | // eslint-disable-next-line no-control-regex 11 | .replace(/\u0000/g, ''); 12 | -------------------------------------------------------------------------------- /src/weaponComponent/ComponentAttachmentPoint.ts: -------------------------------------------------------------------------------- 1 | export enum ComponentAttachmentPoint { 2 | Invalid = 4294967295, 3 | Clip = 3723347892, 4 | Clip2 = 291640902, 5 | FlashLaser = 679107254, 6 | FlashLaser2 = 2722126698, 7 | Supp = 1863181664, 8 | Supp2 = 945598191, 9 | GunRoot = 962500902, 10 | Scope = 196630833, 11 | Scope2 = 1684637069, 12 | Grip = 2972950469, 13 | Grip2 = 3748215485, 14 | TorchBulb = 421673795, 15 | Rail = 2451679629, 16 | Rail2 = 497110245, 17 | Barrel = 2982890265, 18 | } 19 | -------------------------------------------------------------------------------- /examples/typescript/client.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | entry: './src/index.ts', 3 | mode: 'production', 4 | module: { 5 | rules: [ 6 | { 7 | test: /\.tsx?$/, 8 | use: 'ts-loader', 9 | exclude: /node_modules/, 10 | }, 11 | ], 12 | }, 13 | optimization: { 14 | minimize: false, 15 | }, 16 | resolve: { 17 | extensions: ['.tsx', '.ts', '.js'], 18 | }, 19 | output: { 20 | filename: 'index.js', 21 | path: __dirname + '/dist/', 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /src/weapon/WeaponLiveryColor.ts: -------------------------------------------------------------------------------- 1 | export enum WeaponLiveryColor { 2 | Gray, 3 | DarkGray, 4 | Black, 5 | White, 6 | Blue, 7 | Cyan, 8 | Aqua, 9 | CoolBlue, 10 | DarkBlue, 11 | RoyalBlue, 12 | Plum, 13 | DarkPurple, 14 | Purple, 15 | Red, 16 | WineRed, 17 | Magenta, 18 | Pink, 19 | Salmon, 20 | HotPink, 21 | RustOrange, 22 | Brown, 23 | Earth, 24 | Orange, 25 | LightOrange, 26 | DarkYellow, 27 | Yellow, 28 | LightBrown, 29 | LimeGreen, 30 | Olive, 31 | Moss, 32 | Turquoise, 33 | DarkGreen, 34 | } 35 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true, 5 | }, 6 | parser: '@typescript-eslint/parser', 7 | parserOptions: { 8 | ecmaVersion: 2021, 9 | }, 10 | plugins: ['@typescript-eslint'], 11 | extends: [ 12 | 'eslint:recommended', 13 | 'plugin:@typescript-eslint/eslint-recommended', 14 | 'plugin:@typescript-eslint/recommended', 15 | 'prettier', 16 | 'plugin:prettier/recommended', 17 | ], 18 | rules: { 19 | 'no-async-promise-executor': 'off', 20 | }, 21 | }; 22 | -------------------------------------------------------------------------------- /src/hashes/WeatherTypeHash.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Same list as Weather enum, but as hashes. 3 | */ 4 | export enum WeatherTypeHash { 5 | Unknown = -1, 6 | ExtraSunny = -1750463879, 7 | Clear = 916995460, 8 | Neutral = -1530260698, 9 | Smog = 282916021, 10 | Foggy = -1368164796, 11 | Clouds = 821931868, 12 | Overcast = -1148613331, 13 | Clearing = 1840358669, 14 | Raining = 1420204096, 15 | ThunderStorm = -1233681761, 16 | Blizzard = 669657108, 17 | Snowing = -273223690, 18 | Snowlight = 603685163, 19 | Christmas = -1429616491, 20 | Halloween = -921030142, 21 | } 22 | -------------------------------------------------------------------------------- /src/Pickup.ts: -------------------------------------------------------------------------------- 1 | import { Vector3 } from './utils'; 2 | 3 | export class Pickup { 4 | private handle: number; 5 | 6 | constructor(handle: number) { 7 | this.handle = handle; 8 | } 9 | 10 | public get Position(): Vector3 { 11 | return Vector3.fromArray(GetPickupCoords(this.handle)); 12 | } 13 | 14 | public get IsCollected(): boolean { 15 | return HasPickupBeenCollected(this.handle); 16 | } 17 | 18 | public delete(): void { 19 | RemovePickup(this.handle); 20 | } 21 | 22 | public exists(): boolean { 23 | return DoesPickupExist(this.handle); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/enums/FiringPattern.ts: -------------------------------------------------------------------------------- 1 | export enum FiringPattern { 2 | Default, 3 | FullAuto = 3337513804, 4 | BurstFire = 3607063905, 5 | BurstInCover = 40051185, 6 | BurstFireDriveby = 3541198322, 7 | FromGround = 577037782, 8 | DelayFireByOneSec = 2055493265, 9 | SingleShot = 1566631136, 10 | BurstFirePistol = 2685983626, 11 | BurstFireSMG = 3507334638, 12 | BurstFireRifle = 2624893958, 13 | BurstFireMG = 3044263348, 14 | BurstFirePumpShotGun = 12239771, 15 | BurstFireHeli = 2437838959, 16 | BurstFireMicro = 1122960381, 17 | BurstFireBursts = 1122960381, 18 | BurstFireTank = 3804904049, 19 | } 20 | -------------------------------------------------------------------------------- /src/utils/Crypto.ts: -------------------------------------------------------------------------------- 1 | export abstract class Crypto { 2 | public static uuidv4(): string { 3 | let uuid = ''; 4 | for (let ii = 0; ii < 32; ii += 1) { 5 | switch (ii) { 6 | case 8: 7 | case 20: 8 | uuid += '-'; 9 | uuid += ((Math.random() * 16) | 0).toString(16); 10 | break; 11 | case 12: 12 | uuid += '-'; 13 | uuid += '4'; 14 | break; 15 | case 16: 16 | uuid += '-'; 17 | uuid += ((Math.random() * 4) | 8).toString(16); 18 | break; 19 | default: 20 | uuid += ((Math.random() * 16) | 0).toString(16); 21 | } 22 | } 23 | return uuid; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/typescript/README.md: -------------------------------------------------------------------------------- 1 | ## native-wrappers-client Typescript Example 2 | 3 | This example compiles a Typescript webpack project that you can use in your FiveM server. It allows a player to spawn an Adder vehicle at their current location and sets the player into the vehicle. 4 | Thanks to the [`yarn` and `webpack` resources](https://github.com/citizenfx/cfx-server-data/tree/master/resources/%5Bsystem%5D/%5Bbuilders%5D), dependencies will be installed and the project will be automagically compiled on resource start. 5 | 6 | For building without the FiveM builders, checkout [fivem-ts-boilerplate](https://github.com/d0p3t/fivem-ts-boilerplate) -------------------------------------------------------------------------------- /.github/workflows/config.yml: -------------------------------------------------------------------------------- 1 | name: Build CI 2 | on: 3 | push: 4 | branches: [ master ] 5 | pull_request: 6 | branches: [ master ] 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | strategy: 12 | matrix: 13 | node-version: [16.x] 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Use Node.js ${{ matrix.node-version }} 17 | uses: actions/setup-node@v2 18 | with: 19 | node-version: ${{ matrix.node-version }} 20 | - uses: pnpm/action-setup@v2.1.0 21 | with: 22 | version: ^6.24.1 23 | - run: pnpm install 24 | - run: pnpm run ci -------------------------------------------------------------------------------- /src/ui/index.ts: -------------------------------------------------------------------------------- 1 | export * from './interfaces'; 2 | export { Rectangle } from './Rectangle'; 3 | export { Container } from './Container'; 4 | export { Effects } from './Effects'; 5 | export { Fading } from './Fading'; 6 | export { Hud } from './Hud'; 7 | export { InstructionalButtons } from './InstructionalButtons'; 8 | export { LoadingPrompt } from './LoadingPrompt'; 9 | export { Notification } from './Notification'; 10 | export { Scaleform } from './Scaleform'; 11 | export { Screen } from './Screen'; 12 | export { Sprite } from './Sprite'; 13 | export { Text } from './Text'; 14 | export { Timerbar } from './Timerbar'; 15 | export * from './menu'; 16 | -------------------------------------------------------------------------------- /src/weapon/Mk2WeaponHash.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Mk2 weapon hash 3 | * 4 | */ 5 | export enum Mk2WeaponHash { 6 | // handguns 7 | PistolMk2 = 0xbfe256d4, 8 | SNSPistolMk2 = 0x88374054, 9 | RevolverMk2 = 0xcb96392f, 10 | 11 | // smg 12 | SMGMk2 = 0x78a97cd0, 13 | 14 | // shotgun 15 | PumpShotgunMk2 = 0x555af99a, 16 | 17 | // assault_rifles 18 | AssaultRifleMk2 = 0x394f415c, 19 | CarbineRifleMk2 = 0xfad1f1c9, 20 | SpecialCarbineMk2 = 0x969c3d67, 21 | BullpupRifleMk2 = 0x84d6fafd, 22 | 23 | // machine_guns 24 | CombatMGMk2 = 0xdbbd7280, 25 | 26 | // sniper_rifles 27 | HeavySniperMk2 = 0xa914799, 28 | MarksmanRifleMk2 = 0x6a6c02e0, 29 | } 30 | -------------------------------------------------------------------------------- /src/enums/ExplosionType.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * List of explosion sources. 3 | */ 4 | export enum ExplosionType { 5 | Grenade, 6 | GrenadeL, 7 | StickyBomb, 8 | Molotov1, 9 | Rocket, 10 | TankShell, 11 | HiOctane, 12 | Car, 13 | Plane, 14 | PetrolPump, 15 | Bike, 16 | Steam, 17 | Flame, 18 | WaterHydrant, 19 | GasCanister, 20 | Boat, 21 | ShipDestroy, 22 | Truck, 23 | Bullet, 24 | SmokeGL, 25 | SmokeG, 26 | BZGas, 27 | Flare, 28 | GasCanister2, 29 | Extinguisher, 30 | ProgramAR, 31 | Train, 32 | Barrel, 33 | Propane, 34 | Blimp, 35 | FlameExplode, 36 | Tanker, 37 | PlaneRocket, 38 | VehicleBullet, 39 | GasTank, 40 | FireWork, 41 | SnowBall, 42 | ProxMine, 43 | Valkyrie, 44 | } 45 | -------------------------------------------------------------------------------- /src/models/VehicleWheel.ts: -------------------------------------------------------------------------------- 1 | import { Vehicle } from './Vehicle'; 2 | 3 | export class VehicleWheel { 4 | private _owner: Vehicle; 5 | private _index: number; 6 | 7 | constructor(owner: Vehicle, index: number) { 8 | this._owner = owner; 9 | this._index = index; 10 | } 11 | 12 | public get Index(): number { 13 | return this._index; 14 | } 15 | 16 | public set Index(index: number) { 17 | this._index = index; 18 | } 19 | 20 | public get Vehicle(): Vehicle { 21 | return this._owner; 22 | } 23 | 24 | public burst(): void { 25 | SetVehicleTyreBurst(this._owner.Handle, this.Index, true, 1000); 26 | } 27 | 28 | public fix(): void { 29 | SetVehicleTyreFixed(this._owner.Handle, this.Index); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "[Request]" 5 | labels: enhancement 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /src/utils/Point.ts: -------------------------------------------------------------------------------- 1 | export class Point { 2 | public static parse(arg: [number, number] | { X: number; Y: number } | string): Point { 3 | let point = new Point(); 4 | if (arg) { 5 | if (typeof arg === 'object') { 6 | if (Array.isArray(arg)) { 7 | if (arg.length === 2) { 8 | point = new Point(arg[0], arg[1]); 9 | } 10 | } else if (arg.X && arg.Y) { 11 | point = new Point(arg.X, arg.Y); 12 | } 13 | } else { 14 | if (arg.indexOf(',') !== -1) { 15 | const arr = arg.split(','); 16 | point = new Point(parseFloat(arr[0]), parseFloat(arr[1])); 17 | } 18 | } 19 | } 20 | return point; 21 | } 22 | 23 | public X: number; 24 | public Y: number; 25 | 26 | constructor(x = 0, y = 0) { 27 | this.X = x; 28 | this.Y = y; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/utils/LiteEvent.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-explicit-any */ 2 | export interface LiteEvent { 3 | on(handler: { (...args: unknown[]): any }): void; 4 | off(handler: { (...args: unknown[]): any }): void; 5 | } 6 | 7 | export class LiteEvent implements LiteEvent { 8 | private handlers: { (...args: unknown[]): any }[] = []; 9 | 10 | public on(handler: { (...args: unknown[]): any }): void { 11 | this.handlers.push(handler); 12 | } 13 | 14 | public off(handler: { (...args: unknown[]): any }): void { 15 | this.handlers = this.handlers.filter(h => h !== handler); 16 | } 17 | 18 | public emit(...args: unknown[]): void { 19 | this.handlers.slice(0).forEach(h => { 20 | h(...args); 21 | }); 22 | } 23 | 24 | public expose(): LiteEvent { 25 | return this; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/models/EntityBoneCollection.ts: -------------------------------------------------------------------------------- 1 | import { Entity, EntityBone } from './'; 2 | 3 | export class EntityBoneCollection { 4 | protected readonly owner: Entity; 5 | 6 | private readonly _collection: Enumerator | undefined; 7 | private _currentIndex = -1; 8 | 9 | constructor(owner: Entity) { 10 | this.owner = owner; 11 | } 12 | 13 | public hasBone(name: string): boolean { 14 | return GetEntityBoneIndexByName(this.owner.Handle, name) !== -1; 15 | } 16 | 17 | public getBone(boneIndex?: number, boneName?: string): EntityBone { 18 | return new EntityBone( 19 | this.owner, 20 | boneIndex ? boneIndex : GetEntityBoneIndexByName(this.owner.Handle, boneName ?? ''), 21 | ); 22 | } 23 | 24 | public get Core(): EntityBone { 25 | return new EntityBone(this.owner, -1); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/models/PedBoneCollection.ts: -------------------------------------------------------------------------------- 1 | import { EntityBoneCollection, Ped, PedBone } from './'; 2 | 3 | export class PedBoneCollection extends EntityBoneCollection { 4 | constructor(owner: Ped) { 5 | super(owner); 6 | } 7 | 8 | public get Core(): PedBone { 9 | return new PedBone(this.owner as Ped, -1); 10 | } 11 | 12 | public get LastDamaged(): PedBone { 13 | const [, outBone] = GetPedLastDamageBone(this.owner.Handle, 0); 14 | return (PedBone as never)[outBone]; 15 | } 16 | 17 | public clearLastDamaged(): void { 18 | ClearPedLastDamageBone(this.owner.Handle); 19 | } 20 | 21 | public getBone(boneIndex?: number, boneName?: string): PedBone { 22 | return new PedBone( 23 | this.owner as Ped, 24 | boneIndex ? boneIndex : GetEntityBoneIndexByName(this.owner.Handle, boneName ?? ''), 25 | ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/utils/index.ts: -------------------------------------------------------------------------------- 1 | export { Vector2 } from './Vector2'; 2 | export { Vector3 } from './Vector3'; 3 | export { Vector4 } from './Vector4'; 4 | export { String } from './String'; 5 | export { LiteEvent } from './LiteEvent'; 6 | export { PointF } from './PointF'; 7 | export { Crypto } from './Crypto'; 8 | export { Point } from './Point'; 9 | export { Color } from './Color'; 10 | export { Maths } from './Maths'; 11 | export { Size } from './Size'; 12 | export { Quaternion } from './Quaternion'; 13 | 14 | export const Wait = (milliseconds: number): Promise => 15 | new Promise(resolve => setTimeout(resolve, milliseconds)); 16 | 17 | export { enumValues } from './enumValues'; 18 | export { getStringFromUInt8Array } from './getStringFromUInt8Array'; 19 | export { getUInt32FromUint8Array } from './getUInt32FromUint8Array'; 20 | export * from './Animations'; 21 | -------------------------------------------------------------------------------- /src/utils/enumValues.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * EnumValues - iterate over enum values 3 | * Just copy&paste from https://github.com/microsoft/TypeScript/issues/4753#issuecomment-694557208 4 | * 5 | * @param enumObj 6 | */ 7 | export function enumValues(enumObj: { [key: string]: T }): IterableIterator; 8 | export function enumValues(enumObj: { 9 | [key: string]: T; 10 | }): IterableIterator>; 11 | export function* enumValues(enumObj: { [key: string]: T }): IterableIterator { 12 | let isStringEnum = true; 13 | for (const property in enumObj) { 14 | if (typeof enumObj[property] === 'number') { 15 | isStringEnum = false; 16 | break; 17 | } 18 | } 19 | for (const property in enumObj) { 20 | if (isStringEnum || typeof enumObj[property] === 'number') { 21 | yield enumObj[property]; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/enums/Driving.ts: -------------------------------------------------------------------------------- 1 | export enum DrivingStyle { 2 | None = 0, 3 | Normal = 786603, 4 | IgnoreLights = 2883621, 5 | SometimesOvertakeTraffic = 5, 6 | Rushed = 1074528293, 7 | AvoidTraffic = 786468, 8 | AvoidTrafficExtremely = 6, 9 | AvoidHighwaysWhenPossible = 536870912, 10 | IgnorePathing = 16777216, 11 | IgnoreRoads = 4194304, 12 | ShortestPath = 262144, 13 | Backwards = 1024, 14 | } 15 | 16 | export enum VehicleDrivingFlags { 17 | None = 0, 18 | FollowTraffic = 1, 19 | YieldToPeds = 2, 20 | AvoidVehicles = 4, 21 | AvoidEmptyVehicles = 8, 22 | AvoidPeds = 16, 23 | AvoidObjects = 32, 24 | StopAtTrafficLights = 128, 25 | UseBlinkers = 256, 26 | AllowGoingWrongWay = 512, 27 | Reverse = 1024, 28 | AllowMedianCrossing = 262144, 29 | DriveBySight = 4194304, 30 | IgnorePathFinding = 16777216, 31 | TryToAvoidHighways = 536870912, 32 | StopAtDestination = 2147483648, 33 | } 34 | -------------------------------------------------------------------------------- /src/utils/Quaternion.ts: -------------------------------------------------------------------------------- 1 | import { Vector3 } from './Vector3'; 2 | 3 | export class Quaternion { 4 | public x: number; 5 | public y: number; 6 | public z: number; 7 | public w: number; 8 | 9 | constructor(value: number); 10 | constructor(vector: Vector3, w: number); 11 | constructor(x: number, y: number, z: number, w: number); 12 | constructor(valueXOrVector: number | Vector3, yOrW?: number, z?: number, w?: number) { 13 | if (valueXOrVector instanceof Vector3) { 14 | this.x = valueXOrVector.x; 15 | this.y = valueXOrVector.y; 16 | this.z = valueXOrVector.z; 17 | this.w = yOrW ?? 0; 18 | } else if (yOrW === undefined) { 19 | this.x = valueXOrVector; 20 | this.y = valueXOrVector; 21 | this.z = valueXOrVector; 22 | this.w = valueXOrVector; 23 | } else { 24 | this.x = valueXOrVector; 25 | this.y = yOrW; 26 | this.z = z ?? 0; 27 | this.w = w ?? 0; 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/enums/RadioStation.ts: -------------------------------------------------------------------------------- 1 | export enum RadioStation { 2 | LosSantosRockRadio = 'RADIO_01_CLASS_ROCK', 3 | NonStopPopFM = 'RADIO_02_POP', 4 | RadioLosSantos = 'RADIO_03_HIPHOP_NEW', 5 | ChannelX = 'RADIO_04_PUNK', 6 | WestCoastTalkRadio = 'RADIO_05_TALK_01', 7 | RebelRadio = 'RADIO_06_COUNTRY', 8 | SoulwaxFM = 'RADIO_07_DANCE_01', 9 | EastLosFM = 'RADIO_08_MEXICAN', 10 | WestCoastClassics = 'RADIO_09_HIPHOP_OLD', 11 | BlaineCountyRadio = 'RADIO_11_TALK_02', 12 | TheBlueArk = 'RADIO_12_REGGAE', 13 | WorldWideFM = 'RADIO_13_JAZZ', 14 | FlyloFM = 'RADIO_14_DANCE_02', 15 | TheLowdown = 'RADIO_15_MOTOWN', 16 | RadioMirrorPark = 'RADIO_16_SILVERLAKE', 17 | Space = 'RADIO_17_FUNK', 18 | VinewoodBoulevardRadio = 'RADIO_18_90S_ROCK', 19 | SelfRadio = 'RADIO_19_USER', 20 | TheLab = 'RADIO_20_THELAB', 21 | BlondedLosSantos = 'RADIO_21_DLC_XM17', 22 | LosSantosUndergroundRadio = 'RADIO_22_DLC_BATTLE_MIX1_RADIO', 23 | RadioOff = 'OFF', 24 | } 25 | -------------------------------------------------------------------------------- /src/models/index.ts: -------------------------------------------------------------------------------- 1 | export { Entity } from './Entity'; 2 | export { EntityBone } from './EntityBone'; 3 | export { EntityBoneCollection } from './EntityBoneCollection'; 4 | export { Ped } from './Ped'; 5 | export { PedBone } from './PedBone'; 6 | export { PedBoneCollection } from './PedBoneCollection'; 7 | export { Player } from './Player'; 8 | export { Prop } from './Prop'; 9 | export { Vehicle } from './Vehicle'; 10 | export { VehicleDoor } from './VehicleDoor'; 11 | export { VehicleDoorCollection } from './VehicleDoorCollection'; 12 | export { VehicleMod } from './VehicleMod'; 13 | export { VehicleToggleMod } from './VehicleToggleMod'; 14 | export { VehicleModCollection } from './VehicleModCollection'; 15 | export { VehicleWheel } from './VehicleWheel'; 16 | export { VehicleWheelCollection } from './VehicleWheelCollection'; 17 | export { VehicleWindow } from './VehicleWindow'; 18 | export { VehicleWindowCollection } from './VehicleWindowCollection'; 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: "[BUG]" 5 | labels: bug 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Use this code '....' 17 | 3. Download this example '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **FiveM Client (please complete the following information):** 27 | - Canary: [e.g. yes, no] 28 | - Version [e.g. 2880] 29 | 30 | **FiveM Server (please complete the following information):** 31 | - OneSync: [e.g. on, off, population] 32 | - Artifact: [e.g. 2929] 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /src/models/EntityBone.ts: -------------------------------------------------------------------------------- 1 | import { Vector3 } from '../utils'; 2 | import { Entity } from './'; 3 | 4 | export class EntityBone { 5 | public get Index(): number { 6 | return this.index; 7 | } 8 | 9 | public get Owner(): Entity { 10 | return this.owner; 11 | } 12 | 13 | public get Position(): Vector3 { 14 | return Vector3.fromArray(GetWorldPositionOfEntityBone(this.owner.Handle, this.index)); 15 | } 16 | 17 | public get Rotation(): Vector3 { 18 | return Vector3.fromArray(GetEntityBoneRotation(this.owner.Handle, this.index)); 19 | } 20 | 21 | public get IsValid(): boolean { 22 | return this.owner.exists() && this.index !== -1; 23 | } 24 | 25 | protected readonly owner: Entity; 26 | protected readonly index: number; 27 | 28 | constructor(owner: Entity, boneIndex?: number, boneName?: string) { 29 | this.owner = owner; 30 | this.index = boneIndex 31 | ? boneIndex 32 | : GetEntityBoneIndexByName(this.owner.Handle, boneName ?? ''); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/weapon/WeaponTint.ts: -------------------------------------------------------------------------------- 1 | export enum WeaponTint { 2 | Mk2ClassicBlack, 3 | Mk2ClassicGray, 4 | Mk2ClassicTwoTone, 5 | Mk2ClassicWhite, 6 | Mk2ClassicBeige, 7 | Mk2ClassicGreen, 8 | Mk2ClassicBlue, 9 | Mk2ClassicEarth, 10 | Mk2ClassicBrownAndBlack, 11 | Mk2RedContrast, 12 | Mk2BlueContrast, 13 | Mk2YellowContrast, 14 | Mk2OrangeContrast, 15 | Mk2BoldPink, 16 | Mk2BoldPurpleAndYellow, 17 | Mk2BoldOrange, 18 | Mk2BoldGreenAndPurple, 19 | Mk2BoldRedFeatures, 20 | Mk2BoldGreenFeatures, 21 | Mk2BoldCyanFeatures, 22 | Mk2BoldYellowFeatures, 23 | Mk2BoldRedAndWhite, 24 | Mk2BoldBlueAndWhite, 25 | Mk2MetallicGold, 26 | Mk2MetallicPlatinum, 27 | Mk2MetallicGrayAndLilac, 28 | Mk2MetallicPurpleAndLime, 29 | Mk2MetallicRed, 30 | Mk2MetallicGreen, 31 | Mk2MetallicBlue, 32 | Mk2MetallicWhiteAndAqua, 33 | Mk2MetallicRedAndYellow, 34 | Normal = 0, 35 | Green = 1, 36 | Gold = 2, 37 | Pink = 3, 38 | Army = 4, 39 | LSPD = 5, 40 | Orange = 6, 41 | Platinum = 7, 42 | } 43 | -------------------------------------------------------------------------------- /src/utils/Color.ts: -------------------------------------------------------------------------------- 1 | export class Color { 2 | public static empty = new Color(0, 0, 0, 0); 3 | public static transparent = new Color(0, 0, 0, 0); 4 | public static black = new Color(255, 0, 0, 0); 5 | public static white = new Color(255, 255, 255, 255); 6 | public static whiteSmoke = new Color(255, 245, 245, 245); 7 | 8 | public static fromArgb(a: number, r: number, g: number, b: number): Color { 9 | return new Color(a, r, g, b); 10 | } 11 | 12 | public static fromRgb(r: number, g: number, b: number): Color { 13 | return new Color(255, r, g, b); 14 | } 15 | 16 | public static fromArray(primitive: [number, number, number] | number[]): Color { 17 | return new Color(255, primitive[0], primitive[1], primitive[2]); 18 | } 19 | 20 | public a: number; 21 | public r: number; 22 | public g: number; 23 | public b: number; 24 | 25 | constructor(a = 255, r: number, g: number, b: number) { 26 | this.a = a; 27 | this.r = r; 28 | this.g = g; 29 | this.b = b; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/models/Prop.ts: -------------------------------------------------------------------------------- 1 | import { ClassTypes } from '../enums/ClassTypes'; 2 | import { Entity } from './'; 3 | 4 | export class Prop extends Entity { 5 | public static exists(prop: Prop): boolean { 6 | return typeof prop !== 'undefined' && prop.exists(); 7 | } 8 | 9 | public static fromHandle(handle: number): Prop | null { 10 | return new Prop(handle); 11 | } 12 | 13 | public static fromNetworkId(networkId: number, errorOnInvalid = false): Prop | null { 14 | if (errorOnInvalid && NetworkDoesEntityExistWithNetworkId(networkId)) { 15 | throw new Error(`Entity with ${networkId} doesn't exist`); 16 | } 17 | 18 | return new Prop(NetworkGetEntityFromNetworkId(networkId)); 19 | } 20 | protected type = ClassTypes.Prop; 21 | 22 | constructor(handle: number) { 23 | super(handle); 24 | } 25 | 26 | public exists(): boolean { 27 | return super.exists() && GetEntityType(this.handle) === 3; 28 | } 29 | 30 | public placeOnGround(): void { 31 | PlaceObjectOnGroundProperly(this.handle); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /DEVELOPMENT.md: -------------------------------------------------------------------------------- 1 | ### Getting Started 2 | 3 | 1. First, you need to have the latest git, node 12 or greater installed. OSX, Windows and Linux should all be supported as build environments. This may differ from FiveM's supported environments. 4 | 5 | 1. For this repo by using the "Fork" button on the upper-right 6 | 2. Check out your fork 7 | ``` 8 | git clone git@github.com:yournamehere/native-wrappers-client.git 9 | ``` 10 | 3. Install or Update all dependencies 11 | ``` 12 | npm i 13 | ``` 14 | 4. Get coding! If you've changed or added new functionality, update any relevant documentation. Ensure your work is committed within a feature branch. 15 | 5. Ensure the project has no linting errors and builds 16 | ``` 17 | npm run lint 18 | npm run build 19 | ``` 20 | 21 | ### Relevant Commands 22 | 1. `npm i` - install and link all packages 23 | 2. `npm run build` - builds using `tsc` 24 | 3. `npm run format` - autoformats with eslint --fix and prettier 25 | 4. `npm run lint` - checks for linting issues 26 | 5. `npm run docs` - builds documentation 27 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './utils'; 2 | 3 | export { Game } from './Game'; 4 | export { World } from './World'; 5 | export { Model } from './Model'; 6 | export { Audio } from './Audio'; 7 | export { Blip } from './Blip'; 8 | export { Camera } from './Camera'; 9 | export { Checkpoint } from './Checkpoint'; 10 | export { GameplayCamera } from './GameplayCamera'; 11 | export { ParticleEffect } from './ParticleEffect'; 12 | export { ParticleEffectAsset } from './ParticleEffectAsset'; 13 | export { Pickup } from './Pickup'; 14 | export { RaycastResult } from './Raycast'; 15 | export { RelationshipGroup } from './RelationshipGroup'; 16 | export { Tasks } from './Tasks'; 17 | export { TaskSequence } from './TaskSequence'; 18 | export { NetworkedScene } from './NetworkedScene'; 19 | export { Rope } from './Rope'; 20 | 21 | // Lets export all from folders 22 | export * from './models'; 23 | export * from './enums'; 24 | export * from './hashes'; 25 | export * from './ui'; 26 | 27 | export * from './weapon'; 28 | export * from './weaponComponent'; 29 | -------------------------------------------------------------------------------- /src/enums/MarkerType.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * List of markers. Markers are 3D visual objects in the world. 3 | * 4 | * See native [DRAW_MARKER](https://docs.fivem.net/game-references/markers/) for pictures. 5 | */ 6 | export enum MarkerType { 7 | UpsideDownCone, 8 | VerticalCylinder, 9 | ThickChevronUp, 10 | ThinChevronUp, 11 | CheckeredFlagRect, 12 | CheckeredFlagCircle, 13 | VerticleCircle, 14 | PlaneModel, 15 | LostMCDark, 16 | LostMCLight, 17 | Number0, 18 | Number1, 19 | Number2, 20 | Number3, 21 | Number4, 22 | Number5, 23 | Number6, 24 | Number7, 25 | Number8, 26 | Number9, 27 | ChevronUpx1, 28 | ChevronUpx2, 29 | ChevronUpx3, 30 | HorizontalCircleFat, 31 | ReplayIcon, 32 | HorizontalCircleSkinny, 33 | HorizontalCircleSkinnyArrow, 34 | HorizontalSplitArrowCircle, 35 | DebugSphere, 36 | DollarSign, 37 | HorizontalBars, 38 | WolfHead, 39 | QuestionMark, 40 | PlaneSymbol, 41 | HelicopterSymbol, 42 | BoatSymbol, 43 | CarSymbol, 44 | MotorcycleSymbol, 45 | BikeSymbol, 46 | TruckSymbol, 47 | ParachuteSymbol, 48 | SawbladeSymbol, 49 | } 50 | -------------------------------------------------------------------------------- /src/enums/SpeechModifier.ts: -------------------------------------------------------------------------------- 1 | export enum SpeechModifier { 2 | Standard = 0, 3 | AllowRepeat = 1, 4 | Beat = 2, 5 | Force = 3, 6 | ForceFrontend = 4, 7 | ForceNoRepeatFrontend = 5, 8 | ForceNormal = 6, 9 | ForceNormalClear = 7, 10 | ForceNormalCritical = 8, 11 | ForceShouted = 9, 12 | ForceShoutedClear = 10, 13 | ForceShoutedCritical = 11, 14 | ForcePreloadOnly = 12, 15 | Megaphone = 13, 16 | Helicopter = 14, 17 | ForceMegaphone = 15, 18 | ForceHelicopter = 16, 19 | Interrupt = 17, 20 | InterruptShouted = 18, 21 | InterruptShoutedClear = 19, 22 | InterruptShoutedCritical = 20, 23 | InterruptNoForce = 21, 24 | InterruptFrontend = 22, 25 | InterruptNoForceFrontend = 23, 26 | AddBlip = 24, 27 | AddBlipAllowRepeat = 25, 28 | AddBlipForce = 26, 29 | AddBlipShouted = 27, 30 | AddBlipShoutedForce = 28, 31 | AddBlipInterrupt = 29, 32 | AddBlipInterruptForce = 30, 33 | ForcePreloadOnlyShouted = 31, 34 | ForcePreloadOnlyShoutedClear = 32, 35 | ForcePreloadOnlyShoutedCritical = 33, 36 | Shouted = 34, 37 | ShoutedClear = 35, 38 | ShoutedCritical = 36, 39 | } 40 | -------------------------------------------------------------------------------- /src/enums/HudComponent.ts: -------------------------------------------------------------------------------- 1 | export enum HudComponent { 2 | WantedStars = 1, 3 | WeaponIcon, 4 | Cash, 5 | MpCash, 6 | MpMessage, 7 | VehicleName, 8 | AreaName, 9 | Unused, 10 | StreetName, 11 | HelpText, 12 | FloatingHelpText1, 13 | FloatingHelpText2, 14 | CashChange, 15 | Reticle, 16 | SubtitleText, 17 | RadioStationsWheel, 18 | Saving, 19 | GamingStreamUnusde, 20 | WeaponWheel, 21 | WeaponWheelStats, 22 | DrugsPurse01, 23 | DrugsPurse02, 24 | DrugsPurse03, 25 | DrugsPurse04, 26 | MpTagCashFromBank, 27 | MpTagPackages, 28 | MpTagCuffKeys, 29 | MpTagDownloadData, 30 | MpTagIfPedFollowing, 31 | MpTagKeyCard, 32 | MpTagRandomObject, 33 | MpTagRemoteControl, 34 | MpTagCashFromSafe, 35 | MpTagWeaponsPackage, 36 | MpTagKeys, 37 | MpVehicle, 38 | MpVehicleHeli, 39 | MpVehiclePlane, 40 | PlayerSwitchAlert, 41 | MpRankBar, 42 | DirectorMode, 43 | ReplayController, 44 | ReplayMouse, 45 | ReplayHeader, 46 | ReplayOptions, 47 | ReplayHelpText, 48 | ReplayMiscText, 49 | ReplayTopLine, 50 | ReplayBottomLine, 51 | ReplayLeftBar, 52 | ReplayTimer, 53 | } 54 | -------------------------------------------------------------------------------- /src/models/VehicleToggleMod.ts: -------------------------------------------------------------------------------- 1 | import { Vehicle } from './Vehicle'; 2 | import { VehicleToggleModType } from '../enums'; 3 | 4 | export class VehicleToggleMod { 5 | private _owner: Vehicle; 6 | private _modType: VehicleToggleModType; 7 | 8 | constructor(owner: Vehicle, modType: VehicleToggleModType) { 9 | this._owner = owner; 10 | this._modType = modType; 11 | } 12 | 13 | public get ModType(): VehicleToggleModType { 14 | return this._modType; 15 | } 16 | 17 | public set ModType(modType: VehicleToggleModType) { 18 | this._modType = modType; 19 | } 20 | 21 | public get IsInstalled(): boolean { 22 | return IsToggleModOn(this._owner.Handle, this.ModType); 23 | } 24 | 25 | public set IsInstalled(value: boolean) { 26 | ToggleVehicleMod(this._owner.Handle, this.ModType, value); 27 | } 28 | 29 | public get LocalizedModTypeName(): string { 30 | return GetModSlotName(this._owner.Handle, this.ModType); 31 | } 32 | 33 | public get Vehicle(): Vehicle { 34 | return this._owner; 35 | } 36 | 37 | public remove(): void { 38 | RemoveVehicleMod(this._owner.Handle, this.ModType); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/enums/AudioFlag.ts: -------------------------------------------------------------------------------- 1 | export enum AudioFlag { 2 | ActivateSwitchWheelAudio, 3 | AllowCutsceneOverScreenFade, 4 | AllowForceRadioAfterRetune, 5 | AllowPainAndAmbientSpeechToPlayDuringCutscene, 6 | AllowPlayerAIOnMission, 7 | AllowPoliceScannerWhenPlayerHasNoControl, 8 | AllowRadioDuringSwitch, 9 | AllowRadioOverScreenFade, 10 | AllowScoreAndRadio, 11 | AllowScriptedSpeechInSlowMo, 12 | AvoidMissionCompleteDelay, 13 | DisableAbortConversationForDeathAndInjury, 14 | DisableAbortConversationForRagdoll, 15 | DisableBarks, 16 | DisableFlightMusic, 17 | DisableReplayScriptStreamRecording, 18 | EnableHeadsetBeep, 19 | ForceConversationInterrupt, 20 | ForceSeamlessRadioSwitch, 21 | ForceSniperAudio, 22 | FrontendRadioDisabled, 23 | HoldMissionCompleteWhenPrepared, 24 | IsDirectorModeActive, 25 | IsPlayerOnMissionForSpeech, 26 | ListenerReverbDisabled, 27 | LoadMPData, 28 | MobileRadioInGame, 29 | OnlyAllowScriptTriggerPoliceScanner, 30 | PlayMenuMusic, 31 | PoliceScannerDisabled, 32 | ScriptedConvListenerMaySpeak, 33 | SpeechDucksScore, 34 | SuppressPlayerScubaBreathing, 35 | WantedMusicDisabled, 36 | WantedMusicOnMission, 37 | } 38 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: "Publish Package" 2 | on: 3 | push: 4 | tags: 5 | - '*' 6 | jobs: 7 | build: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Get tag 11 | run: echo "RELEASE_VERSION=${GITHUB_REF#refs/*/}" >> $GITHUB_ENV 12 | - name: Checkout 13 | uses: actions/checkout@v2 14 | with: 15 | ref: master 16 | - name: Bump package version 17 | run: node .github/actions/bump-package-version.js 18 | env: 19 | RELEASE_VERSION: ${{ env.RELEASE_VERSION }} 20 | - uses: actions/setup-node@v2 21 | with: 22 | node-version: '16.x' 23 | registry-url: 'https://registry.npmjs.org' 24 | - uses: pnpm/action-setup@v2.1.0 25 | with: 26 | version: ^6.24.1 27 | - run: pnpm install 28 | - run: pnpm run ci 29 | # because we update the package version pnpm will get mad over an unclean branch 30 | # we don't want a bunch of version bump commits so just ignore the git checks 31 | - run: pnpm publish --no-git-checks 32 | env: 33 | NODE_AUTH_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} -------------------------------------------------------------------------------- /src/ui/menu/items/UIMenuSeparatorItem.ts: -------------------------------------------------------------------------------- 1 | import { UIMenuItem } from './'; 2 | import { Alignment } from '../../../enums'; 3 | import { Menu } from '../'; 4 | 5 | export class UIMenuSeparatorItem extends UIMenuItem { 6 | protected supportsDescription = false; 7 | protected supportsPanels = false; 8 | protected supportsLeftBadge = false; 9 | protected supportsRightBadge = false; 10 | protected supportsRightLabel = false; 11 | 12 | constructor(text?: string) { 13 | super(text ?? ''); 14 | this.text.alignment = Alignment.Centered; 15 | } 16 | 17 | public setVerticalPosition(y: number): void { 18 | const yOffset = y + this.offset.Y; 19 | this.rectangle.pos.Y = yOffset + 144; 20 | this.text.pos.Y = yOffset + 147; 21 | } 22 | 23 | public draw(): void { 24 | const width = 431 + (this.parent ? this.parent.WidthOffset : 0); 25 | this.rectangle.size.width = width; 26 | this.rectangle.pos.X = this.offset.X; 27 | this.rectangle.draw(undefined, Menu.screenResolution); 28 | 29 | if (this.text.caption !== '') { 30 | this.text.pos.X = this.offset.X + width / 2; 31 | this.text.draw(undefined, Menu.screenResolution); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/utils/String.ts: -------------------------------------------------------------------------------- 1 | import { Font, Screen, Text } from '..'; 2 | import { Maths } from './Maths'; 3 | 4 | export abstract class String { 5 | public static stringToArray(input: string): string[] { 6 | let stringsNeeded = 1; 7 | if (input.length > 99) { 8 | stringsNeeded = Math.ceil(input.length / 99); 9 | } 10 | 11 | const outputString: string[] = new Array(stringsNeeded); 12 | for (let i = 0; i < stringsNeeded; i++) { 13 | outputString[i] = input.substring( 14 | i * 99, 15 | i * 99 + Maths.clamp(input.substring(i * 99).length, 0, 99), 16 | ); 17 | } 18 | return outputString; 19 | } 20 | 21 | public static measureStringWidthNoConvert( 22 | input: string, 23 | font = Font.ChaletLondon, 24 | scale = 0, 25 | ): number { 26 | SetTextEntryForWidth('STRING'); 27 | Text.addLongString(input); 28 | SetTextFont(font); 29 | SetTextScale(1, scale); 30 | return GetTextScreenWidth(false); 31 | } 32 | 33 | public static measureString( 34 | str: string, 35 | font?: Font, 36 | scale?: number, 37 | screenWidth = Screen.ScaledWidth, 38 | ): number { 39 | return this.measureStringWidthNoConvert(str, font, scale) * screenWidth; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/models/VehicleWindow.ts: -------------------------------------------------------------------------------- 1 | import { Vehicle } from './Vehicle'; 2 | import { VehicleWindowIndex } from '../enums'; 3 | 4 | export class VehicleWindow { 5 | private _owner: Vehicle; 6 | private _index: VehicleWindowIndex; 7 | 8 | constructor(owner: Vehicle, index: VehicleWindowIndex) { 9 | this._owner = owner; 10 | this._index = index; 11 | } 12 | 13 | public get Index(): VehicleWindowIndex { 14 | return this._index; 15 | } 16 | 17 | public set Index(index: VehicleWindowIndex) { 18 | this._index = index; 19 | } 20 | 21 | public get IsIntact(): boolean { 22 | return IsVehicleWindowIntact(this._owner.Handle, this.Index); 23 | } 24 | 25 | public get Vehicle(): Vehicle { 26 | return this._owner; 27 | } 28 | 29 | public repair(): void { 30 | FixVehicleWindow(this._owner.Handle, this.Index); 31 | } 32 | 33 | public smash(): void { 34 | SmashVehicleWindow(this._owner.Handle, this.Index); 35 | } 36 | 37 | public rollUp(): void { 38 | RollUpWindow(this._owner.Handle, this.Index); 39 | } 40 | 41 | public rollDown(): void { 42 | RollDownWindow(this._owner.Handle, this.Index); 43 | } 44 | 45 | public remove(): void { 46 | RemoveVehicleWindow(this._owner.Handle, this.Index); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/weaponComponent/InvalidWeaponComponent.ts: -------------------------------------------------------------------------------- 1 | import { WeaponComponent } from './WeaponComponent'; 2 | import { WeaponComponentHash } from './WeaponComponentHash'; 3 | import { WeaponHash } from '../hashes'; 4 | import { ComponentAttachmentPoint } from './ComponentAttachmentPoint'; 5 | import { Game } from '../Game'; 6 | 7 | export class InvalidWeaponComponent extends WeaponComponent { 8 | constructor() { 9 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 10 | super(null!, null!, WeaponComponentHash.Invalid); 11 | } 12 | 13 | public get Active(): boolean { 14 | return false; 15 | } 16 | 17 | // eslint-disable-next-line @typescript-eslint/no-empty-function 18 | public set Active(value: boolean) {} 19 | 20 | public get DisplayName(): string { 21 | return 'WCT_INVALID'; 22 | } 23 | 24 | public get LocalizedName(): string { 25 | return Game.getGXTEntry(this.DisplayName); 26 | } 27 | 28 | public static getAttachmentPoint( 29 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 30 | hash: WeaponHash, 31 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 32 | componentHash: WeaponComponentHash, 33 | ): ComponentAttachmentPoint { 34 | return ComponentAttachmentPoint.Invalid; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/ui/Container.ts: -------------------------------------------------------------------------------- 1 | import { Color, Point, Size } from '../utils'; 2 | import { IDrawable, Screen } from './'; 3 | 4 | export class Container implements IDrawable { 5 | public pos: Point; 6 | public size: Size; 7 | public color: Color; 8 | public items: IDrawable[] = []; 9 | 10 | constructor(pos: Point, size: Size, color: Color) { 11 | this.pos = pos; 12 | this.size = size; 13 | this.color = color; 14 | } 15 | 16 | public addItem(items: IDrawable | IDrawable[]): void { 17 | if (!Array.isArray(items)) { 18 | items = [items]; 19 | } 20 | this.items.push(...items); 21 | } 22 | 23 | public draw(offset?: Size, resolution?: Size): void { 24 | resolution = resolution || new Size(Screen.ScaledWidth, Screen.Height); 25 | offset = offset || new Size(); 26 | 27 | const w = this.size.width / resolution.width; 28 | const h = this.size.height / resolution.height; 29 | const x = (this.pos.X + offset.width) / resolution.width + w * 0.5; 30 | const y = (this.pos.Y + offset.height) / resolution.height + h * 0.5; 31 | 32 | DrawRect(x, y, w, h, this.color.r, this.color.g, this.color.b, this.color.a); 33 | 34 | for (const item of this.items) { 35 | item.draw(new Size(this.pos.X + offset.width, this.pos.Y + offset.height), resolution); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/enums/ZoneID.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * List of Zones. Useful for using world zone related natives. 3 | */ 4 | export enum ZoneID { 5 | AIRP, 6 | ALAMO, 7 | ALTA, 8 | ARMYB, 9 | BANHAMC, 10 | BANNING, 11 | BEACH, 12 | BHAMCA, 13 | BRADP, 14 | BRADT, 15 | BURTON, 16 | CALAFB, 17 | CANNY, 18 | CCREAK, 19 | CHAMH, 20 | CHIL, 21 | CHU, 22 | CMSW, 23 | CYPRE, 24 | DAVIS, 25 | DELBE, 26 | DELPE, 27 | DELSOL, 28 | DESRT, 29 | DOWNT, 30 | DTVINE, 31 | EAST_V, 32 | EBURO, 33 | ELGORL, 34 | ELYSIAN, 35 | GALFISH, 36 | golf, 37 | GRAPES, 38 | GREATC, 39 | HARMO, 40 | HAWICK, 41 | HORS, 42 | HUMLAB, 43 | JAIL, 44 | KOREAT, 45 | LACT, 46 | LAGO, 47 | LDAM, 48 | LEGSQU, 49 | LMESA, 50 | LOSPUER, 51 | MIRR, 52 | MORN, 53 | MOVIE, 54 | MTCHIL, 55 | MTGORDO, 56 | MTJOSE, 57 | MURRI, 58 | NCHU, 59 | NOOSE, 60 | OCEANA, 61 | PALCOV, 62 | PALETO, 63 | PALFOR, 64 | PALHIGH, 65 | PALMPOW, 66 | PBLUFF, 67 | PBOX, 68 | PROCOB, 69 | RANCHO, 70 | RGLEN, 71 | RICHM, 72 | ROCKF, 73 | RTRAK, 74 | SanAnd, 75 | SANCHIA, 76 | SANDY, 77 | SKID, 78 | SLAB, 79 | STAD, 80 | STRAW, 81 | TATAMO, 82 | TERMINA, 83 | TEXTI, 84 | TONGVAH, 85 | TONGVAV, 86 | VCANA, 87 | VESP, 88 | VINE, 89 | WINDF, 90 | WVINE, 91 | ZANCUDO, 92 | ZP_ORT, 93 | ZQ_UAR, 94 | } 95 | -------------------------------------------------------------------------------- /src/models/VehicleMod.ts: -------------------------------------------------------------------------------- 1 | import { Vehicle } from './Vehicle'; 2 | import { VehicleModType } from '../enums'; 3 | 4 | export class VehicleMod { 5 | private _owner: Vehicle; 6 | private _modType: VehicleModType; 7 | 8 | constructor(owner: Vehicle, modType: VehicleModType) { 9 | this._owner = owner; 10 | this._modType = modType; 11 | } 12 | 13 | public get ModType(): VehicleModType { 14 | return this._modType; 15 | } 16 | 17 | public set ModType(modType: VehicleModType) { 18 | this._modType = modType; 19 | } 20 | 21 | public get Index(): number { 22 | return GetVehicleMod(this._owner.Handle, this.ModType); 23 | } 24 | 25 | public set Index(value: number) { 26 | SetVehicleMod(this._owner.Handle, this.ModType, value, this.Variation); 27 | } 28 | 29 | public get Variation(): boolean { 30 | return GetVehicleModVariation(this._owner.Handle, this.ModType); 31 | } 32 | 33 | public set Variation(value: boolean) { 34 | SetVehicleMod(this._owner.Handle, this.ModType, this.Index, value); 35 | } 36 | 37 | public get ModCount(): number { 38 | return GetNumVehicleMods(this._owner.Handle, this.ModType); 39 | } 40 | 41 | public get Vehicle(): Vehicle { 42 | return this._owner; 43 | } 44 | 45 | public remove(): void { 46 | RemoveVehicleMod(this._owner.Handle, this.ModType); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/ui/LoadingPrompt.ts: -------------------------------------------------------------------------------- 1 | import { LoadingSpinnerType } from '../enums'; 2 | 3 | /** 4 | * Show and hide loading prompt on the bottom right of the screen. 5 | * 6 | * Example: 7 | * 8 | * ```typescript 9 | * import { LoadingPrompt } from '@nativewrappers/client/ui'; 10 | * 11 | * LoadingPrompt.show("Hello World"); 12 | * 13 | * setTimeout(() => { 14 | * LoadingPrompt.hide(); 15 | * }, 10000)' 16 | * ``` 17 | */ 18 | export abstract class LoadingPrompt { 19 | /** 20 | * Shows a loading prompt. 21 | * 22 | * @param loadingText Text to be displayed inside loading prompt. 23 | * @param spinnerType Type of spinner. 24 | */ 25 | public static show( 26 | loadingText = '', 27 | spinnerType: LoadingSpinnerType = LoadingSpinnerType.RegularClockwise, 28 | ): void { 29 | if (this.IsActive) { 30 | this.hide(); 31 | } 32 | 33 | if (loadingText === '') { 34 | BeginTextCommandBusyString(''); 35 | } else { 36 | BeginTextCommandBusyString('STRING'); 37 | AddTextComponentSubstringPlayerName(loadingText); 38 | } 39 | 40 | EndTextCommandBusyString(Number(spinnerType)); 41 | } 42 | 43 | public static hide(): void { 44 | if (this.IsActive) { 45 | RemoveLoadingPrompt(); 46 | } 47 | } 48 | 49 | public static get IsActive(): boolean { 50 | return IsLoadingPromptBeingDisplayed(); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Checkpoint.ts: -------------------------------------------------------------------------------- 1 | import { CheckpointIcon } from './enums'; 2 | import { Vector3 } from './utils'; 3 | 4 | export class Checkpoint { 5 | private handle: number; 6 | private position: Vector3 = new Vector3(0, 0, 0); 7 | private targetPosition: Vector3 = new Vector3(0, 0, 0); 8 | private icon: CheckpointIcon = CheckpointIcon.Empty; 9 | private radius = 0; 10 | 11 | constructor(handle: number) { 12 | this.handle = handle; 13 | } 14 | 15 | public get Position(): Vector3 { 16 | return this.position; 17 | } 18 | 19 | public set Position(position: Vector3) { 20 | this.position = position; 21 | } 22 | 23 | public get TargetPosition(): Vector3 { 24 | return this.targetPosition; 25 | } 26 | 27 | public set TargetPosition(targetPosition: Vector3) { 28 | this.targetPosition = targetPosition; 29 | } 30 | 31 | public get Icon(): CheckpointIcon { 32 | return this.icon; 33 | } 34 | 35 | public set Icon(icon: CheckpointIcon) { 36 | this.icon = icon; 37 | } 38 | 39 | // TODO 40 | // public get CustomIcon(): CheckpointIcon { 41 | // return this.icon; 42 | // } 43 | 44 | // public set CustomIcon(icon: CheckpointIcon) { 45 | // this.icon = icon; 46 | // } 47 | 48 | public get Radius(): number { 49 | return this.radius; 50 | } 51 | 52 | public set Radius(radius: number) { 53 | this.radius = radius; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/enums/Checkpoint.ts: -------------------------------------------------------------------------------- 1 | export enum CheckpointIcon { 2 | CylinderSingleArrow, 3 | CylinderDoubleArrow, 4 | CylinderTripleArrow, 5 | CylinderCycleArrow, 6 | CylinderCheckerboard, 7 | CylinderSingleArrow2, 8 | CylinderDoubleArrow2, 9 | CylinderTripleArrow2, 10 | CylinderCycleArrow2, 11 | CylinderCheckerboard2, 12 | RingSingleArrow, 13 | RingDoubleArrow, 14 | RingTripleArrow, 15 | RingCycleArrow, 16 | RingCheckerboard, 17 | SingleArrow, 18 | DoubleArrow, 19 | TripleArrow, 20 | CycleArrow, 21 | Checkerboard, 22 | CylinderSingleArrow3, 23 | CylinderDoubleArrow3, 24 | CylinderTripleArrow3, 25 | CylinderCycleArrow3, 26 | CylinderCheckerboard3, 27 | CylinderSingleArrow4, 28 | CylinderDoubleArrow4, 29 | CylinderTripleArrow4, 30 | CylinderCycleArrow4, 31 | CylinderCheckerboard4, 32 | CylinderSingleArrow5, 33 | CylinderDoubleArrow5, 34 | CylinderTripleArrow5, 35 | CylinderCycleArrow5, 36 | CylinderCheckerboard5, 37 | RingPlaneUp, 38 | RingPlaneLeft, 39 | RingPlaneRight, 40 | RingPlaneDown, 41 | Empty, 42 | Ring, 43 | Empty2, 44 | // CylinderCustomShape, 45 | // CylinderCustomShape2, 46 | // CylinderCustomShape3, 47 | Cyclinder = 45, 48 | Cyclinder2, 49 | Cyclinder3, 50 | } 51 | 52 | export enum CheckpointCustomIconStyle { 53 | Number, 54 | SingleArrow, 55 | DoubleArrow, 56 | TripleArrow, 57 | Ring, 58 | CycleArrow, 59 | Ring2, 60 | RingPointer, 61 | SegmentedRing, 62 | Sphere, 63 | Dollar, 64 | QuintupleLines, 65 | BeastIcon, 66 | } 67 | -------------------------------------------------------------------------------- /src/ui/Rectangle.ts: -------------------------------------------------------------------------------- 1 | import { Color, Point, Size } from '../utils'; 2 | import { IDrawable, Screen } from './'; 3 | 4 | export class Rectangle implements IDrawable { 5 | public pos: Point; 6 | public size: Size; 7 | public color: Color; 8 | 9 | constructor(pos: Point, size: Size, color: Color) { 10 | this.pos = pos; 11 | this.size = size; 12 | this.color = color; 13 | } 14 | 15 | public draw(offset?: Size, resolution?: Size): void; 16 | public draw(pos: Point, size: Size, color: Color, resolution?: Size): void; 17 | public draw(arg1?: Point | Size, arg2?: Size, color?: Color, resolution?: Size): void { 18 | resolution = color === undefined ? arg2 : resolution; 19 | resolution = resolution || new Size(Screen.ScaledWidth, Screen.Height); 20 | 21 | if (color === undefined) { 22 | if (arg1 && arg1 instanceof Size) { 23 | arg1 = new Point(this.pos.X + arg1.width, this.pos.Y + arg1.height); 24 | } else { 25 | arg1 = this.pos; 26 | } 27 | arg2 = this.size; 28 | } else { 29 | if (!arg1) { 30 | arg1 = this.pos; 31 | } else { 32 | arg1 = arg1 as Point; 33 | } 34 | arg2 = arg2 || this.size; 35 | } 36 | 37 | color = color || this.color; 38 | 39 | const w = arg2.width / resolution.width; 40 | const h = arg2.height / resolution.height; 41 | const x = arg1.X / resolution.width + w * 0.5; 42 | const y = arg1.Y / resolution.height + h * 0.5; 43 | 44 | DrawRect(x, y, w, h, color.r, color.g, color.b, color.a); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/TaskSequence.ts: -------------------------------------------------------------------------------- 1 | import { Ped } from './models/Ped'; 2 | import { Tasks } from './Tasks'; 3 | 4 | export class TaskSequence { 5 | private static nullPed: Ped; 6 | private handle = 0; 7 | private isClosed: boolean; 8 | private count: number; 9 | 10 | constructor(handle?: number) { 11 | handle === undefined ? this.create() : (this.handle = handle); 12 | 13 | if (!TaskSequence.nullPed) { 14 | TaskSequence.nullPed = new Ped(0); 15 | } 16 | 17 | this.isClosed = false; 18 | this.count = 0; 19 | } 20 | 21 | private create(): void { 22 | // Docs generate this as 'void' even though it returns a number 23 | this.handle = OpenSequenceTask(0) as unknown as number; 24 | } 25 | 26 | public dispose(): void { 27 | ClearSequenceTask(this.handle); 28 | this.handle = 0; 29 | } 30 | 31 | public close(repeat = false): void { 32 | if (this.isClosed) return; 33 | 34 | SetSequenceToRepeat(this.handle, repeat); 35 | CloseSequenceTask(this.handle); 36 | 37 | this.isClosed = true; 38 | } 39 | 40 | public get Handle(): number { 41 | return this.handle; 42 | } 43 | 44 | public get AddTask(): Tasks | null | undefined { 45 | if (this.isClosed) { 46 | throw new Error("You can't add tasks to a closed sequence!"); 47 | } 48 | 49 | this.count += 1; 50 | return TaskSequence.nullPed?.Task; 51 | } 52 | 53 | public get IsClosed(): boolean { 54 | return this.isClosed; 55 | } 56 | 57 | public get Count(): number { 58 | return this.count; 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/ui/Hud.ts: -------------------------------------------------------------------------------- 1 | import { CursorSprite, HudComponent } from '../enums'; 2 | import { Point } from '../utils'; 3 | 4 | export abstract class Hud { 5 | public static isComponentActive(component: HudComponent): boolean { 6 | return IsHudComponentActive(Number(component)); 7 | } 8 | 9 | public static showComponentThisFrame(component: HudComponent): void { 10 | ShowHudComponentThisFrame(Number(component)); 11 | } 12 | 13 | public static hideComponentThisFrame(component: HudComponent): void { 14 | HideHudComponentThisFrame(Number(component)); 15 | } 16 | 17 | public static showCursorThisFrame(): void { 18 | ShowCursorThisFrame(); 19 | } 20 | 21 | public static set CursorPosition(position: Point) { 22 | SetCursorLocation(position.X, position.Y); 23 | } 24 | 25 | public static get CursorSprite(): CursorSprite { 26 | return CursorSprite.DownArrow; 27 | } 28 | 29 | public static set CursorSprite(sprite: CursorSprite) { 30 | SetCursorSprite(Number(sprite)); 31 | } 32 | 33 | public static get IsVisible(): boolean { 34 | return !(IsHudHidden() || !IsHudPreferenceSwitchedOn()); 35 | } 36 | 37 | public static set IsVisible(toggle: boolean) { 38 | DisplayHud(toggle); 39 | } 40 | 41 | public static get IsRadarVisible(): boolean { 42 | return !(IsRadarHidden() || IsRadarPreferenceSwitchedOn()); 43 | } 44 | 45 | public static set IsRadarVisible(toggle: boolean) { 46 | DisplayRadar(toggle); 47 | } 48 | 49 | public static set RadarZoom(zoomLevel: number) { 50 | SetRadarZoom(zoomLevel); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/ui/menu/MenuSettings.ts: -------------------------------------------------------------------------------- 1 | import { InputMode } from '../../index'; 2 | import { Control } from '../../enums'; 3 | 4 | export class MenuSettings { 5 | public scaleWithSafezone = true; 6 | public resetCursorOnOpen = true; 7 | public mouseControlsEnabled = true; 8 | public mouseEdgeEnabled = true; 9 | public controlDisablingEnabled = true; 10 | public audio = { 11 | library: 'HUD_FRONTEND_DEFAULT_SOUNDSET', 12 | upDown: 'NAV_UP_DOWN', 13 | leftRight: 'NAV_LEFT_RIGHT', 14 | select: 'SELECT', 15 | back: 'BACK', 16 | error: 'ERROR', 17 | }; 18 | public enabledControls = { 19 | [InputMode.GamePad]: [Control.LookUpDown, Control.LookLeftRight, Control.Aim, Control.Attack], 20 | [InputMode.MouseAndKeyboard]: [ 21 | Control.FrontendAccept, 22 | Control.FrontendAxisX, 23 | Control.FrontendAxisY, 24 | Control.FrontendDown, 25 | Control.FrontendUp, 26 | Control.FrontendLeft, 27 | Control.FrontendRight, 28 | Control.FrontendCancel, 29 | Control.FrontendSelect, 30 | Control.CursorScrollDown, 31 | Control.CursorScrollUp, 32 | Control.CursorX, 33 | Control.CursorY, 34 | Control.MoveUpDown, 35 | Control.MoveLeftRight, 36 | Control.Sprint, 37 | Control.Jump, 38 | Control.Enter, 39 | Control.VehicleExit, 40 | Control.VehicleAccelerate, 41 | Control.VehicleBrake, 42 | Control.VehicleHandbrake, 43 | Control.VehicleMoveLeftRight, 44 | Control.VehicleFlyYawLeft, 45 | Control.VehicleFlyYawRight, 46 | Control.FlyLeftRight, 47 | Control.FlyUpDown, 48 | ], 49 | }; 50 | } 51 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Remco Troost - https://www.d0p3t.nl 2 | 3 | Copyright © 2019 4 | 5 | ----- 6 | 7 | THIS PROJECT USES A CUSTOM LICENSE. MAKE SURE TO READ IT BEFORE THINKING ABOUT DOING ANYTHING WITH FIVEM-JS. 8 | 9 | ----- 10 | 11 | - YOU ARE ALLOWED TO USE FIVEM-JS ON AS MANY SERVERS AS YOU WANT. 12 | - _YOU ARE ALSO ALLOWED TO EDIT THIS RESOURCE TO ADD/CHANGE/REMOVE WHATEVER YOU WANT._ (see the exception to this rule in the "credits" section below) 13 | - **YOU ARE HOWEVER _NOT_ ALLOWED TO RE-RELEASE (EDITED OR NON-EDITED) VERSIONS OF THIS NPM PACKAGE WITHOUT WRITTEN PERMISSIONS BY MYSELF (REMCO TROOST / D0P3T). FOR ADDED FEATURES/CHANGES, FEEL FREE TO CREATE A FORK & CREATE A PULL REQUEST.** 14 | 15 | ---- 16 | 17 | **Credits** 18 | 19 | Never should you change the credits (for example in the source code comment section) to claim this resource to be your own. 90% of the users will recognize this npm package as being fivem-js, so changing the name of it and removing the credits section, is just useless. You're just being extremely rude and nodoby likes you anymore if they find out you're a big fat liar. 20 | 21 | ----- 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /src/ui/menu/items/panels/UIMenuStatisticsPanelItem.ts: -------------------------------------------------------------------------------- 1 | import { Color, Crypto, Point, Size } from '../../../../utils'; 2 | import { Rectangle, Text } from '../../../'; 3 | import { Alignment, Font } from '../../../../enums'; 4 | 5 | export class UIMenuStatisticsPanelItem { 6 | public readonly id: string = Crypto.uuidv4(); 7 | 8 | public readonly text: Text; 9 | public readonly activeBar: Rectangle; 10 | public readonly backgroundBar: Rectangle; 11 | public readonly divider: Rectangle[] = []; 12 | 13 | constructor(name: string, percentage = 0) { 14 | this.text = new Text('', new Point(), 0.35, Color.white, Font.ChaletLondon, Alignment.Left); 15 | this.backgroundBar = new Rectangle( 16 | new Point(), 17 | new Size(200, 10), 18 | Color.fromArgb(100, 87, 87, 87), 19 | ); 20 | this.activeBar = new Rectangle(new Point(), new Size(0, 10), Color.white); 21 | for (let i = 1; i <= 4; i++) { 22 | this.divider.push(new Rectangle(new Point(), new Size(2, 10), Color.black)); 23 | } 24 | this.Name = name; 25 | this.Percentage = percentage; 26 | } 27 | 28 | public get Name(): string { 29 | return this.text.caption; 30 | } 31 | 32 | public set Name(value: string) { 33 | this.text.caption = value ? value.trim() : ''; 34 | } 35 | 36 | public get Percentage(): number { 37 | return this.activeBar.size.width / 200; 38 | } 39 | 40 | public set Percentage(value: number) { 41 | value = value || 0; 42 | value = Math.round(value * 100) / 100; 43 | value = value < 0 ? 0 : value > 1 ? 1 : value; 44 | this.activeBar.size.width = value * 200; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/ui/menu/items/panels/AbstractUIMenuPanel.ts: -------------------------------------------------------------------------------- 1 | import { UIMenuItem } from '../'; 2 | import { Crypto } from '../../../../utils'; 3 | import { Rectangle, Sprite } from '../../../'; 4 | import { Menu } from '../../'; 5 | 6 | export abstract class AbstractUIMenuPanel { 7 | public readonly id: string = Crypto.uuidv4(); 8 | 9 | protected parentItem: UIMenuItem | undefined; 10 | protected enabled = true; 11 | 12 | protected readonly background: Sprite | Rectangle | undefined; 13 | 14 | public get ParentMenu(): Menu | undefined { 15 | return this.parentItem ? this.parentItem.parent : undefined; 16 | } 17 | 18 | public get ParentItem(): UIMenuItem | undefined { 19 | return this.parentItem ?? undefined; 20 | } 21 | 22 | public set ParentItem(value: UIMenuItem | undefined) { 23 | this.parentItem = value; 24 | } 25 | 26 | public get Enabled(): boolean { 27 | return this.enabled; 28 | } 29 | 30 | public set Enabled(value: boolean) { 31 | this.enabled = value; 32 | } 33 | 34 | public get Height(): number { 35 | return this.background ? this.background.size.height : 0; 36 | } 37 | 38 | public setVerticalPosition(y: number): void { 39 | if (this.background) this.background.pos.Y = y; 40 | } 41 | 42 | public draw(): void { 43 | if (this.background) { 44 | this.background.size.width = 431 + (this.ParentMenu ? this.ParentMenu.WidthOffset : 0); 45 | this.background.pos.X = this.parentItem ? this.parentItem.offset.X : 0; 46 | if (this.background instanceof Sprite) { 47 | this.background.draw(Menu.screenResolution); 48 | } else { 49 | this.background.draw(undefined, Menu.screenResolution); 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/NetworkedScene.ts: -------------------------------------------------------------------------------- 1 | import type { Entity, Ped, Vector3 } from '.'; 2 | export class NetworkedScene { 3 | private scene; 4 | constructor( 5 | pos: Vector3, 6 | rot: Vector3, 7 | rotationOrder: number, 8 | holdLastFrame: boolean, 9 | looped: boolean, 10 | sceneHash: number, 11 | animTime: number, 12 | animSpeed: number, 13 | ) { 14 | this.scene = NetworkCreateSynchronisedScene( 15 | pos.x, 16 | pos.y, 17 | pos.z, 18 | rot.x, 19 | rot.y, 20 | rot.z, 21 | rotationOrder, 22 | holdLastFrame, 23 | looped, 24 | sceneHash, 25 | animTime + 0.0, 26 | animSpeed + 0.0, 27 | ); 28 | } 29 | 30 | addPed( 31 | ped: Ped, 32 | animDict: string, 33 | animName: string, 34 | blendInSpeed: number, 35 | blendOutSpeed: number, 36 | duration: number, 37 | flag: number, 38 | playbackRate: number, 39 | p9: number, 40 | ): void { 41 | NetworkAddPedToSynchronisedScene( 42 | ped.Handle, 43 | this.scene, 44 | animDict, 45 | animName, 46 | blendInSpeed, 47 | blendOutSpeed, 48 | duration, 49 | flag, 50 | playbackRate, 51 | p9, 52 | ); 53 | } 54 | 55 | addEntity( 56 | entity: Entity, 57 | animDict: string, 58 | animName: string, 59 | speed: number, 60 | speedMultiplier: number, 61 | flag: number, 62 | ): void { 63 | NetworkAddEntityToSynchronisedScene( 64 | entity.Handle, 65 | this.scene, 66 | animDict, 67 | animName, 68 | speed, 69 | speedMultiplier, 70 | flag, 71 | ); 72 | } 73 | 74 | start(): void { 75 | NetworkStartSynchronisedScene(this.scene); 76 | } 77 | 78 | stop(): void { 79 | NetworkStopSynchronisedScene(this.scene); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@nativewrappers/client", 3 | "version": "1.7.27", 4 | "description": "Javascript/Typescript wrapper for the FiveM natives", 5 | "sideEffects": [ 6 | "./src/models/**" 7 | ], 8 | "main": "lib/index.js", 9 | "module": "lib/index.js", 10 | "types": "lib/index.d.ts", 11 | "scripts": { 12 | "build": "tsc", 13 | "watch": "tsc --watch", 14 | "ci": "pnpm run lint && pnpm run build", 15 | "lint": "eslint . --ext .ts", 16 | "lint-fix": "eslint --fix . --ext .ts", 17 | "typedoc": "typedoc", 18 | "docs": "npm run typedoc -- --options typedoc.json" 19 | }, 20 | "repository": { 21 | "type": "git", 22 | "url": "https://github.com/AvarianKnight/native-wrappers-client.git" 23 | }, 24 | "keywords": [ 25 | "fivem", 26 | "wrapper", 27 | "javascript", 28 | "typescript", 29 | "citizenfx" 30 | ], 31 | "files": [ 32 | "lib/**/*" 33 | ], 34 | "author": "Remco Troost ", 35 | "license": "MIT", 36 | "bugs": { 37 | "url": "https://github.com/AvarianKnight/native-wrappers-client/issues" 38 | }, 39 | "homepage": "https://fivemjs.avarian.dev/", 40 | "devDependencies": { 41 | "@citizenfx/client": "^2.0.5181-1", 42 | "@typescript-eslint/eslint-plugin": "^4.33.0", 43 | "@typescript-eslint/parser": "^4.33.0", 44 | "eslint": "^7.32.0", 45 | "eslint-config-prettier": "^8.3.0", 46 | "eslint-plugin-prettier": "^3.4.1", 47 | "prettier": "^2.5.1", 48 | "typedoc": "^0.22.10", 49 | "typedoc-fivemjs-theme": "^0.2.7", 50 | "typescript": "^4.6.4" 51 | }, 52 | "directories": { 53 | "doc": "docs", 54 | "example": "examples", 55 | "lib": "lib" 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | We welcome contributions and assistance! If you want to know where to start, check out our [Github Projects sorted by name](https://github.com/avarianknight/native-wrappers-client/projects?query=is%3Aopen+sort%3Aname-asc). 4 | 5 | If you want to add a new feature, note that we strive to support the FiveM OneSync system, so keep that in mind when submitting feature requests. 6 | 7 | ## Development 8 | 9 | To get setup for development, refer to [DEVELOPMENT.md](./DEVELOPMENT.md) 10 | 11 | ## Issues 12 | 13 | We use GitHub issues to track public bugs and requests. Please ensure your bug description is clear and has sufficient instructions to be able to reproduce the issue. THe best way is to provide an example resource in JS that uses any of the native-wrappers-client features directly. 14 | 15 | ## Pull Requests 16 | 17 | All active development of this project happens on GitHub. We actively welcome your [pull requests](https://help.github.com/articles/creating-a-pull-request). 18 | 19 | We require that all pull requests are made in the development branch. Please beware of that when opening a new PR. 20 | 21 | ## Commit Message Conventions 22 | 23 | We don't have any strict commit message rules, but we encourage you to keep your commit messages short and descriptive. 24 | 25 | ``` 26 | docs: Scaleform + LoadingPrompt 27 | ``` 28 | ``` 29 | Added bone collections and Camera PointAt functions 30 | ``` 31 | 32 | Both these commit messages are descriptive, short and to the point. 33 | 34 | 35 | ## License 36 | 37 | By contributing to native-wrappers-client, you agree that your contributions will be licensed under the [LICENSE](./LICENSE) file in the project root directory. -------------------------------------------------------------------------------- /src/models/VehicleDoor.ts: -------------------------------------------------------------------------------- 1 | import { Vehicle } from './Vehicle'; 2 | import { VehicleDoorIndex } from '../enums'; 3 | 4 | export class VehicleDoor { 5 | private _owner: Vehicle; 6 | private _index: VehicleDoorIndex; 7 | 8 | constructor(owner: Vehicle, index: VehicleDoorIndex) { 9 | this._owner = owner; 10 | this._index = index; 11 | } 12 | 13 | public get Index(): VehicleDoorIndex { 14 | return this._index; 15 | } 16 | 17 | public set Index(index: VehicleDoorIndex) { 18 | this._index = index; 19 | } 20 | 21 | public get AngleRatio(): number { 22 | return GetVehicleDoorAngleRatio(this._owner.Handle, this.Index); 23 | } 24 | 25 | public set AngleRatio(value: number) { 26 | SetVehicleDoorControl(this._owner.Handle, this.Index, 1, value); 27 | } 28 | 29 | public set CanBeBroken(value: boolean) { 30 | SetVehicleDoorBreakable(this._owner.Handle, this.Index, value); 31 | } 32 | 33 | public get IsOpen(): boolean { 34 | return this.AngleRatio > 0; 35 | } 36 | 37 | public get IsFullyOpen(): boolean { 38 | return IsVehicleDoorFullyOpen(this._owner.Handle, this.Index); 39 | } 40 | 41 | public get IsBroken(): boolean { 42 | return IsVehicleDoorDamaged(this._owner.Handle, this.Index); 43 | } 44 | 45 | public get Vehicle(): Vehicle { 46 | return this._owner; 47 | } 48 | 49 | public open(loose = false, instantly = false): void { 50 | SetVehicleDoorOpen(this._owner.Handle, this.Index, loose, instantly); 51 | } 52 | 53 | public close(instantly = false): void { 54 | SetVehicleDoorShut(this._owner.Handle, this.Index, instantly); 55 | } 56 | 57 | public break(stayInTheWorld = true): void { 58 | SetVehicleDoorBroken(this._owner.Handle, this.Index, stayInTheWorld); 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/ui/Fading.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Static class for screen fading 3 | */ 4 | export abstract class Fading { 5 | /** 6 | * Gets whether the screen is faded in 7 | * 8 | * @returns True or false 9 | */ 10 | public static get IsFadedIn(): boolean { 11 | return IsScreenFadedIn(); 12 | } 13 | 14 | /** 15 | * Gets whether the screen is faded out 16 | * 17 | * @returns True or false 18 | */ 19 | public static get IsFadedOut(): boolean { 20 | return IsScreenFadedOut(); 21 | } 22 | 23 | /** 24 | * Gets whether the screen is currently fading in 25 | * 26 | * @returns True or false 27 | */ 28 | public static get IsFadingIn(): boolean { 29 | return IsScreenFadingIn(); 30 | } 31 | 32 | /** 33 | * Gets whether the screen is currently fading out 34 | * 35 | * @returns True or false 36 | */ 37 | public static get IsFadingOut(): boolean { 38 | return IsScreenFadingOut(); 39 | } 40 | 41 | /** 42 | * Fade in the screen for a certain duration. 43 | * 44 | * @param duration Time to fade in 45 | */ 46 | public static fadeIn(duration: number): Promise { 47 | return new Promise(resolve => { 48 | DoScreenFadeIn(duration); 49 | 50 | const interval = setInterval(() => { 51 | if (this.IsFadedIn) { 52 | clearInterval(interval); 53 | resolve(); 54 | } 55 | }, 0); 56 | }); 57 | } 58 | 59 | /** 60 | * Fade out the screen for a certain duration. 61 | * 62 | * @param duration Time to fade out 63 | */ 64 | public static fadeOut(duration: number): Promise { 65 | return new Promise(resolve => { 66 | DoScreenFadeOut(duration); 67 | 68 | const interval = setInterval(() => { 69 | if (this.IsFadedOut) { 70 | clearInterval(interval); 71 | resolve(); 72 | } 73 | }, 0); 74 | }); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/enums/ScreenEffect.ts: -------------------------------------------------------------------------------- 1 | export enum ScreenEffect { 2 | SwitchHudIn, 3 | SwitchHudOut, 4 | FocusIn, 5 | FocusOut, 6 | MinigameEndNeutral, 7 | MinigameEndTrevor, 8 | MinigameEndFranklin, 9 | MinigameEndMichael, 10 | MinigameTransitionOut, 11 | MinigameTransitionIn, 12 | SwitchShortNeutralIn, 13 | SwitchShortFranklinIn, 14 | SwitchShortTrevorIn, 15 | SwitchShortMichaelIn, 16 | SwitchOpenMichaelIn, 17 | SwitchOpenFranklinIn, 18 | SwitchOpenTrevorIn, 19 | SwitchHudMichaelOut, 20 | SwitchHudFranklinOut, 21 | SwitchHudTrevorOut, 22 | SwitchShortFranklinMid, 23 | SwitchShortMichaelMid, 24 | SwitchShortTrevorMid, 25 | DeathFailOut, 26 | CamPushInNeutral, 27 | CamPushInFranklin, 28 | CamPushInMichael, 29 | CamPushInTrevor, 30 | SwitchSceneFranklin, 31 | SwitchSceneTrevor, 32 | SwitchSceneMichael, 33 | SwitchSceneNeutral, 34 | MpCelebWin, 35 | MpCelebWinOut, 36 | MpCelebLose, 37 | MpCelebLoseOut, 38 | DeathFailNeutralIn, 39 | DeathFailMpDark, 40 | DeathFailMpIn, 41 | MpCelebPreloadFade, 42 | PeyoteEndOut, 43 | PeyoteEndIn, 44 | PeyoteIn, 45 | PeyoteOut, 46 | MpRaceCrash, 47 | SuccessFranklin, 48 | SuccessTrevor, 49 | SuccessMichael, 50 | DrugsMichaelAliensFightIn, 51 | DrugsMichaelAliensFight, 52 | DrugsMichaelAliensFightOut, 53 | DrugsTrevorClownsFightIn, 54 | DrugsTrevorClownsFight, 55 | DrugsTrevorClownsFightOut, 56 | HeistCelebPass, 57 | HeistCelebPassBw, 58 | HeistCelebEnd, 59 | HeistCelebToast, 60 | MenuMgHeistIn, 61 | MenuMgTournamentIn, 62 | MenuMgSelectionIn, 63 | ChopVision, 64 | DmtFlightIntro, 65 | DmtFlight, 66 | DrugsDrivingIn, 67 | DrugsDrivingOut, 68 | SwitchOpenNeutralFib5, 69 | HeistLocate, 70 | MpJobLoad, 71 | RaceTurbo, 72 | MpIntroLogo, 73 | HeistTripSkipFade, 74 | MenuMgHeistOut, 75 | MpCoronaSwitch, 76 | MenuMgSelectionTint, 77 | SuccessNeutral, 78 | ExplosionJosh3, 79 | SniperOverlay, 80 | RampageOut, 81 | Rampage, 82 | DontTazemeBro, 83 | } 84 | -------------------------------------------------------------------------------- /src/weapon/WeaponAsset.ts: -------------------------------------------------------------------------------- 1 | import { WeaponHash } from '../hashes'; 2 | import { Weapon } from './Weapon'; 3 | import { Game } from '../Game'; 4 | import { Wait } from '../utils'; 5 | 6 | /** 7 | * weapon asset 8 | * 9 | */ 10 | export class WeaponAsset { 11 | private readonly hash: WeaponHash; 12 | 13 | constructor(hash: WeaponHash) { 14 | this.hash = hash; 15 | } 16 | 17 | /** 18 | * get weapon hash 19 | * 20 | * @constructor 21 | */ 22 | public get Hash(): WeaponHash { 23 | return this.hash; 24 | } 25 | 26 | /** 27 | * check weapon is valid 28 | * 29 | * @constructor 30 | */ 31 | public get IsValid(): boolean { 32 | return IsWeaponValid(this.hash); 33 | } 34 | 35 | /** 36 | * check weapon assets is loaded 37 | * 38 | * @constructor 39 | */ 40 | public get IsLoaded(): boolean { 41 | return HasWeaponAssetLoaded(this.hash); 42 | } 43 | 44 | /** 45 | * request weapon asset 46 | * 47 | */ 48 | public request(): void { 49 | RequestWeaponAsset(this.hash, 31, 0); 50 | } 51 | 52 | /** 53 | * request weapon asset async 54 | * 55 | * @param timeout 56 | */ 57 | public async requestAsync(timeout: number): Promise { 58 | this.request(); 59 | 60 | const start = GetGameTimer(); 61 | 62 | while (!this.IsLoaded) { 63 | await Wait(100); 64 | 65 | const now = GetGameTimer(); 66 | if (now - start >= timeout) { 67 | return false; 68 | } 69 | } 70 | 71 | return true; 72 | } 73 | 74 | /** 75 | * unload weapon asset 76 | * 77 | */ 78 | public dismiss(): void { 79 | RemoveWeaponAsset(this.hash); 80 | } 81 | 82 | /** 83 | * get weapon display name / label 84 | * 85 | * @constructor 86 | */ 87 | public get DisplayName(): string { 88 | return Weapon.getDisplayNameFromHash(this.hash); 89 | } 90 | 91 | /** 92 | * get weapon localized name 93 | * 94 | * @constructor 95 | */ 96 | public get LocalizedName(): string { 97 | return Game.getGXTEntry(this.DisplayName); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/enums/index.ts: -------------------------------------------------------------------------------- 1 | export { Alignment } from './Alignment'; 2 | export { AnimationFlags } from './AnimationFlags'; 3 | export { AudioFlag } from './AudioFlag'; 4 | export { BadgeStyle } from './BadgeStyle'; 5 | export { BlipColor, BlipSprite } from './Blip'; 6 | export { Bone } from './Bone'; 7 | export { CameraShake } from './CameraShake'; 8 | export { CheckboxStyle } from './CheckboxStyle'; 9 | export { CheckpointCustomIconStyle, CheckpointIcon } from './Checkpoint'; 10 | export { CloudHat } from './CloudHat'; 11 | export { Control } from './Control'; 12 | export { CursorSprite } from './CursorSprite'; 13 | export { DrivingStyle, VehicleDrivingFlags } from './Driving'; 14 | export { ExplosionType } from './ExplosionType'; 15 | export { FiringPattern } from './FiringPattern'; 16 | export { Font } from './Font'; 17 | export { ForceType } from './ForceType'; 18 | export { Gender } from './Gender'; 19 | export { HelmetType } from './HelmetType'; 20 | export { HudColor } from './HudColor'; 21 | export { HudComponent } from './HudComponent'; 22 | export { InputMode } from './InputMode'; 23 | export { IntersectOptions } from './IntersectOptions'; 24 | export { InvertAxis, InvertAxisFlags } from './InvertAxis'; 25 | export { Language } from './Language'; 26 | export { LeaveVehicleFlags } from './LeaveVehicleFlags'; 27 | export { LoadingSpinnerType } from './LoadingSpinnerType'; 28 | export { MarkerType } from './MarkerType'; 29 | export { MenuAlignment } from './MenuAlignment'; 30 | export { NotificationType } from './NotificationType'; 31 | export { ParachuteLandingType, ParachuteState } from './Parachute'; 32 | export { RadioStation } from './RadioStation'; 33 | export { RagdollType } from './RagdollType'; 34 | export { Relationship } from './Relationship'; 35 | export { RopeType } from './RopeType'; 36 | export { ScreenEffect } from './ScreenEffect'; 37 | export { SpeechModifier } from './SpeechModifier'; 38 | export * from './Vehicle'; 39 | export { Weather } from './Weather'; 40 | export { ZoneID } from './ZoneID'; 41 | export { PickupType } from './PickupType'; 42 | export { CameraTypes } from './CameraTypes'; 43 | -------------------------------------------------------------------------------- /src/models/VehicleWheelCollection.ts: -------------------------------------------------------------------------------- 1 | import { Vehicle } from './Vehicle'; 2 | import { VehicleWheel } from './VehicleWheel'; 3 | import { VehicleWheelIndex } from '../enums'; 4 | 5 | export class VehicleWheelCollection { 6 | private _owner: Vehicle; 7 | private readonly _vehicleWheels: Map = new Map(); 8 | 9 | constructor(owner: Vehicle) { 10 | this._owner = owner; 11 | } 12 | 13 | public getWheel(index: VehicleWheelIndex): VehicleWheel | undefined { 14 | if (!this._vehicleWheels.has(index)) { 15 | this._vehicleWheels.set(index, new VehicleWheel(this._owner, index)); 16 | } 17 | return this._vehicleWheels.get(index); 18 | } 19 | 20 | public getAllWheels(): (VehicleWheel | null | undefined)[] { 21 | return Object.keys(VehicleWheelIndex) 22 | .filter(key => !isNaN(Number(key))) 23 | .map(key => { 24 | const index = Number(key); 25 | if (this.hasWheel(index)) { 26 | return this.getWheel(index); 27 | } 28 | return null; 29 | }) 30 | .filter(w => w); 31 | } 32 | 33 | public burstAllWheels(): void { 34 | this.getAllWheels().forEach(wheel => { 35 | wheel?.burst(); 36 | }); 37 | } 38 | 39 | public fixAllWheels(): void { 40 | this.getAllWheels().forEach(wheel => { 41 | wheel?.fix(); 42 | }); 43 | } 44 | 45 | public hasWheel(wheel: VehicleWheelIndex): boolean { 46 | if (this._owner.Bones === undefined) return false; 47 | switch (wheel) { 48 | case VehicleWheelIndex.FrontLeftWheel: 49 | return this._owner.Bones.hasBone('wheel_lf'); 50 | case VehicleWheelIndex.FrontRightWheel: 51 | return this._owner.Bones.hasBone('wheel_rf'); 52 | case VehicleWheelIndex.MidLeftWheel: 53 | return this._owner.Bones.hasBone('wheel_lm'); 54 | case VehicleWheelIndex.MidRightWheel: 55 | return this._owner.Bones.hasBone('wheel_rm'); 56 | case VehicleWheelIndex.RearLeftWheel: 57 | return this._owner.Bones.hasBone('wheel_lr'); 58 | case VehicleWheelIndex.RearRightWheel: 59 | return this._owner.Bones.hasBone('wheel_rr'); 60 | default: 61 | return false; 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/models/VehicleWindowCollection.ts: -------------------------------------------------------------------------------- 1 | import { Vehicle } from './Vehicle'; 2 | import { VehicleWindowIndex } from '../enums'; 3 | import { VehicleWindow } from './VehicleWindow'; 4 | 5 | export class VehicleWindowCollection { 6 | private _owner: Vehicle; 7 | private readonly _vehicleWindows: Map = new Map< 8 | VehicleWindowIndex, 9 | VehicleWindow 10 | >(); 11 | 12 | constructor(owner: Vehicle) { 13 | this._owner = owner; 14 | } 15 | 16 | public getWindow(index: VehicleWindowIndex): VehicleWindow | undefined { 17 | if (!this._vehicleWindows.has(index)) { 18 | this._vehicleWindows.set(index, new VehicleWindow(this._owner, index)); 19 | } 20 | return this._vehicleWindows.get(index); 21 | } 22 | 23 | public getAllWindows(): (VehicleWindow | null | undefined)[] { 24 | return Object.keys(VehicleWindowIndex) 25 | .filter(key => !isNaN(Number(key))) 26 | .map(key => { 27 | const index = Number(key); 28 | if (this.hasWindow(index)) { 29 | return this.getWindow(index); 30 | } 31 | return null; 32 | }) 33 | .filter(w => w); 34 | } 35 | 36 | public get AreAllWindowsIntact(): boolean { 37 | return AreAllVehicleWindowsIntact(this._owner.Handle); 38 | } 39 | 40 | public rollDownAllWindows(): void { 41 | this.getAllWindows().forEach(window => { 42 | window?.rollDown(); 43 | }); 44 | } 45 | 46 | public rollUpAllWindows(): void { 47 | this.getAllWindows().forEach(window => { 48 | window?.rollUp(); 49 | }); 50 | } 51 | 52 | public hasWindow(window: VehicleWindowIndex): boolean { 53 | if (this._owner.Bones === undefined) return false; 54 | switch (window) { 55 | case VehicleWindowIndex.FrontLeftWindow: 56 | return this._owner.Bones.hasBone('window_lf'); 57 | case VehicleWindowIndex.FrontRightWindow: 58 | return this._owner.Bones.hasBone('window_rf'); 59 | case VehicleWindowIndex.BackLeftWindow: 60 | return this._owner.Bones.hasBone('window_lr'); 61 | case VehicleWindowIndex.BackRightWindow: 62 | return this._owner.Bones.hasBone('window_rr'); 63 | default: 64 | return false; 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/ui/InstructionalButtons.ts: -------------------------------------------------------------------------------- 1 | import { Scaleform } from './Scaleform'; 2 | import { IButton } from './interfaces/IButton'; 3 | 4 | /** 5 | * Draw native instructional buttons in the bottom left of the screen using scaleform 6 | * 7 | * Example: 8 | * 9 | * ```typescript 10 | * import { InstructionalButtons, Control } from '@nativewrappers/client'; 11 | * 12 | * const buttons = new InstructionalButtons([ 13 | * {controls: [Control.Context], label: "Interact with Bob"}, 14 | * {controls: [Control.Detonate], label: "Say hello to Alice"} 15 | * ]) 16 | * 17 | * setTick(() => { 18 | * buttons.draw() 19 | * }) 20 | * ``` 21 | */ 22 | export class InstructionalButtons { 23 | private scaleform: Scaleform; 24 | 25 | /** 26 | * Draws native instructional buttons 27 | * 28 | * @param buttons Array of instructional buttons to be drawn 29 | */ 30 | constructor(buttons: IButton[]) { 31 | this.scaleform = new Scaleform('INSTRUCTIONAL_BUTTONS'); 32 | this.scaleform.callFunction('CLEAR_ALL'); 33 | this.scaleform.callFunction('SET_CLEAR_SPACE', 200); 34 | 35 | buttons.forEach((button, index) => { 36 | this.pushButton(button, index); 37 | }); 38 | 39 | this.scaleform.callFunction('DRAW_INSTRUCTIONAL_BUTTONS'); 40 | this.scaleform.callFunction('SET_BACKGROUND_COLOUR', 0, 0, 0, 80); 41 | } 42 | 43 | private pushButton(button: IButton, index: number) { 44 | BeginScaleformMovieMethod(this.scaleform.Handle, 'SET_DATA_SLOT'); 45 | PushScaleformMovieFunctionParameterInt(index); 46 | // Looping backwards here since scaleform is using a stack so the first control ends up being the last 47 | // So looping backwards makes more sense here so that the controls are rendered in the order they're defined 48 | for (let i = button.controls.length - 1; i >= 0; i--) { 49 | PushScaleformMovieMethodParameterButtonName( 50 | GetControlInstructionalButton(2, button.controls[i], true), 51 | ); 52 | } 53 | PushScaleformMovieMethodParameterString(button.label); 54 | EndScaleformMovieMethod(); 55 | } 56 | 57 | /** 58 | * Renders the instructional button scaleform 59 | */ 60 | public async draw(): Promise { 61 | await this.scaleform.render2D(); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Events.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import { ClassTypes } from './enums/ClassTypes'; 3 | import { Ped } from './models/Ped'; 4 | import { Vector2 } from './utils/Vector2'; 5 | import { Vector3 } from './utils/Vector3'; 6 | import { Vector4 } from './utils/Vector4'; 7 | import { Player } from './models/Player'; 8 | import { Prop } from './models/Prop'; 9 | import { Vehicle } from './models/Vehicle'; 10 | import { Entity } from './models/Entity'; 11 | 12 | export type NetEvent = (...args: any[]) => void; 13 | 14 | const getClassFromArguments = (...args: any[]): any[] => { 15 | const newArgs: any[] = []; 16 | 17 | for (const arg of args) { 18 | switch (arg.type) { 19 | case ClassTypes.Vector2: { 20 | newArgs.push(Vector2.create(arg)); 21 | continue; 22 | } 23 | case ClassTypes.Vector3: { 24 | newArgs.push(Vector3.create(arg)); 25 | continue; 26 | } 27 | case ClassTypes.Vector4: { 28 | newArgs.push(Vector4.create(arg)); 29 | continue; 30 | } 31 | case ClassTypes.Ped: { 32 | newArgs.push(Ped.fromNetworkId(arg.handle)); 33 | continue; 34 | } 35 | case ClassTypes.Player: { 36 | newArgs.push(Player.fromServerId(arg.source)); 37 | continue; 38 | } 39 | case ClassTypes.Prop: { 40 | newArgs.push(Prop.fromNetworkId(arg.handle)); 41 | continue; 42 | } 43 | case ClassTypes.Vehicle: { 44 | newArgs.push(Vehicle.fromNetworkId(arg.netId)); 45 | continue; 46 | } 47 | case ClassTypes.Entity: { 48 | newArgs.push(Entity.fromNetworkId(arg.netId)); 49 | continue; 50 | } 51 | default: { 52 | newArgs.push(arg); 53 | } 54 | } 55 | } 56 | return newArgs; 57 | }; 58 | 59 | export class Events { 60 | /** 61 | * An onNet wrapper that properly converts the type into the correct type 62 | */ 63 | public onNet = (eventName: string, event: NetEvent) => { 64 | onNet(eventName, (...args: any[]) => { 65 | event(...getClassFromArguments(...args)); 66 | }); 67 | }; 68 | 69 | /** 70 | * An on wrapper that properly converts the classes 71 | */ 72 | public on = (eventName: string, event: NetEvent) => { 73 | on(eventName, (...args: any[]) => { 74 | event(...getClassFromArguments(...args)); 75 | }); 76 | }; 77 | } 78 | -------------------------------------------------------------------------------- /src/ui/menu/items/UIMenuCheckboxItem.ts: -------------------------------------------------------------------------------- 1 | import { Menu, Sprite } from '../../'; 2 | import { Color, LiteEvent, Point, Size } from '../../../utils'; 3 | import { UIMenuItem } from './'; 4 | import { CheckboxStyle } from '../../../enums'; 5 | 6 | export class UIMenuCheckboxItem extends UIMenuItem { 7 | public readonly checkboxChanged = new LiteEvent(); 8 | 9 | protected supportsRightBadge = false; 10 | protected supportsRightLabel = false; 11 | 12 | private _checked = false; 13 | private _style = CheckboxStyle.Tick; 14 | 15 | private readonly _checkboxSprite: Sprite; 16 | 17 | constructor( 18 | text: string, 19 | checked = false, 20 | description?: string, 21 | style: CheckboxStyle = CheckboxStyle.Tick, 22 | ) { 23 | super(text, description); 24 | this._checkboxSprite = new Sprite('commonmenu', '', new Point(410, 95), new Size(50, 50)); 25 | this.Checked = checked; 26 | this.Style = style; 27 | } 28 | 29 | public get Checked(): boolean { 30 | return this._checked; 31 | } 32 | 33 | public set Checked(value: boolean) { 34 | this._checked = value || false; 35 | } 36 | 37 | public get Style(): CheckboxStyle { 38 | return this._style; 39 | } 40 | 41 | public set Style(value: CheckboxStyle) { 42 | this._style = Number(value); 43 | } 44 | 45 | public setVerticalPosition(y: number): void { 46 | super.setVerticalPosition(y); 47 | this._checkboxSprite.pos.Y = y + 138 + this.offset.Y; 48 | } 49 | 50 | public draw(): void { 51 | super.draw(); 52 | this._checkboxSprite.pos.X = 380 + this.offset.X + (this.parent ? this.parent.WidthOffset : 0); 53 | this._checkboxSprite.textureName = this._getSpriteName(); 54 | this._checkboxSprite.color = this._getSpriteColor(); 55 | this._checkboxSprite.draw(Menu.screenResolution); 56 | } 57 | 58 | private _getSpriteName(): string { 59 | let name = 'blank'; 60 | if (this._checked) { 61 | switch (this._style) { 62 | case CheckboxStyle.Tick: 63 | name = 'tick'; 64 | break; 65 | case CheckboxStyle.Cross: 66 | name = 'cross'; 67 | break; 68 | } 69 | } 70 | return `shop_box_${name}${this.selected ? 'b' : ''}`; 71 | } 72 | 73 | private _getSpriteColor(): Color { 74 | return this.enabled ? Color.white : Color.fromRgb(109, 109, 109); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/utils/Animations.ts: -------------------------------------------------------------------------------- 1 | import { Wait } from '..'; 2 | 3 | /** 4 | * A utility to load an animation dictionary, anything that loads an animation should RemoveAnimDict after its finish being used. 5 | * @param animDict the animation dictionary to load 6 | * @param waitTime how long to wait for the dictionary to load 7 | * @returns {boolean} if the animation successfully loaded 8 | */ 9 | export const LoadAnimDict = async (animDict: string, waitTime = 1000): Promise => { 10 | const start = GetGameTimer(); 11 | 12 | if (!HasAnimDictLoaded(animDict)) { 13 | RequestAnimDict(animDict); 14 | } 15 | 16 | while (!HasAnimDictLoaded(animDict)) { 17 | if (GetGameTimer() - start >= waitTime) return false; 18 | await Wait(0); 19 | } 20 | 21 | return true; 22 | }; 23 | 24 | /** 25 | * A utility to load multiple animation dictionary, anything that loads an animation should RemoveAnimDict after its finish being used. 26 | * @param animDict the animation dictionary to load 27 | * @param waitTime how long to wait for the dictionary to load 28 | * @returns if the animation successfully loaded, if the animation failed to load it will return an array of animations that failed to load 29 | */ 30 | export const LoadAnimDictArray = async ( 31 | animDict: string[], 32 | waitTime = 1000, 33 | ): Promise<[boolean, string[] | null]> => { 34 | const start = GetGameTimer(); 35 | 36 | for (const dict of animDict) { 37 | if (!HasAnimDictLoaded(dict)) { 38 | RequestAnimDict(dict); 39 | } 40 | } 41 | // TODO: more optimized way to do this 42 | const animsLoaded: Set = new Set(); 43 | while (animsLoaded.size !== animDict.length) { 44 | for (const dict of animDict) { 45 | if (!animsLoaded.has(dict) && HasAnimDictLoaded(dict)) { 46 | animsLoaded.add(dict); 47 | } 48 | } 49 | 50 | if (GetGameTimer() - start >= waitTime) 51 | return [false, animDict.filter(dict => !animsLoaded.has(dict))]; 52 | await Wait(0); 53 | } 54 | 55 | return [true, null]; 56 | }; 57 | 58 | /** 59 | * A utility to unload multiple animation dictionary 60 | * @param animDict the animation dictionaries to unload 61 | */ 62 | export const RemoveAnimDictArray = (animDict: string[]): void => { 63 | for (const dict of animDict) { 64 | RemoveAnimDict(dict); 65 | } 66 | }; 67 | -------------------------------------------------------------------------------- /src/models/VehicleDoorCollection.ts: -------------------------------------------------------------------------------- 1 | import { Vehicle } from './Vehicle'; 2 | import { VehicleDoorIndex } from '../enums'; 3 | import { VehicleDoor } from './VehicleDoor'; 4 | 5 | export class VehicleDoorCollection { 6 | private _owner: Vehicle; 7 | private readonly _vehicleDoors: Map = new Map< 8 | VehicleDoorIndex, 9 | VehicleDoor 10 | >(); 11 | 12 | constructor(owner: Vehicle) { 13 | this._owner = owner; 14 | } 15 | 16 | public getDoors(index: VehicleDoorIndex): VehicleDoor | undefined { 17 | if (!this._vehicleDoors.has(index)) { 18 | this._vehicleDoors.set(index, new VehicleDoor(this._owner, index)); 19 | } 20 | return this._vehicleDoors.get(index); 21 | } 22 | 23 | public getAllDoors(): (VehicleDoor | null | undefined)[] { 24 | return Object.keys(VehicleDoorIndex) 25 | .filter(key => !isNaN(Number(key))) 26 | .map(key => { 27 | const index = Number(key); 28 | if (this.hasDoor(index)) { 29 | return this.getDoors(index); 30 | } 31 | return null; 32 | }) 33 | .filter(d => d); 34 | } 35 | 36 | public openAllDoors(loose?: boolean, instantly?: boolean): void { 37 | this.getAllDoors().forEach(door => { 38 | door?.open(loose, instantly); 39 | }); 40 | } 41 | 42 | public closeAllDoors(instantly?: boolean): void { 43 | this.getAllDoors().forEach(door => { 44 | door?.close(instantly); 45 | }); 46 | } 47 | 48 | public breakAllDoors(stayInTheWorld?: boolean): void { 49 | this.getAllDoors().forEach(door => { 50 | door?.break(stayInTheWorld); 51 | }); 52 | } 53 | 54 | public hasDoor(index: VehicleDoorIndex): boolean { 55 | if (this._owner.Bones === undefined) return false; 56 | switch (index) { 57 | case VehicleDoorIndex.FrontLeftDoor: 58 | return this._owner.Bones.hasBone('door_dside_f'); 59 | case VehicleDoorIndex.FrontRightDoor: 60 | return this._owner.Bones.hasBone('door_pside_f'); 61 | case VehicleDoorIndex.BackLeftDoor: 62 | return this._owner.Bones.hasBone('door_dside_r'); 63 | case VehicleDoorIndex.BackRightDoor: 64 | return this._owner.Bones.hasBone('door_pside_r'); 65 | case VehicleDoorIndex.Hood: 66 | return this._owner.Bones.hasBone('bonnet'); 67 | case VehicleDoorIndex.Trunk: 68 | return this._owner.Bones.hasBone('boot'); 69 | default: 70 | return false; 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/weapon/WeaponHudStats.ts: -------------------------------------------------------------------------------- 1 | import { enumValues } from '../utils'; 2 | import { WeaponHash } from '../hashes'; 3 | import { getUInt32FromUint8Array } from '../utils'; 4 | 5 | /*** 6 | * WeaponHudStats 7 | * refer1: https://github.com/citizenfx/fivem/blob/master/code/client/clrcore/External/Game.cs#L900 8 | * refer2: https://docs.fivem.net/natives/?_0xD92C739EE34C9EBA 9 | * // members should be aligned to 8 bytes by default but it's best to use alignas here, just to be sure 10 | * struct WeaponHudStatsData 11 | * { 12 | * alignas(8) uint8_t hudDamage; // 0x0000 13 | * alignas(8) uint8_t hudSpeed; // 0x0008 14 | * alignas(8) uint8_t hudCapacity; // 0x0010 15 | * alignas(8) uint8_t hudAccuracy; // 0x0018 16 | * alignas(8) uint8_t hudRange; // 0x0020 17 | * }; 18 | */ 19 | export interface WeaponHudStats { 20 | hudDamage: number; 21 | hudSpeed: number; 22 | hudCapacity: number; 23 | hudAccuracy: number; 24 | hudRange: number; 25 | } 26 | 27 | /** 28 | * Mapping of WeaponHash -> WeaponHudStats 29 | * 30 | */ 31 | export const WeaponHudStats = new Map(); 32 | 33 | /** 34 | * Initialize WeaponHudStats, avoid calling expansive native repeatedly 35 | * 36 | */ 37 | function initializeOnce() { 38 | let isInitialized = false; 39 | 40 | return function () { 41 | if (isInitialized || IsDuplicityVersion()) { 42 | return; 43 | } 44 | 45 | // magic number based on struct WeaponHudStats 46 | const intLength = 4; 47 | 48 | for (const hash of enumValues(WeaponHash)) { 49 | const buffer = new Uint8Array(0x28); 50 | 51 | // https://docs.fivem.net/natives/?_0xD92C739EE34C9EBA 52 | Citizen.invokeNative('0xD92C739EE34C9EBA', hash, buffer, Citizen.returnResultAnyway()); 53 | 54 | // noinspection PointlessArithmeticExpressionJS 55 | const weaponHudStats: WeaponHudStats = { 56 | hudDamage: getUInt32FromUint8Array(buffer, 0 * intLength, 1 * intLength), 57 | hudSpeed: getUInt32FromUint8Array(buffer, 2 * intLength, 3 * intLength), 58 | hudCapacity: getUInt32FromUint8Array(buffer, 4 * intLength, 5 * intLength), 59 | hudAccuracy: getUInt32FromUint8Array(buffer, 6 * intLength, 7 * intLength), 60 | hudRange: getUInt32FromUint8Array(buffer, 8 * intLength, 9 * intLength), 61 | }; 62 | 63 | WeaponHudStats.set(hash, weaponHudStats); 64 | } 65 | 66 | isInitialized = true; 67 | }; 68 | } 69 | 70 | initializeOnce()(); 71 | -------------------------------------------------------------------------------- /src/weaponComponent/WeaponComponentHudStats.ts: -------------------------------------------------------------------------------- 1 | import { WeaponComponentHash } from './WeaponComponentHash'; 2 | import { enumValues } from '../utils'; 3 | import { getUInt32FromUint8Array } from '../utils'; 4 | 5 | /*** 6 | * WeaponComponentHudStats 7 | * refer: https://github.com/citizenfx/fivem/blob/master/code/client/clrcore/External/Game.cs#L976 8 | * [StructLayout(LayoutKind.Explicit, Size = 0x28)] 9 | * [SecuritySafeCritical] 10 | * internal struct UnsafeWeaponComponentHudStats 11 | * { 12 | * [FieldOffset(0x00)] private int hudDamage; 13 | * [FieldOffset(0x08)] private int hudSpeed; 14 | * [FieldOffset(0x10)] private int hudCapacity; 15 | * [FieldOffset(0x18)] private int hudAccuracy; 16 | * [FieldOffset(0x20)] private int hudRange; 17 | * 18 | */ 19 | export interface WeaponComponentHudStats { 20 | hudDamage: number; 21 | hudSpeed: number; 22 | hudCapacity: number; 23 | hudAccuracy: number; 24 | hudRange: number; 25 | } 26 | 27 | /** 28 | * Mapping of WeaponComponentHash -> WeaponComponentHudStats 29 | * 30 | */ 31 | export const WeaponComponentHudStats = new Map(); 32 | 33 | function initializeOnce() { 34 | let isInitialized = false; 35 | 36 | return function () { 37 | if (isInitialized || IsDuplicityVersion()) { 38 | return; 39 | } 40 | 41 | // magic number based on struct WeaponComponentHudStat 42 | const intLength = 4; 43 | 44 | for (const hash of enumValues(WeaponComponentHash)) { 45 | const buffer = new Uint8Array(0x28); 46 | 47 | // https://docs.fivem.net/natives/?_0xB3CAF387AE12E9F8 48 | Citizen.invokeNative('0xB3CAF387AE12E9F8', hash, buffer, Citizen.returnResultAnyway()); 49 | 50 | // noinspection PointlessArithmeticExpressionJS 51 | const weaponComponentHudStat: WeaponComponentHudStats = { 52 | hudDamage: getUInt32FromUint8Array(buffer, 0 * intLength, 1 * intLength), 53 | hudSpeed: getUInt32FromUint8Array(buffer, 2 * intLength, 3 * intLength), 54 | hudCapacity: getUInt32FromUint8Array(buffer, 4 * intLength, 5 * intLength), 55 | hudAccuracy: getUInt32FromUint8Array(buffer, 6 * intLength, 7 * intLength), 56 | hudRange: getUInt32FromUint8Array(buffer, 8 * intLength, 9 * intLength), 57 | }; 58 | 59 | WeaponComponentHudStats.set(hash, weaponComponentHudStat); 60 | } 61 | 62 | isInitialized = true; 63 | }; 64 | } 65 | 66 | initializeOnce()(); 67 | -------------------------------------------------------------------------------- /src/enums/PickupType.ts: -------------------------------------------------------------------------------- 1 | export enum PickupType { 2 | CustomScript = 738282662, 3 | VehicleCustomScript = 2780351145, 4 | Parachute = 1735599485, 5 | PortablePackage = 2158727964, 6 | PortableCrateUnfixed = 1852930709, 7 | Health = 2406513688, 8 | HealthSnack = 483577702, 9 | Armour = 1274757841, 10 | MoneyCase = 3463437675, 11 | MoneySecurityCase = 3732468094, 12 | MoneyVariable = 4263048111, 13 | MoneyMedBag = 341217064, 14 | MoneyPurse = 513448440, 15 | MoneyDepBag = 545862290, 16 | MoneyWallet = 1575005502, 17 | MoneyPaperBag = 1897726628, 18 | WeaponPistol = 4189041807, 19 | WeaponCombatPistol = 2305275123, 20 | WeaponAPPistol = 996550793, 21 | WeaponSNSPistol = 3317114643, 22 | WeaponHeavyPistol = 2633054488, 23 | WeaponMicroSMG = 496339155, 24 | WeaponSMG = 978070226, 25 | WeaponMG = 2244651441, 26 | WeaponCombatMG = 2995980820, 27 | WeaponAssaultRifle = 4080829360, 28 | WeaponCarbineRifle = 3748731225, 29 | WeaponAdvancedRifle = 2998219358, 30 | WeaponSpecialCarbine = 157823901, 31 | WeaponBullpupRifle = 2170382056, 32 | WeaponPumpShotgun = 2838846925, 33 | WeaponSawnoffShotgun = 2528383651, 34 | WeaponAssaultShotgun = 2459552091, 35 | WeaponSniperRifle = 4264178988, 36 | WeaponHeavySniper = 1765114797, 37 | WeaponGrenadeLauncher = 779501861, 38 | WeaponRPG = 1295434569, 39 | WeaponMinigun = 792114228, 40 | WeaponGrenade = 1577485217, 41 | WeaponStickyBomb = 2081529176, 42 | WeaponSmokeGrenade = 483787975, 43 | WeaponMolotov = 768803961, 44 | WeaponPetrolCan = 3332236287, 45 | WeaponKnife = 663586612, 46 | WeaponNightstick = 1587637620, 47 | WeaponBat = 2179883038, 48 | WeaponCrowbar = 2267924616, 49 | WeaponGolfclub = 2297080999, 50 | WeaponBottle = 4199656437, 51 | VehicleWeaponPistol = 2773149623, 52 | VehicleWeaponCombatPistol = 3500855031, 53 | VehicleWeaponAPPistol = 3431676165, 54 | VehicleWeaponMicroSMG = 3094015579, 55 | VehicleWeaponSawnoffShotgun = 772217690, 56 | VehicleWeaponGrenade = 2803366040, 57 | VehicleWeaponSmokeGrenade = 1705498857, 58 | VehicleWeaponStickyBomb = 746606563, 59 | VehicleWeaponMolotov = 2228647636, 60 | VehicleHealth = 160266735, 61 | AmmoPistol = 544828034, 62 | AmmoSMG = 292537574, 63 | AmmoMG = 3730366643, 64 | AmmoRifle = 3837603782, 65 | AmmoShotgun = 2012476125, 66 | AmmoSniper = 3224170789, 67 | AmmoGrenadeLauncher = 2283450536, 68 | AmmoRPG = 2223210455, 69 | AmmoMinigun = 4065984953, 70 | AmmoMissileMP = 4187887056, 71 | AmmoBulletMP = 1426343849, 72 | AmmoGrenadeLauncherMP = 2753668402, 73 | } 74 | -------------------------------------------------------------------------------- /src/Raycast.ts: -------------------------------------------------------------------------------- 1 | import { Game } from './Game'; 2 | import { MaterialHash } from './hashes'; 3 | import { Ped, Prop, Vehicle } from './models'; 4 | import { Vector3 } from './utils'; 5 | 6 | /** 7 | * Class that represents the result of a raycast. 8 | */ 9 | export class RaycastResult { 10 | /** 11 | * Return the entity that was hit. 12 | */ 13 | public get HitEntity(): Ped | Vehicle | Prop | null { 14 | return this.entityHandleArg; 15 | } 16 | 17 | /** 18 | * Get the position of the entity that was hit. 19 | */ 20 | public get HitPosition(): Vector3 { 21 | return this.hitPositionArg; 22 | } 23 | 24 | /** 25 | * Return the vector perpendicular to the tangent plane. 26 | */ 27 | public get SurfaceNormal(): Vector3 { 28 | return this.surfaceNormalArg; 29 | } 30 | 31 | /** 32 | * Whether we hit anything. 33 | */ 34 | public get DidHit(): boolean { 35 | return this.hitSomethingArg; 36 | } 37 | 38 | /** 39 | * Whether the entity hit exists. 40 | */ 41 | public get DidHitEntity(): boolean { 42 | return this.entityHandleArg?.Handle !== 0; 43 | } 44 | 45 | /** 46 | * Material type that was hit. 47 | */ 48 | public get Material(): MaterialHash { 49 | return this.materialArg; 50 | } 51 | 52 | /** 53 | * Raycast result's handle. 54 | */ 55 | public get Result(): number { 56 | return this.result; 57 | } 58 | 59 | private handle: number; 60 | private hitPositionArg: Vector3; 61 | private hitSomethingArg: boolean; 62 | private entityHandleArg: Ped | Vehicle | Prop | null; 63 | private surfaceNormalArg: Vector3; 64 | private materialArg: MaterialHash; 65 | private result: number; 66 | 67 | // FIXME: This only works with StartExpensiveSynchronousShapeTestLosProbe, this should have some getter you have to await afterwards for all of the data 68 | 69 | /** 70 | * Create a RaycastResult object that gets the results from a StartShapeTestRay() 71 | * 72 | * @param handle The handle returned from StartShapeTestRay() 73 | */ 74 | constructor(handle: number) { 75 | this.handle = handle; 76 | this.hitPositionArg = new Vector3(0, 0, 0); 77 | this.hitSomethingArg = false; 78 | this.entityHandleArg = null; 79 | this.surfaceNormalArg = new Vector3(0, 0, 0); 80 | this.materialArg = 0; 81 | 82 | const [result, hit, endCoords, surfaceNormal, materialHash, entityHit] = 83 | GetShapeTestResultIncludingMaterial(this.handle); 84 | this.hitSomethingArg = hit; 85 | this.hitPositionArg = Vector3.fromArray(endCoords); 86 | this.surfaceNormalArg = Vector3.fromArray(surfaceNormal); 87 | this.materialArg = materialHash; 88 | this.entityHandleArg = Game.entityFromHandle(entityHit); 89 | 90 | this.result = result; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /docs/assets/highlight.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --light-hl-0: #AF00DB; 3 | --dark-hl-0: #C586C0; 4 | --light-hl-1: #000000; 5 | --dark-hl-1: #D4D4D4; 6 | --light-hl-2: #001080; 7 | --dark-hl-2: #9CDCFE; 8 | --light-hl-3: #A31515; 9 | --dark-hl-3: #CE9178; 10 | --light-hl-4: #0000FF; 11 | --dark-hl-4: #569CD6; 12 | --light-hl-5: #0070C1; 13 | --dark-hl-5: #4FC1FF; 14 | --light-hl-6: #795E26; 15 | --dark-hl-6: #DCDCAA; 16 | --light-hl-7: #098658; 17 | --dark-hl-7: #B5CEA8; 18 | --light-hl-8: #008000; 19 | --dark-hl-8: #6A9955; 20 | --light-code-background: #FFFFFF; 21 | --dark-code-background: #1E1E1E; 22 | } 23 | 24 | @media (prefers-color-scheme: light) { :root { 25 | --hl-0: var(--light-hl-0); 26 | --hl-1: var(--light-hl-1); 27 | --hl-2: var(--light-hl-2); 28 | --hl-3: var(--light-hl-3); 29 | --hl-4: var(--light-hl-4); 30 | --hl-5: var(--light-hl-5); 31 | --hl-6: var(--light-hl-6); 32 | --hl-7: var(--light-hl-7); 33 | --hl-8: var(--light-hl-8); 34 | --code-background: var(--light-code-background); 35 | } } 36 | 37 | @media (prefers-color-scheme: dark) { :root { 38 | --hl-0: var(--dark-hl-0); 39 | --hl-1: var(--dark-hl-1); 40 | --hl-2: var(--dark-hl-2); 41 | --hl-3: var(--dark-hl-3); 42 | --hl-4: var(--dark-hl-4); 43 | --hl-5: var(--dark-hl-5); 44 | --hl-6: var(--dark-hl-6); 45 | --hl-7: var(--dark-hl-7); 46 | --hl-8: var(--dark-hl-8); 47 | --code-background: var(--dark-code-background); 48 | } } 49 | 50 | body.light { 51 | --hl-0: var(--light-hl-0); 52 | --hl-1: var(--light-hl-1); 53 | --hl-2: var(--light-hl-2); 54 | --hl-3: var(--light-hl-3); 55 | --hl-4: var(--light-hl-4); 56 | --hl-5: var(--light-hl-5); 57 | --hl-6: var(--light-hl-6); 58 | --hl-7: var(--light-hl-7); 59 | --hl-8: var(--light-hl-8); 60 | --code-background: var(--light-code-background); 61 | } 62 | 63 | body.dark { 64 | --hl-0: var(--dark-hl-0); 65 | --hl-1: var(--dark-hl-1); 66 | --hl-2: var(--dark-hl-2); 67 | --hl-3: var(--dark-hl-3); 68 | --hl-4: var(--dark-hl-4); 69 | --hl-5: var(--dark-hl-5); 70 | --hl-6: var(--dark-hl-6); 71 | --hl-7: var(--dark-hl-7); 72 | --hl-8: var(--dark-hl-8); 73 | --code-background: var(--dark-code-background); 74 | } 75 | 76 | .hl-0 { color: var(--hl-0); } 77 | .hl-1 { color: var(--hl-1); } 78 | .hl-2 { color: var(--hl-2); } 79 | .hl-3 { color: var(--hl-3); } 80 | .hl-4 { color: var(--hl-4); } 81 | .hl-5 { color: var(--hl-5); } 82 | .hl-6 { color: var(--hl-6); } 83 | .hl-7 { color: var(--hl-7); } 84 | .hl-8 { color: var(--hl-8); } 85 | pre, code { background: var(--code-background); } 86 | -------------------------------------------------------------------------------- /src/RelationshipGroup.ts: -------------------------------------------------------------------------------- 1 | import { Relationship } from './enums'; 2 | 3 | /** 4 | * Class to create and manage a relationship group. Useful to manage behavior between Peds. 5 | */ 6 | export class RelationshipGroup { 7 | /** 8 | * The hash of the relationship group 9 | */ 10 | private hash: number; 11 | 12 | /** 13 | * Create a relationship group. Optionally pass a group hash. 14 | * 15 | * @param name Name of the relationship group. 16 | */ 17 | constructor(name: string) { 18 | const [, groupHash] = AddRelationshipGroup(name); 19 | this.hash = groupHash; 20 | } 21 | 22 | /** 23 | * Gets the hash of the relationship group. 24 | * 25 | * @returns The hash of this object. 26 | */ 27 | public get Hash(): number { 28 | return this.hash; 29 | } 30 | 31 | /** 32 | * Get the relationship between two relationship groups. 33 | * 34 | * @param targetGroup The other relationship group. 35 | * @returns The relationship 36 | */ 37 | public getRelationshipBetweenGroups(targetGroup: RelationshipGroup): Relationship { 38 | return GetRelationshipBetweenGroups(this.Hash, targetGroup.Hash); 39 | } 40 | 41 | /** 42 | * Set the relationship group between this relationship group and another one. 43 | * 44 | * @param targetGroup The other relationship group. 45 | * @param relationship The desired relationship. 46 | * @param biDirectionally If target group should have same relationship towards this. 47 | */ 48 | public setRelationshipBetweenGroups( 49 | targetGroup: RelationshipGroup, 50 | relationship: Relationship, 51 | biDirectionally = false, 52 | ): void { 53 | SetRelationshipBetweenGroups(Number(relationship), this.Hash, targetGroup.Hash); 54 | 55 | if (biDirectionally) { 56 | SetRelationshipBetweenGroups(Number(relationship), targetGroup.Hash, this.Hash); 57 | } 58 | } 59 | 60 | /** 61 | * Clear the relationship between this relationship group and another. 62 | * 63 | * @param targetGroup The other relationship group. 64 | * @param relationship The desired relationship to clear. 65 | * @param biDirectionally Whether the target group should also clear the relationship. 66 | */ 67 | public clearRelationshipBetweenGroups( 68 | targetGroup: RelationshipGroup, 69 | relationship: Relationship, 70 | biDirectionally = false, 71 | ): void { 72 | ClearRelationshipBetweenGroups(Number(relationship), this.Hash, targetGroup.Hash); 73 | 74 | if (biDirectionally) { 75 | ClearRelationshipBetweenGroups(Number(relationship), targetGroup.Hash, this.Hash); 76 | } 77 | } 78 | 79 | /** 80 | * Remove this relationship group from the game. This will not delete this object. 81 | */ 82 | public remove(): void { 83 | RemoveRelationshipGroup(this.Hash); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/enums/Bone.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/naming-convention */ 2 | export enum Bone { 3 | SKEL_ROOT, 4 | SKEL_Pelvis = 11816, 5 | SKEL_L_Thigh = 58271, 6 | SKEL_L_Calf = 63931, 7 | SKEL_L_Foot = 14201, 8 | SKEL_L_Toe0 = 2108, 9 | IK_L_Foot = 65245, 10 | PH_L_Foot = 57717, 11 | MH_L_Knee = 46078, 12 | SKEL_R_Thigh = 51826, 13 | SKEL_R_Calf = 36864, 14 | SKEL_R_Foot = 52301, 15 | SKEL_R_Toe0 = 20781, 16 | IK_R_Foot = 35502, 17 | PH_R_Foot = 24806, 18 | MH_R_Knee = 16335, 19 | RB_L_ThighRoll = 23639, 20 | RB_R_ThighRoll = 6442, 21 | SKEL_Spine_Root = 57597, 22 | SKEL_Spine0 = 23553, 23 | SKEL_Spine1 = 24816, 24 | SKEL_Spine2, 25 | SKEL_Spine3, 26 | SKEL_L_Clavicle = 64729, 27 | SKEL_L_UpperArm = 45509, 28 | SKEL_L_Forearm = 61163, 29 | SKEL_L_Hand = 18905, 30 | SKEL_L_Finger00 = 26610, 31 | SKEL_L_Finger01 = 4089, 32 | SKEL_L_Finger02, 33 | SKEL_L_Finger10 = 26611, 34 | SKEL_L_Finger11 = 4169, 35 | SKEL_L_Finger12, 36 | SKEL_L_Finger20 = 26612, 37 | SKEL_L_Finger21 = 4185, 38 | SKEL_L_Finger22, 39 | SKEL_L_Finger30 = 26613, 40 | SKEL_L_Finger31 = 4137, 41 | SKEL_L_Finger32, 42 | SKEL_L_Finger40 = 26614, 43 | SKEL_L_Finger41 = 4153, 44 | SKEL_L_Finger42, 45 | PH_L_Hand = 60309, 46 | IK_L_Hand = 36029, 47 | RB_L_ForeArmRoll = 61007, 48 | RB_L_ArmRoll = 5232, 49 | MH_L_Elbow = 22711, 50 | SKEL_R_Clavicle = 10706, 51 | SKEL_R_UpperArm = 40269, 52 | SKEL_R_Forearm = 28252, 53 | SKEL_R_Hand = 57005, 54 | SKEL_R_Finger00 = 58866, 55 | SKEL_R_Finger01 = 64016, 56 | SKEL_R_Finger02, 57 | SKEL_R_Finger10 = 58867, 58 | SKEL_R_Finger11 = 64096, 59 | SKEL_R_Finger12, 60 | SKEL_R_Finger20 = 58868, 61 | SKEL_R_Finger21 = 64112, 62 | SKEL_R_Finger22, 63 | SKEL_R_Finger30 = 58869, 64 | SKEL_R_Finger31 = 64064, 65 | SKEL_R_Finger32, 66 | SKEL_R_Finger40 = 58870, 67 | SKEL_R_Finger41 = 64080, 68 | SKEL_R_Finger42, 69 | PH_R_Hand = 28422, 70 | IK_R_Hand = 6286, 71 | RB_R_ForeArmRoll = 43810, 72 | RB_R_ArmRoll = 37119, 73 | MH_R_Elbow = 2992, 74 | SKEL_Neck_1 = 39317, 75 | SKEL_Head = 31086, 76 | IK_Head = 12844, 77 | FACIAL_facialRoot = 65068, 78 | FB_L_Brow_Out_000 = 58331, 79 | FB_L_Lid_Upper_000 = 45750, 80 | FB_L_Eye_000 = 25260, 81 | FB_L_CheekBone_000 = 21550, 82 | FB_L_Lip_Corner_000 = 29868, 83 | FB_R_Lid_Upper_000 = 43536, 84 | FB_R_Eye_000 = 27474, 85 | FB_R_CheekBone_000 = 19336, 86 | FB_R_Brow_Out_000 = 1356, 87 | FB_R_Lip_Corner_000 = 11174, 88 | FB_Brow_Centre_000 = 37193, 89 | FB_UpperLipRoot_000 = 20178, 90 | FB_UpperLip_000 = 61839, 91 | FB_L_Lip_Top_000 = 20279, 92 | FB_R_Lip_Top_000 = 17719, 93 | FB_Jaw_000 = 46240, 94 | FB_LowerLipRoot_000 = 17188, 95 | FB_LowerLip_000 = 20623, 96 | FB_L_Lip_Bot_000 = 47419, 97 | FB_R_Lip_Bot_000 = 49979, 98 | FB_Tongue_000 = 47495, 99 | RB_Neck_1 = 35731, 100 | IK_Root = 56604, 101 | } 102 | -------------------------------------------------------------------------------- /src/weapon/WeaponDisplayNameByHash.ts: -------------------------------------------------------------------------------- 1 | import { DlcWeaponData } from './DlcWeaponData'; 2 | import { WeaponHash } from '../hashes'; 3 | 4 | /*** 5 | * Mapping of WeaponHash -> DisplayName(Label) 6 | * 7 | */ 8 | export const WeaponDisplayNameByHash = new Map([ 9 | [WeaponHash.Pistol, 'WT_PIST'], 10 | [WeaponHash.CombatPistol, 'WT_PIST_CBT'], 11 | [WeaponHash.APPistol, 'WT_PIST_AP'], 12 | [WeaponHash.SMG, 'WT_SMG'], 13 | [WeaponHash.MicroSMG, 'WT_SMG_MCR'], 14 | [WeaponHash.AssaultRifle, 'WT_RIFLE_ASL'], 15 | [WeaponHash.CarbineRifle, 'WT_RIFLE_CBN'], 16 | [WeaponHash.AdvancedRifle, 'WT_RIFLE_ADV'], 17 | [WeaponHash.MG, 'WT_MG'], 18 | [WeaponHash.CombatMG, 'WT_MG_CBT'], 19 | [WeaponHash.PumpShotgun, 'WT_SG_PMP'], 20 | [WeaponHash.SawnOffShotgun, 'WT_SG_SOF'], 21 | [WeaponHash.AssaultShotgun, 'WT_SG_ASL'], 22 | [WeaponHash.HeavySniper, 'WT_SNIP_HVY'], 23 | [WeaponHash.SniperRifle, 'WT_SNIP_RIF'], 24 | [WeaponHash.GrenadeLauncher, 'WT_GL'], 25 | [WeaponHash.RPG, 'WT_RPG'], 26 | [WeaponHash.Minigun, 'WT_MINIGUN'], 27 | [WeaponHash.AssaultSMG, 'WT_SMG_ASL'], 28 | [WeaponHash.BullpupShotgun, 'WT_SG_BLP'], 29 | [WeaponHash.Pistol50, 'WT_PIST_50'], 30 | [WeaponHash.Bottle, 'WT_BOTTLE'], 31 | [WeaponHash.Gusenberg, 'WT_GUSENBERG'], 32 | [WeaponHash.SNSPistol, 'WT_SNSPISTOL'], 33 | [WeaponHash.VintagePistol, 'TT_VPISTOL'], 34 | [WeaponHash.Dagger, 'WT_DAGGER'], 35 | [WeaponHash.FlareGun, 'WT_FLAREGUN'], 36 | [WeaponHash.Musket, 'WT_MUSKET'], 37 | [WeaponHash.Firework, 'WT_FWRKLNCHR'], 38 | [WeaponHash.MarksmanRifle, 'WT_HMKRIFLE'], 39 | [WeaponHash.HeavyShotgun, 'WT_HVYSHOT'], 40 | [WeaponHash.ProximityMine, 'WT_PRXMINE'], 41 | [WeaponHash.HomingLauncher, 'WT_HOMLNCH'], 42 | [WeaponHash.CombatPDW, 'WT_COMBATPDW'], 43 | [WeaponHash.KnuckleDuster, 'WT_KNUCKLE'], 44 | [WeaponHash.MarksmanPistol, 'WT_MKPISTOL'], 45 | [WeaponHash.Machete, 'WT_MACHETE'], 46 | [WeaponHash.MachinePistol, 'WT_MCHPIST'], 47 | [WeaponHash.Flashlight, 'WT_FLASHLIGHT'], 48 | [WeaponHash.DoubleBarrelShotgun, 'WT_DBSHGN'], 49 | [WeaponHash.CompactRifle, 'WT_CMPRIFLE'], 50 | [WeaponHash.SwitchBlade, 'WT_SWBLADE'], 51 | [WeaponHash.Revolver, 'WT_REVOLVER'], 52 | // mpgunrunning 53 | [WeaponHash.PistolMk2, 'WT_PIST2'], 54 | [WeaponHash.AssaultRifleMk2, 'WT_RIFLE_ASL2'], 55 | [WeaponHash.CarbineRifleMk2, 'WT_RIFLE_CBN2'], 56 | [WeaponHash.CombatMGMk2, 'WT_MG_CBT2'], 57 | [WeaponHash.HeavySniperMk2, 'WT_SNIP_HVY2'], 58 | [WeaponHash.SMGMk2, 'WT_SMG2'], 59 | ]); 60 | 61 | /** 62 | * Initialize with DlcWeaponData, in case of any missing dlc data 63 | * 64 | */ 65 | function initializeOnce() { 66 | let isInitialized = false; 67 | 68 | return function () { 69 | if (isInitialized) { 70 | return; 71 | } 72 | 73 | for (const [hash, data] of DlcWeaponData) { 74 | WeaponDisplayNameByHash.set(hash, data.name); 75 | } 76 | 77 | isInitialized = true; 78 | }; 79 | } 80 | 81 | initializeOnce()(); 82 | -------------------------------------------------------------------------------- /src/ui/Sprite.ts: -------------------------------------------------------------------------------- 1 | import { Color, Point, Size } from '../utils'; 2 | import { Screen } from './'; 3 | 4 | export class Sprite { 5 | public textureName: string; 6 | public pos: Point; 7 | public size: Size; 8 | public heading: number; 9 | public color: Color; 10 | public visible: boolean; 11 | 12 | private _textureDict: string; 13 | 14 | constructor( 15 | textureDict: string, 16 | textureName: string, 17 | pos?: Point, 18 | size?: Size, 19 | heading = 0, 20 | color = Color.white, 21 | ) { 22 | this._textureDict = textureDict; 23 | this.textureName = textureName; 24 | this.pos = pos || new Point(); 25 | this.size = size || new Size(); 26 | this.heading = heading || 0; 27 | this.color = color || Color.white; 28 | this.visible = true; 29 | } 30 | 31 | public loadTextureDictionary(): void { 32 | RequestStreamedTextureDict(this._textureDict, true); 33 | const interval = setInterval(() => { 34 | if (this.IsTextureDictionaryLoaded) { 35 | clearInterval(interval); 36 | } 37 | }, 0); 38 | } 39 | 40 | public set TextureDict(v: string) { 41 | this._textureDict = v; 42 | if (!this.IsTextureDictionaryLoaded) { 43 | this.loadTextureDictionary(); 44 | } 45 | } 46 | 47 | public get TextureDict(): string { 48 | return this._textureDict; 49 | } 50 | 51 | public get IsTextureDictionaryLoaded(): boolean { 52 | return HasStreamedTextureDictLoaded(this._textureDict); 53 | } 54 | 55 | public draw(resolution?: Size): void; 56 | public draw( 57 | textureDictionary?: string, 58 | textureName?: string, 59 | pos?: Point, 60 | size?: Size, 61 | heading?: number, 62 | color?: Color, 63 | loadTexture?: boolean, 64 | resolution?: Size, 65 | ): void; 66 | public draw( 67 | arg1?: Size | string, 68 | textureName?: string, 69 | pos?: Point, 70 | size?: Size, 71 | heading?: number, 72 | color?: Color, 73 | loadTexture = true, 74 | resolution?: Size, 75 | ): void { 76 | const textureDictionary = arg1 && typeof arg1 === 'string' ? arg1 : this.TextureDict; 77 | 78 | textureName = textureName || this.textureName; 79 | pos = pos || this.pos; 80 | size = size || this.size; 81 | heading = heading || this.heading; 82 | color = color || this.color; 83 | 84 | if (loadTexture) { 85 | if (!HasStreamedTextureDictLoaded(textureDictionary)) { 86 | RequestStreamedTextureDict(textureDictionary, false); 87 | } 88 | } 89 | 90 | resolution = arg1 instanceof Size ? arg1 : resolution; 91 | resolution = resolution || new Size(Screen.ScaledWidth, Screen.Height); 92 | 93 | const w = size.width / resolution.width; 94 | const h = size.height / resolution.height; 95 | const x = pos.X / resolution.width + w * 0.5; 96 | const y = pos.Y / resolution.height + h * 0.5; 97 | 98 | DrawSprite( 99 | textureDictionary, 100 | textureName, 101 | x, 102 | y, 103 | w, 104 | h, 105 | heading, 106 | color.r, 107 | color.g, 108 | color.b, 109 | color.a, 110 | ); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /src/ui/menu/items/panels/UIMenuStatisticsPanel.ts: -------------------------------------------------------------------------------- 1 | import { Color, Point, Size } from '../../../../utils'; 2 | import { AbstractUIMenuPanel, UIMenuStatisticsPanelItem } from './'; 3 | import { Menu, Rectangle } from '../../../'; 4 | 5 | export class UIMenuStatisticsPanel extends AbstractUIMenuPanel { 6 | protected readonly background: Rectangle; 7 | 8 | private _divider = true; 9 | private _items: UIMenuStatisticsPanelItem[] = []; 10 | 11 | constructor(item?: UIMenuStatisticsPanelItem[] | UIMenuStatisticsPanelItem, divider = true) { 12 | super(); 13 | this.background = new Rectangle(new Point(), new Size(431, 47), new Color(170, 0, 0, 0)); 14 | if (item) { 15 | this.addItem(item); 16 | } 17 | this.Divider = divider; 18 | } 19 | 20 | public get Divider(): boolean { 21 | return this._divider; 22 | } 23 | 24 | public set Divider(value: boolean) { 25 | this._divider = value || false; 26 | } 27 | 28 | public get Items(): UIMenuStatisticsPanelItem[] { 29 | return this._items; 30 | } 31 | 32 | public set Items(value: UIMenuStatisticsPanelItem[]) { 33 | this._items = value; 34 | } 35 | 36 | public addItem(item: UIMenuStatisticsPanelItem | UIMenuStatisticsPanelItem[]): void { 37 | const items = Array.isArray(item) ? item : [item]; 38 | this._items.push(...items); 39 | } 40 | 41 | public removeItem(itemOrIndex: UIMenuStatisticsPanelItem | number): void { 42 | if (typeof itemOrIndex === 'number') { 43 | this._items = this._items.filter((i, index) => index !== itemOrIndex); 44 | } else { 45 | this._items = this._items.filter(i => i.id !== itemOrIndex.id); 46 | } 47 | } 48 | 49 | public setVerticalPosition(y: number): void { 50 | super.setVerticalPosition(y); 51 | this._items.forEach(async (item, index) => { 52 | const itemCountOffset = 40 * (index + 1); 53 | const yOffset = y + itemCountOffset - 22; 54 | item.backgroundBar.pos.Y = yOffset; 55 | item.activeBar.pos.Y = yOffset; 56 | item.text.pos.Y = yOffset - 12; 57 | if (this._divider) { 58 | item.divider.forEach(async divider => { 59 | divider.pos.Y = yOffset; 60 | }); 61 | } 62 | }); 63 | } 64 | 65 | public draw(): void { 66 | if (this.enabled) { 67 | super.draw(); 68 | 69 | const x = this.parentItem?.offset.X ?? 0 + (this.ParentMenu?.WidthOffset ?? 0) / 2; 70 | this._items.forEach(async (item, index) => { 71 | const itemCountOffset = 40 * (index + 1); 72 | item.backgroundBar.pos.X = x + 200; 73 | item.activeBar.pos.X = x + 200; 74 | item.text.pos.X = x + 13; 75 | 76 | item.backgroundBar.draw(undefined, Menu.screenResolution); 77 | item.activeBar.draw(undefined, Menu.screenResolution); 78 | item.text.draw(undefined, Menu.screenResolution); 79 | if (this._divider) { 80 | item.divider.forEach(async (divider, index) => { 81 | const dividerWidthOffset = (index + 1) * 40; 82 | divider.pos.X = x + dividerWidthOffset + 200; 83 | this.background.size.height = itemCountOffset + 47 - 39; 84 | 85 | divider.draw(undefined, Menu.screenResolution); 86 | }); 87 | } 88 | }); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/weaponComponent/DlcWeaponComponentData.ts: -------------------------------------------------------------------------------- 1 | import { WeaponComponentHash } from './WeaponComponentHash'; 2 | import { getStringFromUInt8Array, getUInt32FromUint8Array } from '../utils'; 3 | 4 | /** 5 | * DlcWeaponComponentData 6 | * refer1: https://github.com/citizenfx/fivem/blob/master/code/client/clrcore/External/DlcWeaponStructs.cs#L130 7 | * refer2: https://docs.fivem.net/natives/?_0x6CF598A2957C2BF8 8 | * p0 seems to be the weapon index 9 | * p1 seems to be the weapon component index 10 | * struct DlcComponentData{ 11 | * int attachBone; 12 | * int padding1; 13 | * int bActiveByDefault; 14 | * int padding2; 15 | * int unk; 16 | * int padding3; 17 | * int componentHash; 18 | * int padding4; 19 | * int unk2; 20 | * int padding5; 21 | * int componentCost; 22 | * int padding6; 23 | * char nameLabel[64]; 24 | * char descLabel[64]; 25 | * }; 26 | * 27 | */ 28 | export interface DlcWeaponComponentData { 29 | attachBone: number; 30 | bActiveByDefault: number; 31 | unk: number; 32 | componentHash: number; 33 | unk2: number; 34 | componentCost: number; 35 | name: string; 36 | desc: string; 37 | } 38 | 39 | /** 40 | * DlcWeaponComponentData 41 | * 42 | */ 43 | export const DlcWeaponComponentData = new Map(); 44 | 45 | /** 46 | * Initialize DlcWeaponComponentData, avoid calling expansive native repeatedly 47 | * 48 | */ 49 | function initializeOnce() { 50 | let isInitialized = false; 51 | 52 | return function () { 53 | if (isInitialized || IsDuplicityVersion()) { 54 | return; 55 | } 56 | 57 | // magic number based on struct DlcWeaponData 58 | const intLength = 4; 59 | const strLength = 64; 60 | 61 | const weaponCount = GetNumDlcWeapons(); 62 | for (let i = 0; i < weaponCount; i++) { 63 | const componentCount = GetNumDlcWeaponComponents(i); 64 | for (let j = 0; j < componentCount; j++) { 65 | const buffer = new Uint8Array(14 * intLength + 4 * strLength); 66 | 67 | // https://docs.fivem.net/natives/?_0x6CF598A2957C2BF8 68 | Citizen.invokeNative('0x6CF598A2957C2BF8', i, j, buffer, Citizen.returnResultAnyway()); 69 | 70 | // noinspection PointlessArithmeticExpressionJS 71 | const dlcWeaponComponentData: DlcWeaponComponentData = { 72 | attachBone: getUInt32FromUint8Array(buffer, 0 * intLength, 1 * intLength), 73 | bActiveByDefault: getUInt32FromUint8Array(buffer, 2 * intLength, 3 * intLength), 74 | unk: getUInt32FromUint8Array(buffer, 4 * intLength, 5 * intLength), 75 | componentHash: getUInt32FromUint8Array(buffer, 6 * intLength, 7 * intLength), 76 | unk2: getUInt32FromUint8Array(buffer, 8 * intLength, 9 * intLength), 77 | componentCost: getUInt32FromUint8Array(buffer, 10 * intLength, 11 * intLength), 78 | name: getStringFromUInt8Array(buffer, 12 * intLength, 12 * intLength + strLength), 79 | desc: getStringFromUInt8Array( 80 | buffer, 81 | 12 * intLength + strLength, 82 | 12 * intLength + 2 * strLength, 83 | ), 84 | }; 85 | 86 | DlcWeaponComponentData.set(dlcWeaponComponentData.componentHash, dlcWeaponComponentData); 87 | } 88 | } 89 | 90 | isInitialized = true; 91 | }; 92 | } 93 | 94 | initializeOnce()(); 95 | -------------------------------------------------------------------------------- /src/ui/Effects.ts: -------------------------------------------------------------------------------- 1 | import { ScreenEffect } from '../enums'; 2 | 3 | export abstract class Effects { 4 | public static start(effectName: ScreenEffect, duration = 0, looped = false): void { 5 | StartScreenEffect(this.effectToString(effectName), duration, looped); 6 | } 7 | 8 | public static stop(screenEffect?: ScreenEffect): void { 9 | if (typeof screenEffect === 'undefined') { 10 | StopAllScreenEffects(); 11 | } else { 12 | StopScreenEffect(this.effectToString(screenEffect)); 13 | } 14 | } 15 | 16 | public static isActive(screenEffect: ScreenEffect): boolean { 17 | return GetScreenEffectIsActive(this.effectToString(screenEffect)); 18 | } 19 | 20 | private static readonly effects: string[] = [ 21 | 'SwitchHUDIn', 22 | 'SwitchHUDOut', 23 | 'FocusIn', 24 | 'FocusOut', 25 | 'MinigameEndNeutral', 26 | 'MinigameEndTrevor', 27 | 'MinigameEndFranklin', 28 | 'MinigameEndMichael', 29 | 'MinigameTransitionOut', 30 | 'MinigameTransitionIn', 31 | 'SwitchShortNeutralIn', 32 | 'SwitchShortFranklinIn', 33 | 'SwitchShortTrevorIn', 34 | 'SwitchShortMichaelIn', 35 | 'SwitchOpenMichaelIn', 36 | 'SwitchOpenFranklinIn', 37 | 'SwitchOpenTrevorIn', 38 | 'SwitchHUDMichaelOut', 39 | 'SwitchHUDFranklinOut', 40 | 'SwitchHUDTrevorOut', 41 | 'SwitchShortFranklinMid', 42 | 'SwitchShortMichaelMid', 43 | 'SwitchShortTrevorMid', 44 | 'DeathFailOut', 45 | 'CamPushInNeutral', 46 | 'CamPushInFranklin', 47 | 'CamPushInMichael', 48 | 'CamPushInTrevor', 49 | 'SwitchSceneFranklin', 50 | 'SwitchSceneTrevor', 51 | 'SwitchSceneMichael', 52 | 'SwitchSceneNeutral', 53 | 'MP_Celeb_Win', 54 | 'MP_Celeb_Win_Out', 55 | 'MP_Celeb_Lose', 56 | 'MP_Celeb_Lose_Out', 57 | 'DeathFailNeutralIn', 58 | 'DeathFailMPDark', 59 | 'DeathFailMPIn', 60 | 'MP_Celeb_Preload_Fade', 61 | 'PeyoteEndOut', 62 | 'PeyoteEndIn', 63 | 'PeyoteIn', 64 | 'PeyoteOut', 65 | 'MP_race_crash', 66 | 'SuccessFranklin', 67 | 'SuccessTrevor', 68 | 'SuccessMichael', 69 | 'DrugsMichaelAliensFightIn', 70 | 'DrugsMichaelAliensFight', 71 | 'DrugsMichaelAliensFightOut', 72 | 'DrugsTrevorClownsFightIn', 73 | 'DrugsTrevorClownsFight', 74 | 'DrugsTrevorClownsFightOut', 75 | 'HeistCelebPass', 76 | 'HeistCelebPassBW', 77 | 'HeistCelebEnd', 78 | 'HeistCelebToast', 79 | 'MenuMGHeistIn', 80 | 'MenuMGTournamentIn', 81 | 'MenuMGSelectionIn', 82 | 'ChopVision', 83 | 'DMT_flight_intro', 84 | 'DMT_flight', 85 | 'DrugsDrivingIn', 86 | 'DrugsDrivingOut', 87 | 'SwitchOpenNeutralFIB5', 88 | 'HeistLocate', 89 | 'MP_job_load', 90 | 'RaceTurbo', 91 | 'MP_intro_logo', 92 | 'HeistTripSkipFade', 93 | 'MenuMGHeistOut', 94 | 'MP_corona_switch', 95 | 'MenuMGSelectionTint', 96 | 'SuccessNeutral', 97 | 'ExplosionJosh3', 98 | 'SniperOverlay', 99 | 'RampageOut', 100 | 'Rampage', 101 | 'Dont_tazeme_bro', 102 | ]; 103 | 104 | private static effectToString(screenEffect: ScreenEffect): string { 105 | const effect = Number(screenEffect); 106 | if (effect >= 0 && effect <= this.effects.length) { 107 | return this.effects[effect]; 108 | } 109 | return 'INVALID'; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/enums/BadgeStyle.ts: -------------------------------------------------------------------------------- 1 | export enum BadgeStyle { 2 | None, 3 | Lock, 4 | Star, 5 | Warning, 6 | Crown, 7 | MedalBronze, 8 | MedalGold, 9 | MedalSilver, 10 | Cash, 11 | Coke, 12 | Heroin, 13 | Meth, 14 | Weed, 15 | Ammo, 16 | Armor, 17 | Barber, 18 | Clothing, 19 | Franklin, 20 | Bike, 21 | Car, 22 | Gun, 23 | HealthHeart, 24 | MakeupBrush, 25 | Mask, 26 | Michael, 27 | Tattoo, 28 | Tick, 29 | Trevor, 30 | Female, 31 | Male, 32 | LockArena, 33 | Adversary, 34 | BaseJumping, 35 | Briefcase, 36 | MissionStar, 37 | Deathmatch, 38 | Castle, 39 | Trophy, 40 | RaceFlag, 41 | RaceFlagPlane, 42 | RaceFlagBicycle, 43 | RaceFlagPerson, 44 | RaceFlagCar, 45 | RaceFlagBoatAnchor, 46 | Rockstar, 47 | Stunt, 48 | StuntPremium, 49 | RaceFlagStuntJump, 50 | Shield, 51 | TeamDeathmatch, 52 | VehicleDeathmatch, 53 | MpAmmoPickup, 54 | MpAmmo, 55 | MpCash, 56 | MpRp, 57 | MpSpectating, 58 | Sale, 59 | GlobeWhite, 60 | GlobeRed, 61 | GlobeBlue, 62 | GlobeYellow, 63 | GlobeGreen, 64 | GlobeOrange, 65 | InvArmWrestling, 66 | InvBasejump, 67 | InvMission, 68 | InvDarts, 69 | InvDeathmatch, 70 | InvDrug, 71 | InvCastle, 72 | InvGolf, 73 | InvBike, 74 | InvBoat, 75 | InvAnchor, 76 | InvCar, 77 | InvDollar, 78 | InvCoke, 79 | InvKey, 80 | InvData, 81 | InvHeli, 82 | InvHeorin, 83 | InvKeycard, 84 | InvMeth, 85 | InvBriefcase, 86 | InvLink, 87 | InvPerson, 88 | InvPlane, 89 | InvPlane2, 90 | InvQuestionmark, 91 | InvRemote, 92 | InvSafe, 93 | InvSteerWheel, 94 | InvWeapon, 95 | InvWeed, 96 | InvRaceFlagPlane, 97 | InvRaceFlagBicycle, 98 | InvRaceFlagBoatAnchor, 99 | InvRaceFlagPerson, 100 | InvRaceFlagCar, 101 | InvRaceFlagHelmet, 102 | InvShootingRange, 103 | InvSurvival, 104 | InvTeamDeathmatch, 105 | InvTennis, 106 | InvVehicleDeathmatch, 107 | AudioMute, 108 | AudioInactive, 109 | AudioVol1, 110 | AudioVol2, 111 | AudioVol3, 112 | CountryUsa, 113 | CountryUk, 114 | CountrySweden, 115 | CountryKorea, 116 | CountryJapan, 117 | CountryItaly, 118 | CountryGermany, 119 | CountryFrance, 120 | BrandAlbany, 121 | BrandAnnis, 122 | BrandBanshee, 123 | BrandBenefactor, 124 | BrandBf, 125 | BrandBollokan, 126 | BrandBravado, 127 | BrandBrute, 128 | BrandBuckingham, 129 | BrandCanis, 130 | BrandChariot, 131 | BrandCheval, 132 | BrandClassique, 133 | BrandCoil, 134 | BrandDeclasse, 135 | BrandDewbauchee, 136 | BrandDilettante, 137 | BrandDinka, 138 | BrandDundreary, 139 | BrandEmporer, 140 | BrandEnus, 141 | BrandFathom, 142 | BrandGalivanter, 143 | BrandGrotti, 144 | BrandGrotti2, 145 | BrandHijak, 146 | BrandHvy, 147 | BrandImponte, 148 | BrandInvetero, 149 | BrandJacksheepe, 150 | BrandLcc, 151 | BrandJobuilt, 152 | BrandKarin, 153 | BrandLampadati, 154 | BrandMaibatsu, 155 | BrandMammoth, 156 | BrandMtl, 157 | BrandNagasaki, 158 | BrandObey, 159 | BrandOcelot, 160 | BrandOverflod, 161 | BrandPed, 162 | BrandPegassi, 163 | BrandPfister, 164 | BrandPrincipe, 165 | BrandProgen, 166 | BrandProgen2, 167 | BrandRune, 168 | BrandSchyster, 169 | BrandShitzu, 170 | BrandSpeedophile, 171 | BrandStanley, 172 | BrandTruffade, 173 | BrandUbermacht, 174 | BrandVapid, 175 | BrandVulcar, 176 | BrandWeeny, 177 | BrandWestern, 178 | BrandWesternmotorcycle, 179 | BrandWillard, 180 | BrandZirconium, 181 | Info, 182 | } 183 | -------------------------------------------------------------------------------- /src/weapon/DlcWeaponData.ts: -------------------------------------------------------------------------------- 1 | import { WeaponHash } from '../hashes'; 2 | import { getUInt32FromUint8Array } from '../utils'; 3 | import { getStringFromUInt8Array } from '../utils'; 4 | 5 | /** 6 | * DlcWeaponData 7 | * refer1: https://github.com/citizenfx/fivem/blob/master/code/client/clrcore/External/DlcWeaponStructs.cs#L10 8 | * refer2: https://docs.fivem.net/natives/?_0xBF0FD6E56C964FCB 9 | * 10 | * int emptyCheck; //use DLC1::_IS_DLC_DATA_EMPTY on this 11 | * int padding1; 12 | * int weaponHash; 13 | * int padding2; 14 | * int unk; 15 | * int padding3; 16 | * int weaponCost; 17 | * int padding4; 18 | * int ammoCost; 19 | * int padding5; 20 | * int ammoType; 21 | * int padding6; 22 | * int defaultClipSize; 23 | * int padding7; 24 | * char nameLabel[64]; 25 | * char descLabel[64]; 26 | * char desc2Label[64]; // usually "the" + name 27 | * char upperCaseNameLabel[64]; 28 | * 29 | */ 30 | export interface DlcWeaponData { 31 | validCheck: number; 32 | weaponHash: number; 33 | unk: number; 34 | weaponCost: number; 35 | ammoCost: number; 36 | ammoType: number; 37 | defaultClipSize: number; 38 | name: string; 39 | desc: string; 40 | simpleDesc: string; 41 | upperCaseName: string; 42 | } 43 | 44 | /** 45 | * DlcWeaponData - Mapping of WeaponHash -> DlcWeaponData 46 | */ 47 | export const DlcWeaponData = new Map(); 48 | 49 | /** 50 | * Initialize DlcWeaponData, avoid calling expansive native repeatedly 51 | * 52 | */ 53 | function initializeOnce() { 54 | let isInitialized = false; 55 | 56 | return function () { 57 | if (isInitialized || IsDuplicityVersion()) { 58 | return; 59 | } 60 | 61 | // magic number based on struct DlcWeaponData 62 | const intLength = 4; 63 | const strLength = 64; 64 | 65 | const weaponCount = GetNumDlcWeapons(); 66 | for (let i = 0; i < weaponCount; i++) { 67 | const buffer = new Uint8Array(14 * intLength + 4 * strLength); 68 | 69 | // https://docs.fivem.net/natives/?_0x79923CD21BECE14E 70 | Citizen.invokeNative('0x79923CD21BECE14E', i, buffer, Citizen.returnResultAnyway()); 71 | 72 | // noinspection PointlessArithmeticExpressionJS 73 | const dlcWeaponData: DlcWeaponData = { 74 | validCheck: getUInt32FromUint8Array(buffer, 0 * intLength, 1 * intLength), 75 | weaponHash: getUInt32FromUint8Array(buffer, 2 * intLength, 3 * intLength), 76 | unk: getUInt32FromUint8Array(buffer, 4 * intLength, 5 * intLength), 77 | weaponCost: getUInt32FromUint8Array(buffer, 6 * intLength, 7 * intLength), 78 | ammoCost: getUInt32FromUint8Array(buffer, 8 * intLength, 9 * intLength), 79 | ammoType: getUInt32FromUint8Array(buffer, 10 * intLength, 11 * intLength), 80 | defaultClipSize: getUInt32FromUint8Array(buffer, 12 * intLength, 13 * intLength), 81 | name: getStringFromUInt8Array(buffer, 14 * intLength, 14 * intLength + strLength), 82 | desc: getStringFromUInt8Array( 83 | buffer, 84 | 14 * intLength + strLength, 85 | 14 * intLength + 2 * strLength, 86 | ), 87 | simpleDesc: getStringFromUInt8Array( 88 | buffer, 89 | 14 * intLength + 2 * strLength, 90 | 14 * intLength + 3 * strLength, 91 | ), 92 | upperCaseName: getStringFromUInt8Array( 93 | buffer, 94 | 14 * intLength + 3 * strLength, 95 | 14 * intLength + 4 * strLength, 96 | ), 97 | }; 98 | 99 | DlcWeaponData.set(dlcWeaponData.weaponHash, dlcWeaponData); 100 | } 101 | 102 | isInitialized = true; 103 | }; 104 | } 105 | 106 | initializeOnce()(); 107 | -------------------------------------------------------------------------------- /src/ui/Screen.ts: -------------------------------------------------------------------------------- 1 | import { Audio } from '../Audio'; 2 | import { HudColor, NotificationType } from '../enums'; 3 | import { Color, Size, String, Vector3 } from '../utils'; 4 | import { Notification } from './'; 5 | 6 | export abstract class Screen { 7 | public static get Resolution(): Size { 8 | const [width, height] = GetScreenActiveResolution(); 9 | return new Size(width, height); 10 | } 11 | 12 | public static get ScaledResolution(): Size { 13 | const height = this.Height; 14 | return new Size(height * this.AspectRatio, height); 15 | } 16 | 17 | public static get Width(): number { 18 | return this.Resolution.width; 19 | } 20 | 21 | public static get ScaledWidth(): number { 22 | return this.Height * this.AspectRatio; 23 | } 24 | 25 | public static get Height(): number { 26 | return this.Resolution.height; 27 | } 28 | 29 | public static get AspectRatio(): number { 30 | return GetAspectRatio(false); 31 | } 32 | 33 | public static showSubtitle(message: string, duration = 2500): void { 34 | const strings: string[] = String.stringToArray(message); 35 | 36 | BeginTextCommandPrint('CELL_EMAIL_BCON'); 37 | 38 | strings.forEach(element => { 39 | AddTextComponentSubstringPlayerName(element); 40 | }); 41 | 42 | EndTextCommandPrint(duration, true); 43 | } 44 | 45 | public static displayHelpTextThisFrame(message: string): void { 46 | const strings: string[] = String.stringToArray(message); 47 | 48 | BeginTextCommandDisplayHelp('CELL_EMAIL_BCON'); 49 | 50 | strings.forEach(element => { 51 | AddTextComponentSubstringPlayerName(element); 52 | }); 53 | 54 | EndTextCommandDisplayHelp(0, false, false, -1); 55 | } 56 | 57 | public static showNotification(message: string, blinking = false): Notification { 58 | const strings: string[] = String.stringToArray(message); 59 | 60 | SetNotificationTextEntry('CELL_EMAIL_BCON'); 61 | 62 | strings.forEach(element => { 63 | AddTextComponentSubstringPlayerName(element); 64 | }); 65 | 66 | return new Notification(DrawNotification(blinking, true)); 67 | } 68 | 69 | public static showAdvancedNotification( 70 | message: string, 71 | title: string, 72 | subtitle: string, 73 | iconSet: string, 74 | icon: string, 75 | bgColor: HudColor = HudColor.NONE, 76 | flashColor: Color = Color.empty, 77 | blinking = false, 78 | type: NotificationType = NotificationType.Default, 79 | showInBrief = true, 80 | sound = true, 81 | ): Notification { 82 | const strings: string[] = String.stringToArray(message); 83 | 84 | SetNotificationTextEntry('CELL_EMAIL_BCON'); 85 | 86 | strings.forEach(element => { 87 | AddTextComponentSubstringPlayerName(element); 88 | }); 89 | 90 | if (bgColor !== HudColor.NONE) { 91 | SetNotificationBackgroundColor(Number(bgColor)); 92 | } 93 | 94 | if (flashColor !== Color.empty && blinking) { 95 | SetNotificationFlashColor(flashColor.r, flashColor.g, flashColor.b, flashColor.a); 96 | } 97 | 98 | if (sound) { 99 | Audio.playSoundFrontEnd('DELETE', 'HUD_DEATHMATCH_SOUNDSET'); 100 | } 101 | 102 | SetNotificationMessage(iconSet, icon, true, Number(type), title, subtitle); 103 | return new Notification(DrawNotification(blinking, showInBrief)); 104 | } 105 | 106 | public static worldToScreen(position: Vector3, scaleWidth = false): Size { 107 | const coords = GetScreenCoordFromWorldCoord(position.x, position.y, position.z); 108 | return new Size( 109 | coords[1] * (scaleWidth ? this.ScaledWidth : this.Width), 110 | coords[2] * this.Height, 111 | ); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /src/Blip.ts: -------------------------------------------------------------------------------- 1 | import { Vector3 } from './utils'; 2 | import { BlipColor, BlipSprite } from './enums'; 3 | import { Entity, Player } from './models'; 4 | 5 | export class Blip { 6 | protected handle: number; 7 | 8 | constructor(handle: number) { 9 | this.handle = handle; 10 | } 11 | 12 | public get Handle(): number { 13 | return this.handle; 14 | } 15 | 16 | public get Position(): Vector3 { 17 | return Vector3.fromArray(GetBlipInfoIdCoord(this.handle)); 18 | } 19 | 20 | public set Position(location: Vector3) { 21 | SetBlipCoords(this.handle, location.x, location.y, location.z); 22 | } 23 | 24 | public set Rotation(rotation: number) { 25 | SetBlipRotation(this.handle, rotation); 26 | } 27 | 28 | public set Scale(scale: number) { 29 | SetBlipScale(this.handle, scale); 30 | } 31 | 32 | public get Type(): number { 33 | return GetBlipInfoIdType(this.handle); 34 | } 35 | 36 | public get Alpha(): number { 37 | return GetBlipAlpha(this.handle); 38 | } 39 | 40 | public set Alpha(alpha: number) { 41 | SetBlipAlpha(this.handle, alpha); 42 | } 43 | 44 | public set Priority(priority: number) { 45 | SetBlipPriority(this.handle, priority); 46 | } 47 | 48 | public set NumberLabel(number: number) { 49 | ShowNumberOnBlip(this.handle, number); 50 | } 51 | 52 | public get Color(): BlipColor { 53 | return GetBlipColour(this.handle); 54 | } 55 | 56 | public set Color(color: BlipColor) { 57 | SetBlipColour(this.handle, color); 58 | } 59 | 60 | public get Sprite(): BlipSprite { 61 | return GetBlipSprite(this.handle); 62 | } 63 | 64 | public set Sprite(sprite: BlipSprite) { 65 | SetBlipSprite(this.handle, sprite); 66 | } 67 | 68 | public set Display(display: number) { 69 | SetBlipDisplay(this.handle, display); 70 | } 71 | 72 | public set Name(name: string) { 73 | BeginTextCommandSetBlipName('STRING'); 74 | AddTextComponentSubstringPlayerName(name); 75 | EndTextCommandSetBlipName(this.handle); 76 | } 77 | 78 | public setNameToPlayerName(player: Player): void { 79 | SetBlipNameToPlayerName(this.handle, player.Handle); 80 | } 81 | 82 | public get Entity(): Entity | null { 83 | return Entity.fromHandle(GetBlipInfoIdEntityIndex(this.handle)); 84 | } 85 | 86 | public set ShowHeadingIndicator(show: boolean) { 87 | ShowHeadingIndicatorOnBlip(this.handle, show); 88 | } 89 | 90 | public set ShowRoute(show: boolean) { 91 | SetBlipRoute(this.handle, show); 92 | } 93 | 94 | public set IsFriendly(friendly: boolean) { 95 | SetBlipAsFriendly(this.handle, friendly); 96 | } 97 | 98 | public set IsFriend(friend: boolean) { 99 | SetBlipFriend(this.handle, friend); 100 | } 101 | 102 | public set IsCrew(crew: boolean) { 103 | SetBlipCrew(this.handle, crew); 104 | } 105 | 106 | public get IsFlashing(): boolean { 107 | return IsBlipFlashing(this.handle); 108 | } 109 | 110 | public set IsFlashing(flashing: boolean) { 111 | SetBlipFlashes(this.handle, flashing); 112 | } 113 | 114 | public get IsOnMinimap(): boolean { 115 | return IsBlipOnMinimap(this.handle); 116 | } 117 | 118 | public get IsShortRange(): boolean { 119 | return IsBlipShortRange(this.handle); 120 | } 121 | 122 | public set IsShortRange(shortRange: boolean) { 123 | SetBlipAsShortRange(this.handle, shortRange); 124 | } 125 | 126 | public removeNumberLabel(): void { 127 | HideNumberOnBlip(this.handle); 128 | } 129 | 130 | public delete(): void { 131 | if (this.exists()) { 132 | RemoveBlip(this.handle); 133 | } 134 | } 135 | 136 | public exists(): boolean { 137 | return DoesBlipExist(this.handle); 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/Audio.ts: -------------------------------------------------------------------------------- 1 | import { AudioFlag } from './enums'; 2 | import { Entity } from './models'; 3 | import { Vector3 } from './utils'; 4 | 5 | export abstract class Audio { 6 | public static playSoundAt( 7 | position: Vector3, 8 | sound: string, 9 | set?: string, 10 | generateSoundId = true, 11 | ): number { 12 | const SOUND_ID = generateSoundId ? GetSoundId() : -1; 13 | PlaySoundFromCoord( 14 | SOUND_ID, 15 | sound, 16 | position.x, 17 | position.y, 18 | position.z, 19 | set ?? '', 20 | false, 21 | 0, 22 | false, 23 | ); 24 | return SOUND_ID; 25 | } 26 | 27 | public static playSoundFromEntity( 28 | entity: Entity, 29 | sound: string, 30 | set?: string, 31 | generateSoundId = true, 32 | ): number { 33 | const SOUND_ID = generateSoundId ? GetSoundId() : -1; 34 | PlaySoundFromEntity(SOUND_ID, sound, entity.Handle, set ?? '', false, 0); 35 | return SOUND_ID; 36 | } 37 | 38 | public static playSoundFrontEnd(sound: string, set?: string, generateSoundId = true): number { 39 | const SOUND_ID = generateSoundId ? GetSoundId() : -1; 40 | PlaySoundFrontend(SOUND_ID, sound, set ?? '', false); 41 | return SOUND_ID; 42 | } 43 | 44 | public static stopSound(soundId: number): void { 45 | StopSound(soundId); 46 | } 47 | 48 | public static releaseSound(soundId: number): void { 49 | ReleaseSoundId(soundId); 50 | } 51 | 52 | public static hasSoundFinished(soundId: number): boolean { 53 | return HasSoundFinished(soundId); 54 | } 55 | 56 | public static setAudioFlag(flag: string | AudioFlag, toggle: boolean): void { 57 | if (typeof flag === 'string') { 58 | SetAudioFlag(flag, toggle); 59 | } else { 60 | SetAudioFlag(this.audioFlags[Number(flag)], toggle); 61 | } 62 | } 63 | 64 | public static playSound(soundFile: string, soundSet: string): void { 65 | this.releaseSound(this.playSoundFrontEnd(soundFile, soundSet)); 66 | } 67 | 68 | public static playMusic(musicFile: string): void { 69 | if (!this.cachedMusicFile) { 70 | CancelMusicEvent(musicFile); 71 | } 72 | this.cachedMusicFile = musicFile; 73 | TriggerMusicEvent(musicFile); 74 | } 75 | 76 | public static stopMusic(musicFile?: string): void { 77 | if (!musicFile) { 78 | if (!this.cachedMusicFile) { 79 | CancelMusicEvent(this.cachedMusicFile); 80 | this.cachedMusicFile = ''; 81 | } 82 | } else { 83 | CancelMusicEvent(musicFile ?? ''); 84 | } 85 | } 86 | 87 | protected static cachedMusicFile: string; 88 | 89 | private static readonly audioFlags: string[] = [ 90 | 'ActivateSwitchWheelAudio', 91 | 'AllowCutsceneOverScreenFade', 92 | 'AllowForceRadioAfterRetune', 93 | 'AllowPainAndAmbientSpeechToPlayDuringCutscene', 94 | 'AllowPlayerAIOnMission', 95 | 'AllowPoliceScannerWhenPlayerHasNoControl', 96 | 'AllowRadioDuringSwitch', 97 | 'AllowRadioOverScreenFade', 98 | 'AllowScoreAndRadio', 99 | 'AllowScriptedSpeechInSlowMo', 100 | 'AvoidMissionCompleteDelay', 101 | 'DisableAbortConversationForDeathAndInjury', 102 | 'DisableAbortConversationForRagdoll', 103 | 'DisableBarks', 104 | 'DisableFlightMusic', 105 | 'DisableReplayScriptStreamRecording', 106 | 'EnableHeadsetBeep', 107 | 'ForceConversationInterrupt', 108 | 'ForceSeamlessRadioSwitch', 109 | 'ForceSniperAudio', 110 | 'FrontendRadioDisabled', 111 | 'HoldMissionCompleteWhenPrepared', 112 | 'IsDirectorModeActive', 113 | 'IsPlayerOnMissionForSpeech', 114 | 'ListenerReverbDisabled', 115 | 'LoadMPData', 116 | 'MobileRadioInGame', 117 | 'OnlyAllowScriptTriggerPoliceScanner', 118 | 'PlayMenuMusic', 119 | 'PoliceScannerDisabled', 120 | 'ScriptedConvListenerMaySpeak', 121 | 'SpeechDucksScore', 122 | 'SuppressPlayerScubaBreathing', 123 | 'WantedMusicDisabled', 124 | 'WantedMusicOnMission', 125 | ]; 126 | } 127 | -------------------------------------------------------------------------------- /src/ParticleEffect.ts: -------------------------------------------------------------------------------- 1 | import { ParticleEffectAsset } from './'; 2 | import { InvertAxis, InvertAxisFlags } from './enums'; 3 | import { Color, Vector3 } from './utils'; 4 | 5 | // TODO: Lots of Matrix stuff through memory access 6 | /** 7 | * UNFINISHED! Class to manage particle effects. 8 | */ 9 | export abstract class ParticleEffect { 10 | protected readonly asset: ParticleEffectAsset; 11 | protected readonly effectName: string; 12 | protected offset: Vector3 = new Vector3(0, 0, 0); 13 | protected rotation: Vector3 = new Vector3(0, 0, 0); 14 | protected color: Color = Color.empty; 15 | protected scale = 1.0; 16 | protected range = 1.0; 17 | protected invertAxis: InvertAxis = { flags: InvertAxisFlags.None }; 18 | private handle: number; 19 | 20 | /** 21 | * Creates a particle effect. 22 | * 23 | * @param asset Particle effect asset. 24 | * @param effectName Name of effect. 25 | */ 26 | constructor(asset: ParticleEffectAsset, effectName: string) { 27 | this.handle = -1; 28 | this.asset = asset; 29 | this.effectName = effectName; 30 | } 31 | 32 | /** 33 | * Get the particle effect handle. 34 | */ 35 | public get Handle(): number { 36 | return this.handle; 37 | } 38 | 39 | /** 40 | * Get whether particle effect is currently active. 41 | */ 42 | public get IsActive(): boolean { 43 | return this.Handle !== -1 && DoesParticleFxLoopedExist(this.Handle); 44 | } 45 | 46 | public abstract start(): boolean; 47 | 48 | /** 49 | * Stop a particle effect. 50 | */ 51 | public stop(): void { 52 | if (this.IsActive) { 53 | RemoveParticleFx(this.Handle, false); 54 | } 55 | this.handle = -1; 56 | } 57 | 58 | /** 59 | * Get the rotation of the particle effect. 60 | */ 61 | public get Rotation(): Vector3 { 62 | return this.rotation; 63 | } 64 | 65 | /** 66 | * Set the rotation of the particle effect. 67 | */ 68 | public set Rotation(rotation: Vector3) { 69 | this.rotation = rotation; 70 | if (this.IsActive) { 71 | const off = this.offset; // TODO Matrix stuff to access from memory 72 | SetParticleFxLoopedOffsets( 73 | this.Handle, 74 | off.x, 75 | off.y, 76 | off.z, 77 | rotation.x, 78 | rotation.y, 79 | rotation.z, 80 | ); 81 | } 82 | } 83 | 84 | /** 85 | * Get the range of the particle effect. 86 | */ 87 | public get Range(): number { 88 | return this.range; 89 | } 90 | 91 | /** 92 | * Set the range of the particle effect. 93 | */ 94 | public set Range(range: number) { 95 | this.range = range; 96 | SetParticleFxLoopedRange(this.Handle, range); 97 | } 98 | 99 | /** 100 | * Get the invert axis flag of the particle effect. 101 | */ 102 | public get InvertAxis(): InvertAxis { 103 | return this.invertAxis; 104 | } 105 | 106 | /** 107 | * Set the inverted axis of the particle effect. 108 | */ 109 | public set InvertAxis(invertAxis: InvertAxis) { 110 | this.invertAxis = invertAxis; 111 | if (this.IsActive) { 112 | this.stop(); 113 | this.start(); 114 | } 115 | } 116 | 117 | /** 118 | * Set a paramaeter of a particle effect. 119 | * 120 | * @param parameterName Name of parameter. 121 | * @param value Value of parameter. 122 | */ 123 | public setParameter(parameterName: string, value: number): void { 124 | if (this.IsActive) { 125 | SetParticleFxLoopedEvolution(this.Handle, parameterName, value, false); 126 | } 127 | } 128 | 129 | /** 130 | * Get the name of the particle effect asset. Same as ParticleEffect.AssetName. 131 | */ 132 | public get AssetName(): string { 133 | return this.asset.AssetName; 134 | } 135 | 136 | /** 137 | * Get the name of the particle effect. 138 | */ 139 | public get EffectName(): string { 140 | return this.effectName; 141 | } 142 | 143 | /** 144 | * Return the particle effect as string. `AssetName`\\`EffectName`. 145 | */ 146 | public toString(): string { 147 | return `${this.AssetName}\\${this.EffectName}`; 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/utils/Vector2.ts: -------------------------------------------------------------------------------- 1 | // Source: https://raw.githubusercontent.com/you21979/typescript-vector/master/vector3.ts 2 | // This is an adjusted version of the Source 3 | export interface Vec2 { 4 | x: number; 5 | y: number; 6 | } 7 | 8 | export type Vector2Type = Vector2 | Vec2; 9 | 10 | export class Vector2 implements Vec2 { 11 | public static create(v1: Vec2 | number): Vector2 { 12 | if (typeof v1 === 'number') return new Vector2(v1, v1); 13 | return new Vector2(v1.x, v1.y); 14 | } 15 | 16 | /** 17 | * Creates a vector from an array of numbers 18 | * @param primitive An array of numbers (usually returned by a native) 19 | * ``` 20 | */ 21 | public static fromArray(primitive: [number, number] | number[]): Vector2 { 22 | return new Vector2(primitive[0], primitive[1]); 23 | } 24 | 25 | /** 26 | * Creates an array of vectors from an array number arrays 27 | * @param primitives A multi-dimensional array of number arrays 28 | * ``` 29 | */ 30 | public static fromArrays(primitives: [number, number][] | number[][]): Vector2[] { 31 | return primitives.map(prim => new Vector2(prim[0], prim[1])); 32 | } 33 | 34 | public static clone(v1: Vec2): Vector2 { 35 | return Vector2.create(v1); 36 | } 37 | 38 | public static add(v1: Vector2Type, v2: Vector2Type | number): Vector2 { 39 | if (typeof v2 === 'number') return new Vector2(v1.x + v2, v1.y + v2); 40 | return new Vector2(v1.x + v2.x, v1.y + v2.y); 41 | } 42 | 43 | public static subtract(v1: Vector2Type, v2: Vector2Type | number): Vector2 { 44 | if (typeof v2 === 'number') return new Vector2(v1.x - v2, v1.y - v2); 45 | return new Vector2(v1.x - v2.x, v1.y - v2.y); 46 | } 47 | 48 | public static multiply(v1: Vector2Type, v2: Vector2Type | number): Vector2 { 49 | if (typeof v2 === 'number') return new Vector2(v1.x * v2, v1.y * v2); 50 | return new Vector2(v1.x * v2.x, v1.y * v2.y); 51 | } 52 | 53 | public static divide(v1: Vector2Type, v2: Vector2Type | number): Vector2 { 54 | if (typeof v2 === 'number') return new Vector2(v1.x / v2, v1.y / v2); 55 | return new Vector2(v1.x / v2.x, v1.y / v2.y); 56 | } 57 | 58 | public static dotProduct(v1: Vector2Type, v2: Vector2Type): number { 59 | return v1.x * v2.x + v1.y * v2.y; 60 | } 61 | 62 | public static normalize(v: Vector2): Vector2 { 63 | return Vector2.divide(v, v.Length); 64 | } 65 | 66 | constructor(public x: number, public y: number) {} 67 | 68 | public clone(): Vector2 { 69 | return new Vector2(this.x, this.y); 70 | } 71 | 72 | /** 73 | * The product of the Euclidean magnitudes of this and another Vector2. 74 | * 75 | * @param v Vector2 to find Euclidean magnitude between. 76 | * @returns Euclidean magnitude with another vector. 77 | */ 78 | public distanceSquared(v: Vector2Type): number { 79 | const w: Vector2 = this.subtract(v); 80 | return Vector2.dotProduct(w, w); 81 | } 82 | 83 | /** 84 | * The distance between two Vectors. 85 | * 86 | * @param v Vector2 to find distance between. 87 | * @returns Distance between this and another vector. 88 | */ 89 | public distance(v: Vector2Type): number { 90 | return Math.sqrt(this.distanceSquared(v)); 91 | } 92 | 93 | public get normalize(): Vector2 { 94 | return Vector2.normalize(this); 95 | } 96 | 97 | public dotProduct(v: Vector2Type): number { 98 | return Vector2.dotProduct(this, v); 99 | } 100 | 101 | public add(v: Vector2Type | number): Vector2 { 102 | return Vector2.add(this, v); 103 | } 104 | 105 | public subtract(v: Vector2Type): Vector2 { 106 | return Vector2.subtract(this, v); 107 | } 108 | 109 | public multiply(v: Vector2Type | number): Vector2 { 110 | return Vector2.multiply(this, v); 111 | } 112 | 113 | public divide(v: Vector2Type | number): Vector2 { 114 | return Vector2.divide(this, v); 115 | } 116 | 117 | public toArray(): [number, number] { 118 | return [this.x, this.y]; 119 | } 120 | 121 | public replace(v: Vector2Type): void { 122 | this.x = v.x; 123 | this.y = v.y; 124 | } 125 | 126 | public get Length(): number { 127 | return Math.sqrt(this.x * this.x + this.y * this.y); 128 | } 129 | } 130 | -------------------------------------------------------------------------------- /src/enums/Blip.ts: -------------------------------------------------------------------------------- 1 | export enum BlipColor { 2 | White, 3 | Red, 4 | Green, 5 | Blue, 6 | MichaelBlue = 42, 7 | FranklinGreen, 8 | TrevorOrange, 9 | Yellow = 66, 10 | } 11 | 12 | export enum BlipSprite { 13 | Standard = 1, 14 | BigBlip, 15 | PoliceOfficer, 16 | PoliceArea, 17 | Square, 18 | Player, 19 | North, 20 | Waypoint, 21 | BigCircle, 22 | BigCircleOutline, 23 | ArrowUpOutlined, 24 | ArrowDownOutlined, 25 | ArrowUp, 26 | ArrowDown, 27 | PoliceHelicopterAnimated, 28 | Jet, 29 | Number1, 30 | Number2, 31 | Number3, 32 | Number4, 33 | Number5, 34 | Number6, 35 | Number7, 36 | Number8, 37 | Number9, 38 | Number10, 39 | GTAOCrew, 40 | GTAOFriendly, 41 | Lift = 36, 42 | RaceFinish = 38, 43 | Safehouse = 40, 44 | PoliceOfficer2, 45 | PoliceCarDot, 46 | PoliceHelicopter, 47 | ChatBubble = 47, 48 | Garage2 = 50, 49 | Drugs, 50 | Store, 51 | PoliceCar = 56, 52 | PolicePlayer = 58, 53 | PoliceStation = 60, 54 | Hospital, 55 | Helicopter = 64, 56 | StrangersAndFreaks, 57 | ArmoredTruck, 58 | TowTruck = 68, 59 | Barber = 71, 60 | LosSantosCustoms, 61 | Clothes, 62 | TattooParlor = 75, 63 | Simeon, 64 | Lester, 65 | Michael, 66 | Trevor, 67 | Rampage = 84, 68 | VinewoodTours, 69 | Lamar, 70 | Franklin = 88, 71 | Chinese, 72 | Airport, 73 | Bar = 93, 74 | BaseJump, 75 | CarWash = 100, 76 | ComedyClub = 102, 77 | Dart, 78 | FIB = 106, 79 | DollarSign = 108, 80 | Golf, 81 | AmmuNation, 82 | Exile = 112, 83 | ShootingRange = 119, 84 | Solomon, 85 | StripClub, 86 | Tennis, 87 | Triathlon = 126, 88 | OffRoadRaceFinish, 89 | Key = 134, 90 | MovieTheater, 91 | Music, 92 | Marijuana = 140, 93 | Hunting, 94 | ArmsTraffickingGround = 147, 95 | Nigel = 149, 96 | AssaultRifle, 97 | Bat, 98 | Grenade, 99 | Health, 100 | Knife, 101 | Molotov, 102 | Pistol, 103 | RPG, 104 | Shotgun, 105 | SMG, 106 | Sniper, 107 | SonicWave, 108 | PointOfInterest, 109 | GTAOPassive, 110 | GTAOUsingMenu, 111 | Link = 171, 112 | Minigun = 173, 113 | GrenadeLauncher, 114 | Armor, 115 | Castle, 116 | Camera = 184, 117 | Handcuffs = 188, 118 | Yoga = 197, 119 | Cab, 120 | Number11, 121 | Number12, 122 | Number13, 123 | Number14, 124 | Number15, 125 | Number16, 126 | Shrink, 127 | Epsilon, 128 | PersonalVehicleCar = 225, 129 | PersonalVehicleBike, 130 | Custody = 237, 131 | ArmsTraffickingAir = 251, 132 | Fairground = 266, 133 | PropertyManagement, 134 | Altruist = 269, 135 | Enemy, 136 | Chop = 273, 137 | Dead, 138 | Hooker = 279, 139 | Friend, 140 | BountyHit = 303, 141 | GTAOMission, 142 | GTAOSurvival, 143 | CrateDrop, 144 | PlaneDrop, 145 | Sub, 146 | Race, 147 | Deathmatch, 148 | ArmWrestling, 149 | AmmuNationShootingRange = 313, 150 | RaceAir, 151 | RaceCar, 152 | RaceSea, 153 | GarbageTruck = 318, 154 | SafehouseForSale = 350, 155 | Package, 156 | MartinMadrazo, 157 | EnemyHelicopter, 158 | Boost, 159 | Devin, 160 | Marina, 161 | Garage, 162 | GolfFlag, 163 | Hangar, 164 | Helipad, 165 | JerryCan, 166 | Masks, 167 | HeistSetup, 168 | Incapacitated, 169 | PickupSpawn, 170 | BoilerSuit, 171 | Completed, 172 | Rockets, 173 | GarageForSale, 174 | HelipadForSale, 175 | MarinaForSale, 176 | HangarForSale, 177 | Business = 374, 178 | BusinessForSale, 179 | RaceBike, 180 | Parachute, 181 | TeamDeathmatch, 182 | RaceFoot, 183 | VehicleDeathmatch, 184 | Barry, 185 | Dom, 186 | MaryAnn, 187 | Cletus, 188 | Josh, 189 | Minute, 190 | Omega, 191 | Tonya, 192 | Paparazzo, 193 | Crosshair, 194 | Creator = 398, 195 | CreatorDirection, 196 | Abigail, 197 | Blimp, 198 | Repair, 199 | Testosterone, 200 | Dinghy, 201 | Fanatic, 202 | Information = 407, 203 | CaptureBriefcase, 204 | LastTeamStanding, 205 | Boat, 206 | CaptureHouse, 207 | JerryCan2 = 415, 208 | RP, 209 | GTAOPlayerSafehouse, 210 | GTAOPlayerSafehouseDead, 211 | CaptureAmericanFlag, 212 | CaptureFlag, 213 | Tank, 214 | HelicopterAnimated, 215 | Plane, 216 | PlayerNoColor = 425, 217 | GunCar, 218 | Speedboat, 219 | Heist, 220 | Stopwatch = 430, 221 | DollarSignCircled, 222 | Crosshair2, 223 | DollarSignSquared = 434, 224 | } 225 | -------------------------------------------------------------------------------- /src/weaponComponent/WeaponComponent.ts: -------------------------------------------------------------------------------- 1 | import { Ped } from '../models'; 2 | import { Weapon } from '../weapon'; 3 | import { WeaponComponentHash } from './WeaponComponentHash'; 4 | import { WeaponHash } from '../hashes'; 5 | import { ComponentAttachmentPoint } from './ComponentAttachmentPoint'; 6 | import { Game } from '../Game'; 7 | import { ComponentDisplayNameByHash } from './ComponentDisplayNameByHash'; 8 | import { WeaponComponentHashesByWeaponHash } from './WeaponComponentHashesByWeaponHash'; 9 | import { ComponentAttachmentPointByHash } from './ComponentAttachmentPointByHash'; 10 | import { WeaponComponentHudStats } from './WeaponComponentHudStats'; 11 | 12 | /** 13 | * ped weapon component on weapon 14 | * 15 | */ 16 | export class WeaponComponent { 17 | protected readonly owner: Ped; 18 | protected readonly weapon: Weapon; 19 | protected readonly componentHash: WeaponComponentHash; 20 | 21 | public constructor(owner: Ped, weapon: Weapon, componentHash: WeaponComponentHash) { 22 | this.owner = owner; 23 | this.weapon = weapon; 24 | this.componentHash = componentHash; 25 | } 26 | 27 | /** 28 | * Check WeaponComponent is invalid or not 29 | * 30 | * @constructor 31 | */ 32 | public get IsInvalid(): boolean { 33 | return this.componentHash === WeaponComponentHash.Invalid; 34 | } 35 | 36 | /** 37 | * get component hash 38 | * 39 | * @constructor 40 | */ 41 | public get ComponentHash(): WeaponComponentHash { 42 | return this.componentHash; 43 | } 44 | 45 | /** 46 | * check ped has weapon component 47 | * 48 | * @constructor 49 | */ 50 | public get Active(): boolean { 51 | return HasPedGotWeaponComponent(this.owner.Handle, this.weapon.Hash, this.componentHash); 52 | } 53 | 54 | /** 55 | * give weapon component to ped 56 | * 57 | * @param value 58 | * @constructor 59 | */ 60 | public set Active(value: boolean) { 61 | if (value) { 62 | GiveWeaponComponentToPed(this.owner.Handle, this.weapon.Hash, this.componentHash); 63 | } else { 64 | RemoveWeaponComponentFromPed(this.owner.Handle, this.weapon.Hash, this.componentHash); 65 | } 66 | } 67 | 68 | /** 69 | * get component display name / label 70 | * 71 | * @constructor 72 | */ 73 | public get DisplayName(): string { 74 | return WeaponComponent.getComponentDisplayNameFromHash(this.weapon.Hash, this.componentHash); 75 | } 76 | 77 | /** 78 | * get component localized name 79 | * 80 | * @constructor 81 | */ 82 | public get LocalizedName(): string { 83 | return Game.getGXTEntry(this.DisplayName); 84 | } 85 | 86 | /** 87 | * get component attachment point 88 | * 89 | * @constructor 90 | */ 91 | public get AttachmentPoint(): ComponentAttachmentPoint { 92 | return WeaponComponent.getAttachmentPoint(this.weapon.Hash, this.componentHash); 93 | } 94 | 95 | /** 96 | * get component hud stats 97 | * 98 | * @constructor 99 | */ 100 | public get HudStats(): WeaponComponentHudStats { 101 | // eslint-disable-next-line @typescript-eslint/no-non-null-assertion 102 | return WeaponComponentHudStats.get(this.componentHash)!; 103 | } 104 | 105 | /** 106 | * get component display name / label by hash 107 | * 108 | * @param hash 109 | * @param componentHash 110 | * @constructor 111 | */ 112 | public static getComponentDisplayNameFromHash( 113 | hash: WeaponHash, 114 | componentHash: WeaponComponentHash, 115 | ): string { 116 | if (!hash) { 117 | return 'WCT_INVALID'; 118 | } 119 | 120 | return ComponentDisplayNameByHash.get(componentHash) ?? 'WCT_INVALID'; 121 | } 122 | 123 | /** 124 | * get component attachment point by WeaponHash and WeaponComponentHash 125 | * 126 | * @param weaponHash 127 | * @param componentHash 128 | * @constructor 129 | */ 130 | public static getAttachmentPoint( 131 | weaponHash: WeaponHash, 132 | componentHash: WeaponComponentHash, 133 | ): ComponentAttachmentPoint { 134 | const componentHashes = WeaponComponentHashesByWeaponHash.get(weaponHash); 135 | if (!componentHashes) { 136 | return ComponentAttachmentPoint.Invalid; 137 | } 138 | 139 | if (componentHashes.every(x => x !== componentHash)) { 140 | return ComponentAttachmentPoint.Invalid; 141 | } 142 | 143 | return ComponentAttachmentPointByHash.get(componentHash) ?? ComponentAttachmentPoint.Invalid; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /src/ParticleEffectAsset.ts: -------------------------------------------------------------------------------- 1 | import { InvertAxis, InvertAxisFlags } from './enums'; 2 | import { Entity } from './models/'; 3 | import { Vector3 } from './utils'; 4 | 5 | /** 6 | * UNFINISHED! Class that represents a particle effect asset. 7 | */ 8 | export class ParticleEffectAsset { 9 | /** 10 | * Returns the name of the asset. Same as AssetName. 11 | */ 12 | public get Asset(): string { 13 | return this.assetName; 14 | } 15 | 16 | private readonly assetName: string; 17 | 18 | constructor(assetName: string) { 19 | this.assetName = assetName; 20 | } 21 | 22 | /** 23 | * Get the name of the particle effect. 24 | */ 25 | public get AssetName(): string { 26 | return this.assetName; 27 | } 28 | 29 | /** 30 | * Get whether the particle effect has loaded into game memory. 31 | */ 32 | public get IsLoaded(): boolean { 33 | return HasNamedPtfxAssetLoaded(this.assetName); 34 | } 35 | 36 | /** 37 | * Start a particle effect at a world position. 38 | * 39 | * @param effectName Name of effect. 40 | * @param entity Entity to use effect on. 41 | * @param off Offset from entity position. 42 | * @param rot Rotation from entity position. 43 | * @param scale Size of the effect. 44 | * @param invertAxis Which axis to invert (default none). 45 | */ 46 | public startNonLoopedAtCoord( 47 | effectName: string, 48 | pos: Vector3, 49 | rot: Vector3 = new Vector3(0, 0, 0), 50 | scale = 1.0, 51 | invertAxis: InvertAxis = { flags: InvertAxisFlags.None }, 52 | ): boolean { 53 | if (!this.setNextCall()) { 54 | return false; 55 | } 56 | const invertAxisFlags = invertAxis.flags; 57 | SetPtfxAssetNextCall(this.assetName); 58 | return ( 59 | StartParticleFxLoopedAtCoord( 60 | effectName, 61 | pos.x, 62 | pos.y, 63 | pos.z, 64 | rot.x, 65 | rot.y, 66 | rot.z, 67 | scale, 68 | !!(invertAxisFlags & InvertAxisFlags.X), 69 | !!(invertAxisFlags & InvertAxisFlags.Y), 70 | !!(invertAxisFlags & InvertAxisFlags.Z), 71 | false, 72 | ) > 0 73 | ); 74 | } 75 | 76 | /** 77 | * Start a particle effect on an entity 78 | * 79 | * @param effectName Name of effect. 80 | * @param entity Entity to use effect on. 81 | * @param off Offset from entity position. 82 | * @param rot Rotation from entity position. 83 | * @param scale Size of the effect. 84 | * @param invertAxis Which axis to invert (default none). 85 | */ 86 | public startNonLoopedOnEntity( 87 | effectName: string, 88 | entity: Entity, 89 | off: Vector3 = new Vector3(0, 0, 0), 90 | rot: Vector3 = new Vector3(0, 0, 0), 91 | scale = 1.0, 92 | invertAxis: InvertAxis = { flags: InvertAxisFlags.None }, 93 | ): boolean { 94 | if (!this.setNextCall()) { 95 | return false; 96 | } 97 | const invertAxisFlags = invertAxis.flags; 98 | SetPtfxAssetNextCall(this.assetName); 99 | return !!StartParticleFxLoopedOnEntity( 100 | effectName, 101 | entity.Handle, 102 | off.x, 103 | off.y, 104 | off.z, 105 | rot.x, 106 | rot.y, 107 | rot.z, 108 | scale, 109 | !!(invertAxisFlags & InvertAxisFlags.X), 110 | !!(invertAxisFlags & InvertAxisFlags.Y), 111 | !!(invertAxisFlags & InvertAxisFlags.Z), 112 | ); 113 | } 114 | 115 | /** 116 | * Load a particle effect into the game memory. 117 | * 118 | * @param timeout Max time to load Particle Effect 119 | */ 120 | public request(timeout: number): Promise { 121 | return new Promise(resolve => { 122 | if (!this.IsLoaded) { 123 | RequestNamedPtfxAsset(this.assetName); 124 | const start = GetGameTimer(); 125 | const interval = setInterval(() => { 126 | if (this.IsLoaded || GetGameTimer() - start >= timeout) { 127 | clearInterval(interval); 128 | resolve(this.IsLoaded); 129 | } 130 | }, 0); 131 | } else { 132 | resolve(this.IsLoaded); 133 | } 134 | }); 135 | } 136 | 137 | /** 138 | * Allow game engine to safely unload particle effect model from memory. 139 | */ 140 | public markAsNoLongerNeeded(): void { 141 | RemoveNamedPtfxAsset(this.assetName); 142 | } 143 | 144 | public toString(): string { 145 | return this.assetName; 146 | } 147 | 148 | private setNextCall(): boolean { 149 | if (!this.IsLoaded) { 150 | RequestNamedPtfxAsset(this.assetName); 151 | } else { 152 | SetPtfxAssetNextCall(this.assetName); 153 | return true; 154 | } 155 | return false; 156 | } 157 | } 158 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Notice for breaking changes 2 | This library is going to be undergoing a rewrite over the next few months, backwards compatibility will not be guaranteed, if you want version thats guaranteed stable please look use 1.7.* 3 | 4 |

native-wrappers-client

5 | 6 |

7 | :fire: A Javascript/Typescript wrapper for the FiveM natives :video_game: 8 |
9 |
10 | 11 | License: MIT 12 | 13 | 14 | npm version 15 | 16 | 17 | 18 | 19 | 20 | Workflow Status 21 | 22 | 23 | Last commit 24 | 25 |

26 | 27 |

28 | Documentation 29 | - 30 | Forum 31 |

32 | 33 | This is a continuation of [fivem-js](https://github.com/d0p3t/fivem-js), who's maintainer has sadly passed away. 34 | 35 | This project is in no way affiliated with FiveM or the Cfx Collective. 36 | 37 | Functionality of this wrapper is **based on the FiveM C# wrapper** - [link](https://github.com/citizenfx/fivem/tree/master/code/client/clrcore/External). It's a feature-rich set of helper classes, objects, and functions to help you develop your project faster. 38 | 39 | ## Features 40 | 41 | - No runtime dependencies 42 | - Abstracts common used FiveM practices 43 | - Entity management through class objects (i.e. `Vehicle` and `Ped` entities) 44 | - UI elements such as `scaleforms` and loading `prompts` 45 | - Audio, Blips, Cameras and more... 46 | 47 | In other words, whatever the FiveM C# wrapper can do, this package can as well and more! 48 | 49 | ## Download & Install 50 | 51 | `yarn add @nativewrappers/client` 52 | 53 | or 54 | 55 | `npm i @nativewrappers/client` 56 | 57 | https://www.npmjs.com/package/@nativewrappers/client 58 | 59 | 60 | ## Simple Usage 61 | 62 | See [here](https://github.com/AvarianKnight/native-wrappers-client/tree/master/examples) for example projects. 63 | 64 | ### Typescript 65 | 66 | ```ts 67 | import * as Cfx from '@nativewrappers/client'; 68 | 69 | RegisterCommand( 70 | 'adder', 71 | async (source: number, args: string[]) => { 72 | const vehicle = await Cfx.World.createVehicle( 73 | new Cfx.Model('adder'), 74 | new Cfx.Vector3(1, 2, 3), 75 | 4, 76 | ); 77 | Cfx.Game.PlayerPed.setIntoVehicle(vehicle, Cfx.VehicleSeat.Driver); 78 | }, 79 | false, 80 | ); 81 | ``` 82 | 83 | You can also individually import classes. 84 | 85 | ```typescript 86 | import { World } from '@nativewrappers/client/lib/World'; 87 | ``` 88 | 89 | ### Javascript 90 | 91 | ```js 92 | /// 93 | /// 94 | 95 | const Cfx = require('@nativewrappers/client'); 96 | 97 | RegisterCommand( 98 | 'adder', 99 | async (source, args) => { 100 | const vehicle = await Cfx.World.createVehicle( 101 | new Cfx.Model('adder'), 102 | new Cfx.Vector3(1, 2, 3), 103 | 4, 104 | ); 105 | Cfx.Game.PlayerPed.setIntoVehicle(vehicle, Cfx.VehicleSeat.Driver); 106 | }, 107 | false, 108 | ); 109 | ``` 110 | 111 | ## Contributing 112 | 113 | You are more than welcome to contribute to this project by submitting a pull request and creating issues. 114 | 115 | Please checkout [CONTRIBUTING.md](./CONTRIBUTING.md) for our contributing guidelines. 116 | 117 | ## License 118 | 119 | MIT with customization. See [LICENSE](https://github.com/AvarianKnight/native-wrappers-client/blob/master/LICENSE) 120 | -------------------------------------------------------------------------------- /src/Rope.ts: -------------------------------------------------------------------------------- 1 | import { Entity } from './models'; 2 | import { Vector3 } from './utils'; 3 | 4 | /** 5 | * Class to manage invisible ropes between entities. 6 | */ 7 | export class Rope { 8 | /** 9 | * Id of rope entity. 10 | */ 11 | private readonly handle: number; 12 | 13 | /** 14 | * Create a rope object based on an existing rope in the world. 15 | * 16 | * @param handle entity Id of rope. 17 | */ 18 | constructor(handle: number) { 19 | this.handle = handle; 20 | } 21 | 22 | public get Handle(): number { 23 | return this.handle; 24 | } 25 | /** 26 | * Get the length of the rope. 27 | * 28 | * @returns The rope length. 29 | */ 30 | public get Length(): number { 31 | return GetRopeLength(this.handle); 32 | } 33 | 34 | /** 35 | * Sets the length of the rope. 36 | * 37 | * @param length Desired new length of rope. 38 | */ 39 | public set Length(length: number) { 40 | RopeForceLength(this.handle, length); 41 | } 42 | 43 | /** 44 | * Get the number of vertices on the rope. 45 | * 46 | * @returns Returns the number of vertices. 47 | */ 48 | public get VertexCount(): number { 49 | return GetRopeVertexCount(this.handle); 50 | } 51 | 52 | /** 53 | * Resets the length of the rope to it's length upon object creation or a length of 1. 54 | * 55 | * @param reset Whether to reset the length to it's original length or 1. 56 | */ 57 | public resetLength(reset: boolean): void { 58 | RopeResetLength(this.handle, reset ? 1 : this.Length); 59 | } 60 | 61 | /** 62 | * Activates world physics on the rope object. 63 | */ 64 | public activatePhysics(): void { 65 | ActivatePhysics(this.handle); 66 | } 67 | 68 | /** 69 | * Attach the rope to an entity. 70 | * 71 | * @param entity Entity to attach the rope to. 72 | * @param position Location where the rope is to be attached. 73 | */ 74 | public attachEntity(entity: Entity, position: Vector3): void { 75 | AttachRopeToEntity(this.handle, entity.Handle, position.x, position.y, position.z, false); 76 | } 77 | 78 | /** 79 | * Attach the rope between two entities at given locations on the entities. 80 | * 81 | * @param entityOne The first entity to attach to. 82 | * @param positionOne Where on the first entity to attach the rope to. 83 | * @param entityTwo The second entity to attach to. 84 | * @param positionTwo Where on the second entity to attach the rope to. 85 | * @param length The desired length of the rope between the two entities. 86 | */ 87 | public attachEntities( 88 | entityOne: Entity, 89 | positionOne: Vector3, 90 | entityTwo: Entity, 91 | positionTwo: Vector3, 92 | length: number, 93 | ): void { 94 | AttachEntitiesToRope( 95 | this.handle, 96 | entityOne.Handle, 97 | entityTwo.Handle, 98 | positionOne.x, 99 | positionOne.y, 100 | positionOne.z, 101 | positionTwo.x, 102 | positionTwo.y, 103 | positionTwo.z, 104 | length, 105 | false, 106 | false, 107 | '', 108 | '', 109 | ); 110 | } 111 | 112 | /** 113 | * Detach the rope from an entity. 114 | * 115 | * @param entity Entity to detach the rope from. 116 | */ 117 | public detachEntity(entity: Entity): void { 118 | DetachRopeFromEntity(this.handle, entity.Handle); 119 | } 120 | 121 | /** 122 | * Pin a vertex of the rope to a certain location. 123 | * 124 | * @param vertex Vertex to pin. 125 | * @param position Location to pin the vertex to. 126 | */ 127 | public pinVertex(vertex: number, position: Vector3): void { 128 | PinRopeVertex(this.handle, vertex, position.x, position.y, position.z); 129 | } 130 | 131 | /** 132 | * Unpin a specified vertex from it's current pinned location (if any). 133 | * 134 | * @param vertex Vertex to unpin. 135 | */ 136 | public unpinVertex(vertex: number): void { 137 | UnpinRopeVertex(this.handle, vertex); 138 | } 139 | 140 | /** 141 | * Return the world location of a specified vertex on the rope. 142 | * 143 | * @param vertex Vertex to get location from. 144 | * @returns The vector location of the vertex. 145 | */ 146 | public getVertexCoord(vertex: number): Vector3 { 147 | return Vector3.fromArray(GetRopeVertexCoord(this.handle, vertex)); 148 | } 149 | 150 | /** 151 | * Delete the rope from the world. This does not delete the rope object. 152 | */ 153 | public delete(): void { 154 | DeleteRope(this.handle); 155 | } 156 | 157 | /** 158 | * Check if the rope still exists in the world based on it's handle. 159 | * 160 | * @returns Whether the rope exists or not. 161 | */ 162 | public exists(): boolean { 163 | const [exists] = DoesRopeExist(this.handle); 164 | return exists; 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /src/hashes/WeaponHash.ts: -------------------------------------------------------------------------------- 1 | export enum WeaponHash { 2 | // melee 3 | Dagger = -1834847097, 4 | Bat = -1786099057, 5 | Bottle = -102323637, 6 | Crowbar = -2067956739, 7 | Unarmed = -1569615261, 8 | Flashlight = -1951375401, 9 | GolfClub = 1141786504, 10 | Hammer = 1317494643, 11 | Hatchet = -102973651, 12 | KnuckleDuster = -656458692, 13 | Knife = -1716189206, 14 | Machete = -581044007, 15 | SwitchBlade = -538741184, 16 | Nightstick = 1737195953, 17 | Wrench = 419712736, 18 | BattleAxe = -853065399, 19 | PoolCue = -1810795771, 20 | StoneHatchet = 940833800, 21 | 22 | // handguns 23 | Pistol = 453432689, 24 | PistolMk2 = 3219281620, 25 | CombatPistol = 1593441988, 26 | APPistol = 584646201, 27 | StunGun = 911657153, 28 | StunGunMp = 1171102963, 29 | Pistol50 = -1716589765, 30 | SNSPistol = -1076751822, 31 | SNSPistolMk2 = -2009644972, 32 | HeavyPistol = -771403250, 33 | VintagePistol = 137902532, 34 | FlareGun = 1198879012, 35 | MarksmanPistol = -598887786, 36 | Revolver = -1045183535, 37 | RevolverMk2 = -879347409, 38 | DoubleAction = -1746263880, 39 | RayPistol = -1355376991, 40 | CeramicPistol = 727643628, 41 | NavyRevolver = -1853920116, 42 | GadgetPistol = 1470379660, 43 | 44 | // sub-machine guns 45 | MicroSMG = 324215364, 46 | SMG = 736523883, 47 | SMGMk2 = 2024373456, 48 | AssaultSMG = -270015777, 49 | CombatPDW = 171789620, 50 | MachinePistol = -619010992, 51 | MiniSMG = -1121678507, 52 | RayCarbine = 1198256469, 53 | 54 | // Light Machine Guns 55 | MG = -1660422300, 56 | CombatMG = 2144741730, 57 | CombatMGMk2 = 3686625920, 58 | Gusenberg = 1627465347, 59 | 60 | // shotguns 61 | PumpShotgun = 487013001, 62 | PumpShotgunMk2 = 1432025498, 63 | SawnOffShotgun = 2017895192, 64 | AssaultShotgun = -494615257, 65 | BullpupShotgun = -1654528753, 66 | Musket = -1466123874, 67 | HeavyShotgun = 984333226, 68 | DoubleBarrelShotgun = -275439685, 69 | SweeperShotgun = 317205821, 70 | CombatShotgun = 94989220, 71 | 72 | // Assault Rifles 73 | AssaultRifle = -1074790547, 74 | AssaultRifleMk2 = 961495388, 75 | CarbineRifle = -2084633992, 76 | CarbineRifleMk2 = 4208062921, 77 | AdvancedRifle = -1357824103, 78 | SpecialCarbine = -1063057011, 79 | SpecialCarbineMk2 = -1768145561, 80 | BullpupRifle = 2132975508, 81 | BullpupRifleMk2 = -2066285827, 82 | CompactRifle = 1649403952, 83 | MilitaryRifle = -1658906650, 84 | HeavyRifle = -947031628, 85 | 86 | // Sniper Rifles 87 | SniperRifle = 100416529, 88 | HeavySniper = 205991906, 89 | HeavySniperMk2 = 177293209, 90 | MarksmanRifle = -952879014, 91 | MarksmanRifleMk2 = 1785463520, 92 | 93 | // Heavy Weapons 94 | RPG = -1312131151, 95 | GrenadeLauncher = -1568386805, 96 | GrenadeLauncherSmoke = 1305664598, 97 | Minigun = 1119849093, 98 | Firework = 2138347493, 99 | Railgun = 1834241177, 100 | HomingLauncher = 1672152130, 101 | CompactGrenadeLauncher = 125959754, 102 | RayMinigun = -1238556825, 103 | EmpLauncher = -618237638, 104 | 105 | // Throwables 106 | Grenade = -1813897027, 107 | BZGas = -1600701090, 108 | Molotov = 615608432, 109 | StickyBomb = 741814745, 110 | ProximityMine = -1420407917, 111 | Snowball = 126349499, 112 | PipeBomb = -1169823560, 113 | Ball = 600439132, 114 | SmokeGrenade = -37975472, 115 | Flare = 1233104067, 116 | 117 | // Miscellaneous 118 | PetrolCan = 883325847, 119 | Parachute = -72657034, 120 | FireExtinguisher = 101631238, 121 | HazardCan = -1168940174, 122 | FertilizerCan = 406929569, 123 | } 124 | 125 | export enum VehicleWeaponHash { 126 | Invalid = -1, 127 | Tank = 1945616459, 128 | SpaceRocket = -123497569, 129 | PlaneRocket = -821520672, 130 | PlayerLaser = -268631733, 131 | PlayerBullet = 1259576109, 132 | PlayerBuzzard = 1186503822, 133 | PlayerHunter = -1625648674, 134 | PlayerLazer = -494786007, 135 | EnemyLaser = 1566990507, 136 | SearchLight = -844344963, 137 | Radar = -764006018, 138 | } 139 | 140 | // TODO: Convert this to uint instead of hash 141 | export enum AmmoType { 142 | Melee = 0, 143 | FireExtinguisher = 0x5106b43c, 144 | Flare = 0x6bccf76f, 145 | FlareGun = 0x45f0e965, 146 | PetrolCan = 0xca6318a1, 147 | Shotgun = 0x90083d3b, 148 | Pistol = 0x743d4f54, 149 | Ball = 0xff956666, 150 | Snowball = 0x8218416d, 151 | Sniper = 0x4c98087b, 152 | AssaultRifle = 0xd05319f, 153 | SMG = 0x6c7d23b8, 154 | Molotov = 0x5633f9d5, 155 | StunGun = 0xb02eade0, 156 | MG = 0x6aa1343f, 157 | GrenadeLauncher = 0x3bcca5ee, 158 | RPG = 0x67dd81f2, 159 | Minigun = 0x9fc5c882, 160 | Firework = 0xaf23ee0f, 161 | Railgun = 0x794446fd, 162 | HomingLauncher = 0x99150e2d, 163 | Grenade = 0x3bd313b1, 164 | StickyBomb = 0x5424b617, 165 | ProximityMine = 0xaf2208a7, 166 | PipeBomb = 0x155663f8, 167 | SmokeGrenade = 0xe60e08a6, 168 | BZGas = 0x9b747ea4, 169 | } 170 | -------------------------------------------------------------------------------- /src/ui/menu/items/UIMenuListItem.ts: -------------------------------------------------------------------------------- 1 | import { Menu, Sprite, Text } from '../../'; 2 | import { Alignment, Font } from '../../../enums'; 3 | import { Color, LiteEvent, Point, Size, String } from '../../../utils'; 4 | import { ListItem } from '../modules/'; 5 | import { UIMenuItem } from './'; 6 | 7 | export class UIMenuListItem extends UIMenuItem { 8 | public readonly listChanged = new LiteEvent(); 9 | public readonly listSelected = new LiteEvent(); 10 | 11 | protected supportsRightBadge = false; 12 | protected supportsRightLabel = false; 13 | 14 | private _itemText: Text; 15 | private _leftArrow: Sprite; 16 | private _rightArrow: Sprite; 17 | 18 | private _index = 0; 19 | private _arrowOnlyOnSelected = false; 20 | private _items: ListItem[] = []; 21 | private _textWidth = 0; 22 | 23 | constructor( 24 | text: string, 25 | items: ListItem[], 26 | startIndex = 0, 27 | description?: string, 28 | arrowOnlyOnSelected = true, 29 | ) { 30 | super(text, description); 31 | this._leftArrow = new Sprite('commonmenu', 'arrowleft', new Point(), new Size(30, 30)); 32 | this._rightArrow = new Sprite('commonmenu', 'arrowright', new Point(), new Size(30, 30)); 33 | this._itemText = new Text( 34 | '', 35 | new Point(), 36 | 0.35, 37 | Color.white, 38 | Font.ChaletLondon, 39 | Alignment.Right, 40 | ); 41 | this.ArrowOnlyOnSelected = arrowOnlyOnSelected; 42 | this.Items = items; 43 | this.Index = startIndex; 44 | } 45 | 46 | public get Items(): ListItem[] { 47 | return this._items; 48 | } 49 | 50 | public set Items(value: ListItem[]) { 51 | if (!value) { 52 | throw new Error("Items can't be null"); 53 | } 54 | this._items = value; 55 | } 56 | 57 | public get SelectedItem(): ListItem { 58 | return this.Items[this.Index]; 59 | } 60 | 61 | public set SelectedItem(value: ListItem) { 62 | const index = this.Items.findIndex(i => i.id === value.id); 63 | if (index >= 0) { 64 | this.Index = index; 65 | } 66 | } 67 | 68 | public get SelectedValue(): unknown { 69 | const item = this.SelectedItem; 70 | return item ? item.value : null; 71 | } 72 | 73 | public get Index(): number { 74 | return this._index % this.Items.length; 75 | } 76 | 77 | public set Index(value: number) { 78 | if (!this._items.length) { 79 | return; 80 | } 81 | value = value < 0 ? this._items.length - 1 : value > this._items.length - 1 ? 0 : value; 82 | this._index = value; 83 | this._textWidth = 0; 84 | } 85 | 86 | public get ArrowOnlyOnSelected(): boolean { 87 | return this._arrowOnlyOnSelected; 88 | } 89 | 90 | public set ArrowOnlyOnSelected(value: boolean) { 91 | this._arrowOnlyOnSelected = value; 92 | } 93 | 94 | public get IsMouseInBoundsOfLeftArrow(): boolean { 95 | return this.parent 96 | ? this.parent.isMouseInBounds(this._leftArrow.pos, this._leftArrow.size) 97 | : false; 98 | } 99 | 100 | public get IsMouseInBoundsOfRightArrow(): boolean { 101 | return this.parent 102 | ? this.parent.isMouseInBounds(this._rightArrow.pos, this._rightArrow.size) 103 | : false; 104 | } 105 | 106 | public setVerticalPosition(y: number): void { 107 | const yOffset = y + this.offset.Y + 147; 108 | this._leftArrow.pos.Y = yOffset; 109 | this._rightArrow.pos.Y = yOffset; 110 | this._itemText.pos.Y = yOffset; 111 | super.setVerticalPosition(y); 112 | } 113 | 114 | public draw(): void { 115 | super.draw(); 116 | if (this._textWidth === undefined) { 117 | const caption = this._getSelectedItemCaption(); 118 | this._itemText.caption = caption; 119 | this._textWidth = String.measureString( 120 | caption, 121 | this._itemText.font, 122 | this._itemText.scale, 123 | Menu.screenWidth, 124 | ); 125 | } 126 | 127 | this._rightArrow.pos.X = this.offset.X + (this.parent ? this.parent.WidthOffset : 0) + 400; 128 | this._itemText.pos.X = this._rightArrow.pos.X + 5; 129 | 130 | this._itemText.color = this.enabled 131 | ? this.selected 132 | ? this.HighlightedForeColor 133 | : this.ForeColor 134 | : new Color(255, 163, 159, 148); 135 | 136 | if (this._arrowOnlyOnSelected && !this.selected) { 137 | this._itemText.pos.X += this._rightArrow.size.width / 2; 138 | } else { 139 | this._leftArrow.color = this._itemText.color; 140 | this._rightArrow.color = this._itemText.color; 141 | 142 | this._leftArrow.pos.X = 143 | this._itemText.pos.X - this._textWidth - this._leftArrow.size.width + 5; 144 | 145 | this._leftArrow.draw(Menu.screenResolution); 146 | this._rightArrow.draw(Menu.screenResolution); 147 | } 148 | 149 | this._itemText.draw(undefined, Menu.screenResolution); 150 | } 151 | 152 | private _getSelectedItemCaption(): string { 153 | const item = this.SelectedItem; 154 | return item ? item.name : ''; 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/GameplayCamera.ts: -------------------------------------------------------------------------------- 1 | import { Camera } from './Camera'; 2 | import { CameraShake } from './enums'; 3 | import { Vector3 } from './utils'; 4 | 5 | /** 6 | * The current rendering gameplay camera 7 | */ 8 | export abstract class GameplayCamera { 9 | /** 10 | * Get the world position of gameplay camera. 11 | */ 12 | public static get Position(): Vector3 { 13 | return Vector3.fromArray(GetGameplayCamCoords()); 14 | } 15 | 16 | /** 17 | * Get the rotation of gameplay camera. 18 | */ 19 | public static get Rotation(): Vector3 { 20 | return Vector3.fromArray(GetGameplayCamRot(2)); 21 | } 22 | 23 | /** 24 | * Get the forward vector of gameplay camera. 25 | */ 26 | public static get ForwardVector(): Vector3 { 27 | const rotation = Vector3.multiply(this.Rotation, Math.PI / 180); 28 | return Vector3.normalize( 29 | new Vector3( 30 | -Math.sin(rotation.z) * Math.abs(Math.cos(rotation.x)), 31 | Math.cos(rotation.z) * Math.abs(Math.cos(rotation.x)), 32 | Math.sin(rotation.x), 33 | ), 34 | ); 35 | } 36 | 37 | /** 38 | * Get the pitch of the gameplay camera relative to player. 39 | */ 40 | public static get RelativePitch(): number { 41 | return GetGameplayCamRelativePitch(); 42 | } 43 | 44 | /** 45 | * Set gameplay camera pitch relative to player. 46 | */ 47 | public static set RelativePitch(pitch: number) { 48 | SetGameplayCamRelativePitch(pitch, 1); 49 | } 50 | 51 | /** 52 | * Get heading of gameplay camera. 53 | */ 54 | public static get RelativeHeading(): number { 55 | return GetGameplayCamRelativeHeading(); 56 | } 57 | 58 | /** 59 | * Get heading of gameplay camera. 60 | */ 61 | public static set RelativeHeading(heading: number) { 62 | SetGameplayCamRelativeHeading(heading); 63 | } 64 | 65 | /** 66 | * Clamps the yaw of the gameplay camera. 67 | * 68 | * @param min The minimum yaw value. 69 | * @param max The maximum yaw value. 70 | */ 71 | public static clampYaw(min: number, max: number): void { 72 | ClampGameplayCamYaw(min, max); 73 | } 74 | 75 | /** 76 | * Clamps the pitch of the gameplay camera. 77 | * 78 | * @param min The minimum pitch value. 79 | * @param max The maximum pitch value. 80 | */ 81 | public static clampPitch(min: number, max: number): void { 82 | ClampGameplayCamPitch(min, max); 83 | } 84 | 85 | /** 86 | * Gets zoom of the gameplay camera. 87 | */ 88 | public static get Zoom(): number { 89 | return GetGameplayCamZoom(); 90 | } 91 | 92 | /** 93 | * Gets field of view of the gameplay camera. 94 | */ 95 | public static get FieldOfView(): number { 96 | return GetGameplayCamFov(); 97 | } 98 | 99 | /** 100 | * Gets a value indicating whether the gameplay camera is rendering. 101 | * 102 | * @returns true if the gameplay camera is rendering; otherwise, false. 103 | */ 104 | public static get IsRendering(): boolean { 105 | return IsGameplayCamRendering(); 106 | } 107 | 108 | /** 109 | * Gets a value indicating whether the aiming camera is rendering. 110 | * 111 | * @returns true if the aiming camera is rendering; otherwise, false. 112 | */ 113 | public static get IsAimCamActive(): boolean { 114 | return IsAimCamActive(); 115 | } 116 | 117 | /** 118 | * Gets a value indicating whether the first person aiming camera is rendering. 119 | * 120 | * @returns true if the first person aiming camera is rendering; otherwise, false. 121 | */ 122 | public static get IsFirstPersonAimCamActive(): boolean { 123 | return IsFirstPersonAimCamActive(); 124 | } 125 | 126 | /** 127 | * Gets a value indicating whether the gameplay camera is looking behind. 128 | * 129 | * @returns true if the gameplay camera is looking behind; otherwise, false. 130 | */ 131 | public static get IsLookingBehind(): boolean { 132 | return IsGameplayCamLookingBehind(); 133 | } 134 | 135 | /** 136 | * Shakes the gameplay camera. 137 | * 138 | * @param shakeType Type of the shake to apply. 139 | * @param amplitude The amplitude of the shaking. 140 | */ 141 | public static shake(shakeType: CameraShake, amplitude: number): void { 142 | ShakeGameplayCam(Camera.shakeNames[Number(shakeType)], amplitude); 143 | } 144 | 145 | /** 146 | * Stops shaking the gameplay camera. 147 | */ 148 | public static stopShaking(): void { 149 | StopGameplayCamShaking(true); 150 | } 151 | 152 | /** 153 | * Gets a value indicating whether the gameplay camera is shaking. 154 | * 155 | * @returns true if the gameplay camera is shaking; otherwise, false. 156 | */ 157 | public static get IsShaking(): boolean { 158 | return IsGameplayCamShaking(); 159 | } 160 | 161 | /** 162 | * Sets the shake amplitude for the gameplay camera. 163 | */ 164 | public static set ShakeAmplitude(value: number) { 165 | SetGameplayCamShakeAmplitude(value); 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /src/ui/Text.ts: -------------------------------------------------------------------------------- 1 | import { Alignment, Font } from '../enums'; 2 | import { Color, Point, Size } from '../utils'; 3 | import { IDrawable, Screen } from './'; 4 | 5 | export class Text implements IDrawable { 6 | public static draw( 7 | caption: string, 8 | pos: Point, 9 | scale = 1, 10 | color = Color.white, 11 | font = Font.ChaletLondon, 12 | alignment = Alignment.Left, 13 | dropShadow = false, 14 | outline = false, 15 | wordWrap?: Size, 16 | resolution?: Size, 17 | ): void { 18 | resolution = resolution || new Size(Screen.ScaledWidth, Screen.Height); 19 | const x = pos.X / resolution.width; 20 | const y = pos.Y / resolution.height; 21 | 22 | SetTextFont(Number(font)); 23 | SetTextScale(1.0, scale); 24 | SetTextColour(color.r, color.g, color.b, color.a); 25 | 26 | if (dropShadow) { 27 | SetTextDropshadow(2, 0, 0, 0, 0); 28 | } 29 | 30 | if (outline) { 31 | SetTextOutline(); 32 | } 33 | 34 | switch (alignment) { 35 | case Alignment.Centered: 36 | SetTextCentre(true); 37 | break; 38 | case Alignment.Right: 39 | SetTextRightJustify(true); 40 | if (!wordWrap) { 41 | SetTextWrap(0.0, x); 42 | } 43 | break; 44 | } 45 | 46 | if (wordWrap) { 47 | SetTextWrap(x, (pos.X + wordWrap.width) / resolution.width); 48 | } 49 | 50 | SetTextEntry('STRING'); 51 | Text.addLongString(caption); 52 | DrawText(x, y); 53 | } 54 | 55 | public static addLongString(str: string): void { 56 | const strLen = 99; 57 | for (let i = 0; i < str.length; i += strLen) { 58 | const substr = str.substr(i, Math.min(strLen, str.length - i)); 59 | AddTextComponentSubstringPlayerName(substr); 60 | } 61 | } 62 | 63 | public caption: string; 64 | public pos: Point; 65 | public scale: number; 66 | public color: Color; 67 | public font: Font; 68 | public alignment: Alignment; 69 | public dropShadow: boolean; 70 | public outline: boolean; 71 | public wordWrap: Size; 72 | 73 | /** 74 | * 75 | * @param caption Text to display 76 | * @param pos Position of text relative to alignment. In pixels. 77 | * @param scale Size of text. Default 1.0 78 | * @param color Color of text. Default black. 79 | * @param font Font of text. Default Chalet London. 80 | * @param alignment Alignment of text. Default Left. 81 | * @param dropShadow 82 | * @param outline 83 | * @param wordWrap 84 | */ 85 | constructor( 86 | caption: string, 87 | pos: Point, 88 | scale = 1, 89 | color = Color.white, 90 | font = Font.ChaletLondon, 91 | alignment = Alignment.Left, 92 | dropShadow = false, 93 | outline = false, 94 | wordWrap: Size = new Size(500, 300), 95 | ) { 96 | this.caption = caption; 97 | this.pos = pos; 98 | this.scale = scale; 99 | this.color = color; 100 | this.font = font; 101 | this.alignment = alignment; 102 | this.dropShadow = dropShadow; 103 | this.outline = outline; 104 | this.wordWrap = wordWrap; 105 | } 106 | 107 | public draw(offset?: Size, resolution?: Size): void; 108 | public draw( 109 | caption: string, 110 | pos: Point, 111 | scale: number, 112 | color?: Color, 113 | font?: Font, 114 | alignment?: Alignment, 115 | dropShadow?: boolean, 116 | outline?: boolean, 117 | wordWrap?: Size, 118 | resolution?: Size, 119 | ): void; 120 | public draw( 121 | arg1?: Size | string, 122 | arg2?: Size | Point, 123 | scale?: number, 124 | color?: Color, 125 | font?: Font, 126 | alignment?: Alignment, 127 | dropShadow?: boolean, 128 | outline?: boolean, 129 | wordWrap?: Size, 130 | resolution?: Size, 131 | ): void { 132 | resolution = arg2 instanceof Size ? arg2 : resolution; 133 | 134 | if (scale === undefined) { 135 | if (arg1 && arg1 instanceof Size) { 136 | arg2 = new Point(this.pos.X + arg1.width, this.pos.Y + arg1.height); 137 | } else { 138 | arg2 = this.pos; 139 | } 140 | arg1 = this.caption; 141 | scale = this.scale; 142 | color = this.color; 143 | font = this.font; 144 | alignment = this.alignment; 145 | dropShadow = this.dropShadow; 146 | outline = this.outline; 147 | wordWrap = this.wordWrap; 148 | } else { 149 | arg1 = arg1 || this.caption; 150 | if (!arg2) { 151 | arg2 = this.pos; 152 | } else { 153 | arg2 = arg2 as Point; 154 | } 155 | scale = scale !== undefined && scale !== null ? scale : this.scale; 156 | color = color || this.color; 157 | font = font !== undefined && font !== null ? font : this.font; 158 | alignment = alignment !== undefined && alignment !== null ? alignment : this.alignment; 159 | dropShadow = typeof dropShadow === 'boolean' ? dropShadow : dropShadow; 160 | outline = typeof outline === 'boolean' ? outline : outline; 161 | wordWrap = wordWrap || this.wordWrap; 162 | } 163 | 164 | Text.draw( 165 | arg1 as string, 166 | arg2, 167 | scale, 168 | color, 169 | font, 170 | alignment, 171 | dropShadow, 172 | outline, 173 | wordWrap, 174 | resolution, 175 | ); 176 | } 177 | } 178 | -------------------------------------------------------------------------------- /src/utils/Vector4.ts: -------------------------------------------------------------------------------- 1 | // Source: https://raw.githubusercontent.com/you21979/typescript-vector/master/vector3.ts 2 | 3 | import { Vector3 } from './Vector3'; 4 | 5 | // This is an adjusted version of the Source 6 | export interface Vec4 { 7 | x: number; 8 | y: number; 9 | z: number; 10 | w: number; 11 | } 12 | 13 | export type Vector4Type = Vector4 | Vec4; 14 | 15 | export class Vector4 implements Vec4 { 16 | public static create(v1: Vec4 | number): Vector4 { 17 | if (typeof v1 === 'number') return new Vector4(v1, v1, v1, v1); 18 | return new Vector4(v1.x, v1.y, v1.z, v1.w); 19 | } 20 | 21 | /** 22 | * Creates a vector from an array of numbers 23 | * @param primitive An array of numbers (usually returned by a native) 24 | * ``` 25 | */ 26 | public static fromArray(primitive: [number, number, number, number] | number[]): Vector4 { 27 | return new Vector4(primitive[0], primitive[1], primitive[2], primitive[3]); 28 | } 29 | 30 | /** 31 | * Creates an array of vectors from an array number arrays 32 | * @param primitives A multi-dimensional array of number arrays 33 | * ``` 34 | */ 35 | public static fromArrays(primitives: [number, number, number, number][] | number[][]): Vector4[] { 36 | return primitives.map(prim => new Vector4(prim[0], prim[1], prim[2], prim[3])); 37 | } 38 | 39 | public static clone(v1: Vec4): Vector4 { 40 | return Vector4.create(v1); 41 | } 42 | 43 | public static add(v1: Vector4Type, v2: Vector4Type | number): Vector4 { 44 | if (typeof v2 === 'number') return new Vector4(v1.x + v2, v1.y + v2, v1.z + v2, v1.w + v2); 45 | return new Vector4(v1.x + v2.x, v1.y + v2.y, v1.z + v2.z, v1.w + v2.w); 46 | } 47 | 48 | public static subtract(v1: Vector4Type, v2: Vector4Type | number): Vector4 { 49 | if (typeof v2 === 'number') return new Vector4(v1.x - v2, v1.y - v2, v1.z - v2, v1.w - v2); 50 | return new Vector4(v1.x - v2.x, v1.y - v2.y, v1.z - v2.z, v1.w - v2.w); 51 | } 52 | 53 | public static multiply(v1: Vector4Type, v2: Vector4Type | number): Vector4 { 54 | if (typeof v2 === 'number') return new Vector4(v1.x * v2, v1.y * v2, v1.z * v2, v1.w * v2); 55 | return new Vector4(v1.x * v2.x, v1.y * v2.y, v1.z * v2.z, v1.w * v2.w); 56 | } 57 | 58 | public static divide(v1: Vector4Type, v2: Vector4Type | number): Vector4 { 59 | if (typeof v2 === 'number') return new Vector4(v1.x / v2, v1.y / v2, v1.z / v2, v1.w / v2); 60 | return new Vector4(v1.x / v2.x, v1.y / v2.y, v1.z / v2.z, v1.w / v2.w); 61 | } 62 | 63 | public static dotProduct(v1: Vector4Type, v2: Vector4Type): number { 64 | return v1.x * v2.x + v1.y * v2.y + v1.z * v2.z + v1.w * v2.w; 65 | } 66 | 67 | public static crossProduct(v1: Vector4Type, v2: Vector4Type): Vector4 { 68 | const x = v1.y * v2.z - v1.z * v2.y; 69 | const y = v1.z * v2.x - v1.x * v2.z; 70 | const z = v1.x * v2.y - v1.y * v2.x; 71 | return new Vector4(x, y, z, v1.w); 72 | } 73 | 74 | public static normalize(v: Vector4): Vector4 { 75 | return Vector4.divide(v, v.Length); 76 | } 77 | 78 | constructor(public x: number, public y: number, public z: number, public w: number) {} 79 | 80 | public clone(): Vector4 { 81 | return new Vector4(this.x, this.y, this.z, this.w); 82 | } 83 | 84 | /** 85 | * The product of the Euclidean magnitudes of this and another Vector4. 86 | * 87 | * @param v Vector4 to find Euclidean magnitude between. 88 | * @returns Euclidean magnitude with another vector. 89 | */ 90 | public distanceSquared(v: Vector4Type): number { 91 | const w: Vector4 = this.subtract(v); 92 | return Vector4.dotProduct(w, w); 93 | } 94 | 95 | /** 96 | * The distance between two Vectors. 97 | * 98 | * @param v Vector4 to find distance between. 99 | * @returns Distance between this and another vector. 100 | */ 101 | public distance(v: Vector4Type): number { 102 | return Math.sqrt(this.distanceSquared(v)); 103 | } 104 | 105 | public get normalize(): Vector4 { 106 | return Vector4.normalize(this); 107 | } 108 | 109 | public crossProduct(v: Vector4Type): Vector4 { 110 | return Vector4.crossProduct(this, v); 111 | } 112 | 113 | public dotProduct(v: Vector4Type): number { 114 | return Vector4.dotProduct(this, v); 115 | } 116 | 117 | public add(v: Vector4Type | number): Vector4 { 118 | return Vector4.add(this, v); 119 | } 120 | 121 | public subtract(v: Vector4Type): Vector4 { 122 | return Vector4.subtract(this, v); 123 | } 124 | 125 | public multiply(v: Vector4Type | number): Vector4 { 126 | return Vector4.multiply(this, v); 127 | } 128 | 129 | public divide(v: Vector4Type | number): Vector4 { 130 | return Vector4.divide(this, v); 131 | } 132 | 133 | public toArray(): [number, number, number, number] { 134 | return [this.x, this.y, this.z, this.w]; 135 | } 136 | 137 | public toVec3(): Vector3 { 138 | return new Vector3(this.x, this.y, this.z); 139 | } 140 | 141 | public replace(v: Vector4Type): void { 142 | this.x = v.x; 143 | this.y = v.y; 144 | this.z = v.z; 145 | this.w = v.w; 146 | } 147 | 148 | public get Length(): number { 149 | return Math.sqrt(this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w); 150 | } 151 | } 152 | --------------------------------------------------------------------------------