Release v.0.1.0 #2
63
.gitea/ISSUE_TEMPLATE.yaml
Normal file
63
.gitea/ISSUE_TEMPLATE.yaml
Normal file
@ -0,0 +1,63 @@
|
||||
name: Bug Report
|
||||
about: Create a report to help us improve
|
||||
|
||||
rules:
|
||||
- All issues must be reported in English
|
||||
- Ensure you have searched for existing issues before creating a new one
|
||||
- Provide as much detail as possible to help us resolve the issue efficiently
|
||||
|
||||
body:
|
||||
- type: dropdown
|
||||
id: package_version
|
||||
attributes:
|
||||
label: Package Version
|
||||
description: Select the version of the package where the bug was found
|
||||
options:
|
||||
- 0.1.0
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: bug_description
|
||||
attributes:
|
||||
label: Bug Description
|
||||
description: Provide a detailed description of the bug
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: reproduction
|
||||
attributes:
|
||||
label: Reproduction (Optional)
|
||||
description: Steps to reproduce the bug, if applicable
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: os
|
||||
attributes:
|
||||
label: OS Where the Bug Was Found
|
||||
description: Select the operating system where the bug was found
|
||||
options:
|
||||
- Windows
|
||||
- macOS
|
||||
- Linux
|
||||
- Other (please specify at the end of bug description)
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: cli_version
|
||||
attributes:
|
||||
label: CLI Version (Optional)
|
||||
description: Specify the CLI version if used
|
||||
validations:
|
||||
required: false
|
||||
|
||||
- type: textarea
|
||||
id: additional_information
|
||||
attributes:
|
||||
label: Additional Information
|
||||
description: Add any other information that might be useful in diagnosing the issue
|
||||
validations:
|
||||
required: false
|
@ -1,10 +1,11 @@
|
||||
{
|
||||
"name": "rage-fw-cef",
|
||||
"version": "0.0.20-alpha.0",
|
||||
"version": "0.1.0",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/src/index.d.ts",
|
||||
"files": [
|
||||
"dist/**/*"
|
||||
"dist/**/*",
|
||||
"readme.md"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsup"
|
||||
|
2
cef/readme.md
Normal file
2
cef/readme.md
Normal file
@ -0,0 +1,2 @@
|
||||
# RageFW CEF
|
||||
[Read docs for details](https://git.entityseven.com/entityseven/rage-framework/wiki/Docs)
|
@ -21,7 +21,9 @@ class Cef {
|
||||
eventName: EventName,
|
||||
callback: RageFW_CefCallback<EventName>,
|
||||
): void {
|
||||
rpc.register(eventName, callback)
|
||||
if ('mp' in window) {
|
||||
rpc.register(eventName, callback)
|
||||
}
|
||||
}
|
||||
|
||||
public trigger<EventName extends keyof RageFW_ICustomCefEvent>(
|
||||
@ -30,7 +32,13 @@ class Cef {
|
||||
? [RageFW_CefArguments<EventName>]
|
||||
: []
|
||||
): Promise<RageFW_CefReturn<EventName>> {
|
||||
return rpc.call(eventName, args)
|
||||
if ('mp' in window) {
|
||||
return rpc.call(eventName, args)
|
||||
}
|
||||
|
||||
return Promise.reject(
|
||||
'RageFW was started in window which not contain global variable MP!',
|
||||
)
|
||||
}
|
||||
|
||||
public triggerServer<EventName extends keyof RageFW_ICustomServerEvent>(
|
||||
@ -39,7 +47,13 @@ class Cef {
|
||||
? [RageFW_ServerArguments<EventName>]
|
||||
: []
|
||||
): Promise<RageFW_ServerReturn<EventName>> {
|
||||
return rpc.callServer(eventName, args)
|
||||
if ('mp' in window) {
|
||||
return rpc.callServer(eventName, args)
|
||||
}
|
||||
|
||||
return Promise.reject(
|
||||
'RageFW was started in window which not contain global variable MP!',
|
||||
)
|
||||
}
|
||||
|
||||
public triggerClient<EventName extends keyof RageFW_ICustomClientEvent>(
|
||||
@ -48,7 +62,13 @@ class Cef {
|
||||
? [RageFW_ClientArguments<EventName>]
|
||||
: []
|
||||
): Promise<RageFW_ClientReturn<EventName>> {
|
||||
return rpc.callClient(eventName, args)
|
||||
if ('mp' in window) {
|
||||
return rpc.callClient(eventName, args)
|
||||
}
|
||||
|
||||
return Promise.reject(
|
||||
'RageFW was started in window which not contain global variable MP!',
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
6
cli/.prettierrc.yaml
Normal file
6
cli/.prettierrc.yaml
Normal file
@ -0,0 +1,6 @@
|
||||
tabWidth: 4
|
||||
printWidth: 80
|
||||
singleQuote: true
|
||||
semi: false
|
||||
arrowParens: avoid
|
||||
endOfLine: auto
|
35
cli/package.json
Normal file
35
cli/package.json
Normal file
@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "create-rage-fw",
|
||||
"version": "0.1.0",
|
||||
"bin": {
|
||||
"rage-fw": "dist/index.js"
|
||||
},
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"watch": "tsc -w",
|
||||
"build": "tsup",
|
||||
"start": "npx ./dist create"
|
||||
},
|
||||
"files": [
|
||||
"dist/**/*",
|
||||
"readme.md"
|
||||
],
|
||||
"description": "CLI to scaffold a template project for RageFW",
|
||||
"keywords": [],
|
||||
"author": "rilaxik",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@inquirer/prompts": "^5.0.5",
|
||||
"axios": "^1.7.2",
|
||||
"chalk": "4.1.2",
|
||||
"git-clone": "^0.2.0",
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/git-clone": "^0.2.4",
|
||||
"@types/node": "^20.14.2",
|
||||
"@types/yargs": "^17.0.32",
|
||||
"prettier": "^3.3.2",
|
||||
"typescript": "^5.4.5"
|
||||
}
|
||||
}
|
29
cli/readme.md
Normal file
29
cli/readme.md
Normal file
@ -0,0 +1,29 @@
|
||||
# RageFW CLI
|
||||
|
||||
To make you life easier while using RageFW we created a basic CLI. At the moment automation we have only works via [pnpm](https://pnpm.io/)
|
||||
|
||||
``pnpm create rage-fw@latest``
|
||||
|
||||
## TL;DR
|
||||
- ``Initialize new project`` - create new template project
|
||||
- ``Install RAGE:MP updater`` - download and update RAGE:MP server files
|
||||
|
||||
## Options
|
||||
For now, you will see a few available options. They are described in detail below
|
||||
|
||||
- ``Initialize new project``
|
||||
- ``Install RAGE:MP updater``
|
||||
|
||||
### Initialize new project
|
||||
Using this options will forward you to common project-creation menu
|
||||
- ``Enter project name``
|
||||
|
||||
This option will specify a name for your project which is used as a folder name too. Defaults to **rage-fw**
|
||||
|
||||
- ``Select frontend``
|
||||
|
||||
Use this selector menu to choose which frontend framework you want to use. We will do our best to expand this menu after some time.
|
||||
Defaults to **React + TypeScript (Vite)**
|
||||
|
||||
### Install Rage:MP updater
|
||||
This option will simplify installation process of Rage:MP server files required to start your server
|
66
cli/src/commands/create.ts
Normal file
66
cli/src/commands/create.ts
Normal file
@ -0,0 +1,66 @@
|
||||
import c from 'chalk'
|
||||
import { input, select } from '@inquirer/prompts'
|
||||
import clone from 'git-clone'
|
||||
import path from 'node:path'
|
||||
|
||||
export async function initProject() {
|
||||
let folder
|
||||
let framework
|
||||
|
||||
if (!folder) {
|
||||
folder = await input({
|
||||
message: c.gray('Enter project name:'),
|
||||
default: 'rage-fw',
|
||||
})
|
||||
} else {
|
||||
console.log(c.gray('Project name:'), folder)
|
||||
}
|
||||
|
||||
if (!framework) {
|
||||
framework = await select({
|
||||
message: c.gray('Select frontend:'),
|
||||
default: 'react',
|
||||
loop: true,
|
||||
choices: [
|
||||
{
|
||||
name: 'React + TypeScript (Vite)',
|
||||
value: 'react',
|
||||
description: 'React + TypeScript (Vite) as a frontend',
|
||||
},
|
||||
// {
|
||||
// name: 'vue',
|
||||
// value: 'vue',
|
||||
// description: 'npm is the most popular package manager',
|
||||
// },
|
||||
],
|
||||
})
|
||||
} else {
|
||||
console.log(c.gray('Frontend:'), framework)
|
||||
}
|
||||
|
||||
console.log(
|
||||
c.gray('\nScaffolding template project into'),
|
||||
folder,
|
||||
c.gray('with'),
|
||||
framework,
|
||||
c.gray('as a frontend..'),
|
||||
)
|
||||
|
||||
clone(
|
||||
'https://git.entityseven.com/entityseven/rage-framework-example',
|
||||
path.join(process.cwd(), folder),
|
||||
{},
|
||||
err => {
|
||||
if (err) {
|
||||
console.log(c.red('Error occured: \n', err))
|
||||
return
|
||||
}
|
||||
console.log(c.gray('Scaffolded project into'), folder)
|
||||
console.log(
|
||||
c.gray(
|
||||
`Project was created ar dir: ${path.join(process.cwd(), folder)}`,
|
||||
),
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
37
cli/src/commands/download-updater.ts
Normal file
37
cli/src/commands/download-updater.ts
Normal file
@ -0,0 +1,37 @@
|
||||
import axios from 'axios'
|
||||
import * as fs from 'node:fs'
|
||||
|
||||
const latestReleases =
|
||||
'https://git.entityseven.com/api/v1/repos/entityseven/rage-server-downloader/releases?page=1&limit=1'
|
||||
|
||||
type Release = {
|
||||
id: number
|
||||
}
|
||||
|
||||
type Asset = {
|
||||
browser_download_url: string
|
||||
}
|
||||
|
||||
export async function downloadUpdater(): Promise<void> {
|
||||
const id = await getLatestReleaseID()
|
||||
|
||||
const latestAssets = `https://git.entityseven.com/api/v1/repos/entityseven/rage-server-downloader/releases/${id}/assets?page=1&limit=1`
|
||||
|
||||
axios.get<Asset[]>(latestAssets).then(async ({ data }) => {
|
||||
const downloadURL = data[0].browser_download_url
|
||||
|
||||
const file = await axios.get(data[0].browser_download_url, {
|
||||
responseType: 'arraybuffer',
|
||||
})
|
||||
const fileData = Buffer.from(file.data, 'binary')
|
||||
|
||||
const fileSplit = downloadURL.split('/')
|
||||
const fileName = fileSplit[fileSplit.length - 1]
|
||||
|
||||
fs.writeFileSync(`./${fileName}`, fileData)
|
||||
})
|
||||
}
|
||||
|
||||
async function getLatestReleaseID() {
|
||||
return axios.get<Release[]>(latestReleases).then(({ data }) => data[0].id)
|
||||
}
|
40
cli/src/index.ts
Normal file
40
cli/src/index.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import c from 'chalk'
|
||||
import { select } from '@inquirer/prompts'
|
||||
|
||||
import { checkForUpdate } from './utils/update'
|
||||
import { initProject } from './commands/create'
|
||||
import { downloadUpdater } from './commands/download-updater'
|
||||
|
||||
enum Actions {
|
||||
INIT_PROJECT = 'INIT_PROJECT',
|
||||
UPDATER = 'UPDATER',
|
||||
}
|
||||
|
||||
;(async () => {
|
||||
await checkForUpdate()
|
||||
|
||||
console.log(
|
||||
c.blueBright('Rage FW CLI | Powered by Entity Seven Group ️ <3'),
|
||||
)
|
||||
|
||||
const action = await select({
|
||||
message: c.gray('Select action:'),
|
||||
choices: [
|
||||
{
|
||||
name: 'Initialize new project',
|
||||
value: Actions.INIT_PROJECT,
|
||||
description: 'Initialize new project and start develop',
|
||||
},
|
||||
{
|
||||
name: 'Install RAGE:MP updater',
|
||||
value: Actions.UPDATER,
|
||||
description:
|
||||
'Use our custom updater to download and update RAGE:MP server files.',
|
||||
},
|
||||
],
|
||||
loop: true,
|
||||
})
|
||||
|
||||
if (action === Actions.INIT_PROJECT) await initProject()
|
||||
if (action === Actions.UPDATER) await downloadUpdater()
|
||||
})()
|
32
cli/src/utils/update.ts
Normal file
32
cli/src/utils/update.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import axios from 'axios'
|
||||
import c from 'chalk'
|
||||
import yargs from 'yargs'
|
||||
|
||||
const latestVersionURL =
|
||||
'https://git.entityseven.com/api/v1/repos/entityseven/rage-framework/tags?page=1&limit=1'
|
||||
|
||||
type Version = {
|
||||
name: string
|
||||
message: string
|
||||
}
|
||||
|
||||
export async function checkForUpdate(): Promise<void> {
|
||||
return new Promise(res => {
|
||||
yargs.showVersion(version =>
|
||||
axios
|
||||
.get<Version[]>(latestVersionURL)
|
||||
.then(({ data }) => {
|
||||
const latestVersion = data[0].name
|
||||
|
||||
if (latestVersion !== `v${version}`)
|
||||
notifyUserAboutUpdate(latestVersion)
|
||||
else console.log(c.yellow(`Version: ${version}`))
|
||||
})
|
||||
.then(() => res()),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
function notifyUserAboutUpdate(version: string) {
|
||||
console.log(c.green(`Update available. New version: ${version}`))
|
||||
}
|
24
cli/tsconfig.json
Normal file
24
cli/tsconfig.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es6",
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
"lib": ["DOM", "ES6"],
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
|
||||
"outDir": "bin",
|
||||
"esModuleInterop": true,
|
||||
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noImplicitAny": true
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
],
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
]
|
||||
}
|
10
cli/tsup.config.ts
Normal file
10
cli/tsup.config.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { defineConfig } from 'tsup'
|
||||
|
||||
export default defineConfig({
|
||||
entry: ['src/index.ts'],
|
||||
outDir: './dist',
|
||||
bundle: true,
|
||||
splitting: false,
|
||||
sourcemap: false,
|
||||
clean: true,
|
||||
})
|
@ -1,10 +1,11 @@
|
||||
{
|
||||
"name": "rage-fw-client",
|
||||
"version": "0.0.20-alpha.0",
|
||||
"version": "0.1.0",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/src/index.d.ts",
|
||||
"files": [
|
||||
"dist/**/*"
|
||||
"dist/**/*",
|
||||
"readme.md"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsup"
|
||||
|
2
client/readme.md
Normal file
2
client/readme.md
Normal file
@ -0,0 +1,2 @@
|
||||
# RageFW Client
|
||||
[Read docs for details](https://git.entityseven.com/entityseven/rage-framework/wiki/Docs)
|
@ -4,16 +4,22 @@ import type { RageFW_ICustomClientEvent } from 'rage-fw-shared-types'
|
||||
|
||||
/**
|
||||
* Union of all available client event names
|
||||
* These only include custom events
|
||||
* These include custom and system events
|
||||
*/
|
||||
export type RageFW_ClientEvent = keyof RageFW_ICustomClientEvent
|
||||
export type RageFW_ClientEvent =
|
||||
| keyof RageFW_ICustomClientEvent
|
||||
| keyof IClientEvents
|
||||
|
||||
/**
|
||||
* Array of arguments for an event, name of which you pass as a generic
|
||||
* These only include custom events
|
||||
* These include custom and system events
|
||||
*/
|
||||
export type RageFW_ClientEventArguments<K extends RageFW_ClientEvent> =
|
||||
Parameters<RageFW_ICustomClientEvent[K]>
|
||||
K extends keyof RageFW_ICustomClientEvent
|
||||
? Parameters<RageFW_ICustomClientEvent[K]>
|
||||
: K extends keyof IClientEvents
|
||||
? Parameters<IClientEvents[K]>
|
||||
: never
|
||||
|
||||
/**
|
||||
* Callback (function) for an event, name of which you pass as a generic
|
||||
|
@ -1,5 +1,5 @@
|
||||
{
|
||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
|
||||
"version": "0.0.20-alpha.0",
|
||||
"version": "0.1.0",
|
||||
"npmClient": "pnpm"
|
||||
}
|
||||
|
13
license.md
Normal file
13
license.md
Normal file
@ -0,0 +1,13 @@
|
||||
# Custom Attribution-NoDerivs Software License
|
||||
|
||||
This license allows you to use, copy, and distribute the RageFW (the "Software"), including for commercial purposes, provided that the following conditions are met:
|
||||
|
||||
1. **Attribution:** You must give appropriate credit to the original author of the Software, provide a link to the license, and indicate if changes were made. You may do so in any reasonable manner, but not in any way that suggests the licensor endorses you or your use.
|
||||
|
||||
2. **No Derivative Works:** You may not modify, transform, or build upon the Software.
|
||||
|
||||
3. **Usage and Commercial Use:** You are allowed to use, sell, and gain income from projects that utilize the Software, as long as you comply with the terms of this license.
|
||||
|
||||
4. **No Additional Restrictions:** You may not apply legal terms or technological measures that legally restrict others from doing anything the license permits.
|
||||
|
||||
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. 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.
|
330
pnpm-lock.yaml
330
pnpm-lock.yaml
@ -9,7 +9,7 @@ importers:
|
||||
dependencies:
|
||||
'@microsoft/api-extractor':
|
||||
specifier: ^7.47.0
|
||||
version: 7.47.0
|
||||
version: 7.47.0(@types/node@20.14.2)
|
||||
'@ragempcommunity/types-cef':
|
||||
specifier: ^2.1.8
|
||||
version: 2.1.8
|
||||
@ -39,7 +39,7 @@ importers:
|
||||
version: 0.4.0
|
||||
tsup:
|
||||
specifier: ^8.1.0
|
||||
version: 8.1.0(@microsoft/api-extractor@7.47.0)(typescript@5.4.5)
|
||||
version: 8.1.0(@microsoft/api-extractor@7.47.0(@types/node@20.14.2))(typescript@5.4.5)
|
||||
typescript:
|
||||
specifier: ^5.4.5
|
||||
version: 5.4.5
|
||||
@ -59,6 +59,40 @@ importers:
|
||||
specifier: ^0.4.0
|
||||
version: 0.4.0
|
||||
|
||||
cli:
|
||||
dependencies:
|
||||
'@inquirer/prompts':
|
||||
specifier: ^5.0.5
|
||||
version: 5.0.5
|
||||
axios:
|
||||
specifier: ^1.7.2
|
||||
version: 1.7.2
|
||||
chalk:
|
||||
specifier: 4.1.2
|
||||
version: 4.1.2
|
||||
git-clone:
|
||||
specifier: ^0.2.0
|
||||
version: 0.2.0
|
||||
yargs:
|
||||
specifier: ^17.7.2
|
||||
version: 17.7.2
|
||||
devDependencies:
|
||||
'@types/git-clone':
|
||||
specifier: ^0.2.4
|
||||
version: 0.2.4
|
||||
'@types/node':
|
||||
specifier: ^20.14.2
|
||||
version: 20.14.2
|
||||
'@types/yargs':
|
||||
specifier: ^17.0.32
|
||||
version: 17.0.32
|
||||
prettier:
|
||||
specifier: ^3.3.2
|
||||
version: 3.3.2
|
||||
typescript:
|
||||
specifier: ^5.4.5
|
||||
version: 5.4.5
|
||||
|
||||
client:
|
||||
dependencies:
|
||||
'@ragempcommunity/types-client':
|
||||
@ -386,6 +420,90 @@ packages:
|
||||
}
|
||||
engines: { node: '>=6.9.0' }
|
||||
|
||||
'@inquirer/checkbox@2.3.5':
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-3V0OSykTkE/38GG1DhxRGLBmqefgzRg2EK5A375zz+XEvIWfAHcac31e+zlBDPypRHxhmXc/Oh6v9eOPbH3nAg==,
|
||||
}
|
||||
engines: { node: '>=18' }
|
||||
|
||||
'@inquirer/confirm@3.1.9':
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-UF09aejxCi4Xqm6N/jJAiFXArXfi9al52AFaSD+2uIHnhZGtd1d6lIGTRMPouVSJxbGEi+HkOWSYaiEY/+szUw==,
|
||||
}
|
||||
engines: { node: '>=18' }
|
||||
|
||||
'@inquirer/core@8.2.2':
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-K8SuNX45jEFlX3EBJpu9B+S2TISzMPGXZIuJ9ME924SqbdW6Pt6fIkKvXg7mOEOKJ4WxpQsxj0UTfcL/A434Ww==,
|
||||
}
|
||||
engines: { node: '>=18' }
|
||||
|
||||
'@inquirer/editor@2.1.9':
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-5xCD7CoCh993YqXcsZPt45qkE3gl+03Yfv9vmAkptRi4nrzaUDmyhgBzndKdRG8SrKbQLBmOtztnRLGxvG/ahg==,
|
||||
}
|
||||
engines: { node: '>=18' }
|
||||
|
||||
'@inquirer/expand@2.1.9':
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-ymnR8qu2ie/3JpOeyZ3QSGJ+ai8qqtjBwopxLjzIZm7mZVKT6SV1sURzijkOLRgGUHwPemOfYX5biqXuqhpoBg==,
|
||||
}
|
||||
engines: { node: '>=18' }
|
||||
|
||||
'@inquirer/figures@1.0.3':
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-ErXXzENMH5pJt5/ssXV0DfWUZqly8nGzf0UcBV9xTnP+KyffE2mqyxIMBrZ8ijQck2nU0TQm40EQB53YreyWHw==,
|
||||
}
|
||||
engines: { node: '>=18' }
|
||||
|
||||
'@inquirer/input@2.1.9':
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-1xTCHmIe48x9CG1+8glAHrVVdH+QfYhzgBUbgyoVpp5NovnXgRcjSn/SNulepxf9Ol8HDq3gzw3ZCAUr+h1Eyg==,
|
||||
}
|
||||
engines: { node: '>=18' }
|
||||
|
||||
'@inquirer/password@2.1.9':
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-QPtVcT12Fkn0TyuZJelR7QOtc5l1d/6pB5EfkHOivTzC6QTFxRCHl+Gx7Q3E2U/kgJeCCmDov6itDFggk9nkgA==,
|
||||
}
|
||||
engines: { node: '>=18' }
|
||||
|
||||
'@inquirer/prompts@5.0.5':
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-LV2XZzc8ls4zhUzYNSpsXcnA8djOptY4G01lFzp3Bey6E1oiZMzIU25N9cb5AOwNz6pqDXpjLwRFQmLQ8h6PaQ==,
|
||||
}
|
||||
engines: { node: '>=18' }
|
||||
|
||||
'@inquirer/rawlist@2.1.9':
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-GuMmfa/v1ZJqEWSkUx1hMxzs5/0DCUP0S8IicV/wu8QrbjfBOh+7mIQgtsvh8IJ3sRkRcQ+9wh9CE9jiYqyMgw==,
|
||||
}
|
||||
engines: { node: '>=18' }
|
||||
|
||||
'@inquirer/select@2.3.5':
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-IyBj8oEtmdF2Gx4FJTPtEya37MD6s0KATKsHqgmls0lK7EQbhYSq9GQlcFq6cBsYe/cgQ0Fg2cCqYYPi/d/fxQ==,
|
||||
}
|
||||
engines: { node: '>=18' }
|
||||
|
||||
'@inquirer/type@1.3.3':
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-xTUt0NulylX27/zMx04ZYar/kr1raaiFTVvQ5feljQsiAgdm0WPj4S73/ye0fbslh+15QrIuDvfCXTek7pMY5A==,
|
||||
}
|
||||
engines: { node: '>=18' }
|
||||
|
||||
'@isaacs/cliui@8.0.2':
|
||||
resolution:
|
||||
{
|
||||
@ -1069,6 +1187,12 @@ packages:
|
||||
integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==,
|
||||
}
|
||||
|
||||
'@types/git-clone@0.2.4':
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-1ybApDpKU12dychtOp2zBe93ZwAsxVSjOqKUqH7NCDm4GXuPnjmcz2P9K2S1z+BCX2AnLmFFuB6pI6CMZ3j9sQ==,
|
||||
}
|
||||
|
||||
'@types/minimatch@3.0.5':
|
||||
resolution:
|
||||
{
|
||||
@ -1081,6 +1205,18 @@ packages:
|
||||
integrity: sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==,
|
||||
}
|
||||
|
||||
'@types/mute-stream@0.0.4':
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-CPM9nzrCPPJHQNA9keH9CVkVI+WR5kMa+7XEs5jcGQ0VoAGnLv242w8lIVgwAEfmE4oufJRaTc9PNLQl0ioAow==,
|
||||
}
|
||||
|
||||
'@types/node@20.14.2':
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-xyu6WAMVwv6AKFLB+e/7ySZVr/0zLCzOa7rSpq6jNwpqOrUbcACDWC+53d4n2QHOnDou0fbIsg8wZu/sxrnI4Q==,
|
||||
}
|
||||
|
||||
'@types/normalize-package-data@2.4.4':
|
||||
resolution:
|
||||
{
|
||||
@ -1093,6 +1229,24 @@ packages:
|
||||
integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==,
|
||||
}
|
||||
|
||||
'@types/wrap-ansi@3.0.0':
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-ltIpx+kM7g/MLRZfkbL7EsCEjfzCcScLpkg37eXEtx5kmrAKBkTJwd1GIAjDSL8wTpM6Hzn5YO4pSb91BEwu1g==,
|
||||
}
|
||||
|
||||
'@types/yargs-parser@21.0.3':
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==,
|
||||
}
|
||||
|
||||
'@types/yargs@17.0.32':
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-xQ67Yc/laOG5uMfX/093MRlGGCIBzZMarVa+gfNKJxWAIgykYpVGkBdbqEzGDDfCrVUj6Hiff4mTZ5BA6TmAog==,
|
||||
}
|
||||
|
||||
'@typescript-eslint/eslint-plugin@7.13.0':
|
||||
resolution:
|
||||
{
|
||||
@ -1667,6 +1821,13 @@ packages:
|
||||
}
|
||||
engines: { node: '>= 10' }
|
||||
|
||||
cli-width@4.1.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==,
|
||||
}
|
||||
engines: { node: '>= 12' }
|
||||
|
||||
cliui@7.0.4:
|
||||
resolution:
|
||||
{
|
||||
@ -2340,10 +2501,10 @@ packages:
|
||||
debug:
|
||||
optional: true
|
||||
|
||||
foreground-child@3.1.1:
|
||||
foreground-child@3.2.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==,
|
||||
integrity: sha512-CrWQNaEl1/6WeZoarcM9LHupTo3RpZO2Pdk1vktwzPiQTsJnAKJmm3TACKeG5UZbWDfaH2AbvYxzP96y0MT7fA==,
|
||||
}
|
||||
engines: { node: '>=14' }
|
||||
|
||||
@ -2458,6 +2619,12 @@ packages:
|
||||
}
|
||||
engines: { node: '>=10' }
|
||||
|
||||
git-clone@0.2.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-1UAkEPIFbyjHaddljUKvPhhLRnrKaImT71T7rdvSvWLXw95nLdhdi6Qmlx0KOWoV1qqvHGLq5lMLJEZM0JXk8A==,
|
||||
}
|
||||
|
||||
git-raw-commits@3.0.0:
|
||||
resolution:
|
||||
{
|
||||
@ -5086,6 +5253,12 @@ packages:
|
||||
engines: { node: '>=0.8.0' }
|
||||
hasBin: true
|
||||
|
||||
undici-types@5.26.5:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==,
|
||||
}
|
||||
|
||||
unique-filename@3.0.0:
|
||||
resolution:
|
||||
{
|
||||
@ -5490,6 +5663,87 @@ snapshots:
|
||||
|
||||
'@hutson/parse-repository-url@3.0.2': {}
|
||||
|
||||
'@inquirer/checkbox@2.3.5':
|
||||
dependencies:
|
||||
'@inquirer/core': 8.2.2
|
||||
'@inquirer/figures': 1.0.3
|
||||
'@inquirer/type': 1.3.3
|
||||
ansi-escapes: 4.3.2
|
||||
chalk: 4.1.2
|
||||
|
||||
'@inquirer/confirm@3.1.9':
|
||||
dependencies:
|
||||
'@inquirer/core': 8.2.2
|
||||
'@inquirer/type': 1.3.3
|
||||
|
||||
'@inquirer/core@8.2.2':
|
||||
dependencies:
|
||||
'@inquirer/figures': 1.0.3
|
||||
'@inquirer/type': 1.3.3
|
||||
'@types/mute-stream': 0.0.4
|
||||
'@types/node': 20.14.2
|
||||
'@types/wrap-ansi': 3.0.0
|
||||
ansi-escapes: 4.3.2
|
||||
chalk: 4.1.2
|
||||
cli-spinners: 2.9.2
|
||||
cli-width: 4.1.0
|
||||
mute-stream: 1.0.0
|
||||
signal-exit: 4.1.0
|
||||
strip-ansi: 6.0.1
|
||||
wrap-ansi: 6.2.0
|
||||
|
||||
'@inquirer/editor@2.1.9':
|
||||
dependencies:
|
||||
'@inquirer/core': 8.2.2
|
||||
'@inquirer/type': 1.3.3
|
||||
external-editor: 3.1.0
|
||||
|
||||
'@inquirer/expand@2.1.9':
|
||||
dependencies:
|
||||
'@inquirer/core': 8.2.2
|
||||
'@inquirer/type': 1.3.3
|
||||
chalk: 4.1.2
|
||||
|
||||
'@inquirer/figures@1.0.3': {}
|
||||
|
||||
'@inquirer/input@2.1.9':
|
||||
dependencies:
|
||||
'@inquirer/core': 8.2.2
|
||||
'@inquirer/type': 1.3.3
|
||||
|
||||
'@inquirer/password@2.1.9':
|
||||
dependencies:
|
||||
'@inquirer/core': 8.2.2
|
||||
'@inquirer/type': 1.3.3
|
||||
ansi-escapes: 4.3.2
|
||||
|
||||
'@inquirer/prompts@5.0.5':
|
||||
dependencies:
|
||||
'@inquirer/checkbox': 2.3.5
|
||||
'@inquirer/confirm': 3.1.9
|
||||
'@inquirer/editor': 2.1.9
|
||||
'@inquirer/expand': 2.1.9
|
||||
'@inquirer/input': 2.1.9
|
||||
'@inquirer/password': 2.1.9
|
||||
'@inquirer/rawlist': 2.1.9
|
||||
'@inquirer/select': 2.3.5
|
||||
|
||||
'@inquirer/rawlist@2.1.9':
|
||||
dependencies:
|
||||
'@inquirer/core': 8.2.2
|
||||
'@inquirer/type': 1.3.3
|
||||
chalk: 4.1.2
|
||||
|
||||
'@inquirer/select@2.3.5':
|
||||
dependencies:
|
||||
'@inquirer/core': 8.2.2
|
||||
'@inquirer/figures': 1.0.3
|
||||
'@inquirer/type': 1.3.3
|
||||
ansi-escapes: 4.3.2
|
||||
chalk: 4.1.2
|
||||
|
||||
'@inquirer/type@1.3.3': {}
|
||||
|
||||
'@isaacs/cliui@8.0.2':
|
||||
dependencies:
|
||||
string-width: 5.1.2
|
||||
@ -5595,23 +5849,23 @@ snapshots:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
'@microsoft/api-extractor-model@7.29.2':
|
||||
'@microsoft/api-extractor-model@7.29.2(@types/node@20.14.2)':
|
||||
dependencies:
|
||||
'@microsoft/tsdoc': 0.15.0
|
||||
'@microsoft/tsdoc-config': 0.17.0
|
||||
'@rushstack/node-core-library': 5.4.1
|
||||
'@rushstack/node-core-library': 5.4.1(@types/node@20.14.2)
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
|
||||
'@microsoft/api-extractor@7.47.0':
|
||||
'@microsoft/api-extractor@7.47.0(@types/node@20.14.2)':
|
||||
dependencies:
|
||||
'@microsoft/api-extractor-model': 7.29.2
|
||||
'@microsoft/api-extractor-model': 7.29.2(@types/node@20.14.2)
|
||||
'@microsoft/tsdoc': 0.15.0
|
||||
'@microsoft/tsdoc-config': 0.17.0
|
||||
'@rushstack/node-core-library': 5.4.1
|
||||
'@rushstack/node-core-library': 5.4.1(@types/node@20.14.2)
|
||||
'@rushstack/rig-package': 0.5.2
|
||||
'@rushstack/terminal': 0.13.0
|
||||
'@rushstack/ts-command-line': 4.22.0
|
||||
'@rushstack/terminal': 0.13.0(@types/node@20.14.2)
|
||||
'@rushstack/ts-command-line': 4.22.0(@types/node@20.14.2)
|
||||
lodash: 4.17.21
|
||||
minimatch: 3.0.8
|
||||
resolve: 1.22.8
|
||||
@ -5890,7 +6144,7 @@ snapshots:
|
||||
'@rollup/rollup-win32-x64-msvc@4.18.0':
|
||||
optional: true
|
||||
|
||||
'@rushstack/node-core-library@5.4.1':
|
||||
'@rushstack/node-core-library@5.4.1(@types/node@20.14.2)':
|
||||
dependencies:
|
||||
ajv: 8.13.0
|
||||
ajv-draft-04: 1.0.0(ajv@8.13.0)
|
||||
@ -5900,20 +6154,24 @@ snapshots:
|
||||
jju: 1.4.0
|
||||
resolve: 1.22.8
|
||||
semver: 7.5.4
|
||||
optionalDependencies:
|
||||
'@types/node': 20.14.2
|
||||
|
||||
'@rushstack/rig-package@0.5.2':
|
||||
dependencies:
|
||||
resolve: 1.22.8
|
||||
strip-json-comments: 3.1.1
|
||||
|
||||
'@rushstack/terminal@0.13.0':
|
||||
'@rushstack/terminal@0.13.0(@types/node@20.14.2)':
|
||||
dependencies:
|
||||
'@rushstack/node-core-library': 5.4.1
|
||||
'@rushstack/node-core-library': 5.4.1(@types/node@20.14.2)
|
||||
supports-color: 8.1.1
|
||||
optionalDependencies:
|
||||
'@types/node': 20.14.2
|
||||
|
||||
'@rushstack/ts-command-line@4.22.0':
|
||||
'@rushstack/ts-command-line@4.22.0(@types/node@20.14.2)':
|
||||
dependencies:
|
||||
'@rushstack/terminal': 0.13.0
|
||||
'@rushstack/terminal': 0.13.0(@types/node@20.14.2)
|
||||
'@types/argparse': 1.0.38
|
||||
argparse: 1.0.10
|
||||
string-argv: 0.3.2
|
||||
@ -5995,14 +6253,32 @@ snapshots:
|
||||
|
||||
'@types/estree@1.0.5': {}
|
||||
|
||||
'@types/git-clone@0.2.4': {}
|
||||
|
||||
'@types/minimatch@3.0.5': {}
|
||||
|
||||
'@types/minimist@1.2.5': {}
|
||||
|
||||
'@types/mute-stream@0.0.4':
|
||||
dependencies:
|
||||
'@types/node': 20.14.2
|
||||
|
||||
'@types/node@20.14.2':
|
||||
dependencies:
|
||||
undici-types: 5.26.5
|
||||
|
||||
'@types/normalize-package-data@2.4.4': {}
|
||||
|
||||
'@types/triple-beam@1.3.5': {}
|
||||
|
||||
'@types/wrap-ansi@3.0.0': {}
|
||||
|
||||
'@types/yargs-parser@21.0.3': {}
|
||||
|
||||
'@types/yargs@17.0.32':
|
||||
dependencies:
|
||||
'@types/yargs-parser': 21.0.3
|
||||
|
||||
'@typescript-eslint/eslint-plugin@7.13.0(@typescript-eslint/parser@7.13.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5)':
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.10.1
|
||||
@ -6361,6 +6637,8 @@ snapshots:
|
||||
|
||||
cli-width@3.0.0: {}
|
||||
|
||||
cli-width@4.1.0: {}
|
||||
|
||||
cliui@7.0.4:
|
||||
dependencies:
|
||||
string-width: 4.2.3
|
||||
@ -6796,7 +7074,7 @@ snapshots:
|
||||
|
||||
follow-redirects@1.15.6: {}
|
||||
|
||||
foreground-child@3.1.1:
|
||||
foreground-child@3.2.0:
|
||||
dependencies:
|
||||
cross-spawn: 7.0.3
|
||||
signal-exit: 4.1.0
|
||||
@ -6866,6 +7144,8 @@ snapshots:
|
||||
|
||||
get-stream@6.0.1: {}
|
||||
|
||||
git-clone@0.2.0: {}
|
||||
|
||||
git-raw-commits@3.0.0:
|
||||
dependencies:
|
||||
dargs: 7.0.0
|
||||
@ -6905,7 +7185,7 @@ snapshots:
|
||||
|
||||
glob@10.4.1:
|
||||
dependencies:
|
||||
foreground-child: 3.1.1
|
||||
foreground-child: 3.2.0
|
||||
jackspeak: 3.4.0
|
||||
minimatch: 9.0.4
|
||||
minipass: 7.1.2
|
||||
@ -7186,13 +7466,13 @@ snapshots:
|
||||
jake@10.9.1:
|
||||
dependencies:
|
||||
async: 3.2.5
|
||||
chalk: 4.1.0
|
||||
chalk: 4.1.2
|
||||
filelist: 1.0.4
|
||||
minimatch: 3.1.2
|
||||
|
||||
jest-diff@29.7.0:
|
||||
dependencies:
|
||||
chalk: 4.1.0
|
||||
chalk: 4.1.2
|
||||
diff-sequences: 29.6.3
|
||||
jest-get-type: 29.6.3
|
||||
pretty-format: 29.7.0
|
||||
@ -7783,7 +8063,7 @@ snapshots:
|
||||
'@yarnpkg/parsers': 3.0.0-rc.46
|
||||
'@zkochan/js-yaml': 0.0.7
|
||||
axios: 1.7.2
|
||||
chalk: 4.1.0
|
||||
chalk: 4.1.2
|
||||
cli-cursor: 3.1.0
|
||||
cli-spinners: 2.6.1
|
||||
cliui: 8.0.1
|
||||
@ -7858,7 +8138,7 @@ snapshots:
|
||||
ora@5.3.0:
|
||||
dependencies:
|
||||
bl: 4.1.0
|
||||
chalk: 4.1.0
|
||||
chalk: 4.1.2
|
||||
cli-cursor: 3.1.0
|
||||
cli-spinners: 2.6.1
|
||||
is-interactive: 1.0.0
|
||||
@ -8487,7 +8767,7 @@ snapshots:
|
||||
|
||||
tslib@2.6.3: {}
|
||||
|
||||
tsup@8.1.0(@microsoft/api-extractor@7.47.0)(typescript@5.4.5):
|
||||
tsup@8.1.0(@microsoft/api-extractor@7.47.0(@types/node@20.14.2))(typescript@5.4.5):
|
||||
dependencies:
|
||||
bundle-require: 4.2.1(esbuild@0.21.5)
|
||||
cac: 6.7.14
|
||||
@ -8504,7 +8784,7 @@ snapshots:
|
||||
sucrase: 3.35.0
|
||||
tree-kill: 1.2.2
|
||||
optionalDependencies:
|
||||
'@microsoft/api-extractor': 7.47.0
|
||||
'@microsoft/api-extractor': 7.47.0(@types/node@20.14.2)
|
||||
typescript: 5.4.5
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@ -8551,6 +8831,8 @@ snapshots:
|
||||
uglify-js@3.18.0:
|
||||
optional: true
|
||||
|
||||
undici-types@5.26.5: {}
|
||||
|
||||
unique-filename@3.0.0:
|
||||
dependencies:
|
||||
unique-slug: 4.0.0
|
||||
|
@ -2,4 +2,5 @@ packages:
|
||||
- "server"
|
||||
- "client"
|
||||
- "cef"
|
||||
- "cli"
|
||||
- "shared-types"
|
1
rage-rpc/README.md
Normal file
1
rage-rpc/README.md
Normal file
@ -0,0 +1 @@
|
||||
Currently not maintained.
|
24
rage-rpc/package.json
Normal file
24
rage-rpc/package.json
Normal file
@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "rage-fw-rpc",
|
||||
"version": "0.0.23-alpha.0",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/src/index.d.ts",
|
||||
"files": [
|
||||
"dist/**/*"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsup"
|
||||
},
|
||||
"dependencies": {
|
||||
"rage-rpc": "^0.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ragempcommunity/types-client": "^2.1.8",
|
||||
"rage-fw-shared-types": "workspace:^"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "SashaGoncharov19",
|
||||
"license": "MIT",
|
||||
"description": "Client side of rage-fw",
|
||||
"gitHead": "053e4fd12aa120d53e11e0d2009c0df78c1a2ad0"
|
||||
}
|
42
rage-rpc/src/defs.d.ts
vendored
Normal file
42
rage-rpc/src/defs.d.ts
vendored
Normal file
@ -0,0 +1,42 @@
|
||||
declare var mp: any;
|
||||
declare var global: any;
|
||||
declare var window: any;
|
||||
|
||||
declare type ProcedureListener = (args: any, info: ProcedureListenerInfo) => any;
|
||||
|
||||
declare interface Player {
|
||||
call: (eventName: string, args?: any[]) => void;
|
||||
[property: string]: any;
|
||||
}
|
||||
|
||||
declare interface Browser {
|
||||
url: string;
|
||||
execute: (code: string) => void;
|
||||
[property: string]: any;
|
||||
}
|
||||
|
||||
declare interface ProcedureListenerInfo {
|
||||
environment: string;
|
||||
id?: string;
|
||||
player?: Player;
|
||||
browser?: Browser;
|
||||
}
|
||||
|
||||
declare interface CallOptions {
|
||||
timeout?: number;
|
||||
noRet?: boolean;
|
||||
}
|
||||
|
||||
declare interface Event {
|
||||
req?: number;
|
||||
ret?: number;
|
||||
b?: string;
|
||||
id: string;
|
||||
name?: string;
|
||||
args?: any;
|
||||
env: string;
|
||||
fenv?: string;
|
||||
res?: any;
|
||||
err?: any;
|
||||
noRet?: number;
|
||||
}
|
568
rage-rpc/src/index.ts
Normal file
568
rage-rpc/src/index.ts
Normal file
@ -0,0 +1,568 @@
|
||||
import * as util from './util';
|
||||
|
||||
const environment = util.getEnvironment();
|
||||
if(!environment) throw 'Unknown RAGE environment';
|
||||
|
||||
const ERR_NOT_FOUND = 'PROCEDURE_NOT_FOUND';
|
||||
|
||||
const IDENTIFIER = '__rpc:id';
|
||||
const PROCESS_EVENT = '__rpc:process';
|
||||
const BROWSER_REGISTER = '__rpc:browserRegister';
|
||||
const BROWSER_UNREGISTER = '__rpc:browserUnregister';
|
||||
const TRIGGER_EVENT = '__rpc:triggerEvent';
|
||||
const TRIGGER_EVENT_BROWSERS = '__rpc:triggerEventBrowsers';
|
||||
|
||||
const glob = environment === 'cef' ? window : global;
|
||||
|
||||
if(!glob[PROCESS_EVENT]){
|
||||
glob.__rpcListeners = {};
|
||||
glob.__rpcPending = {};
|
||||
glob.__rpcEvListeners = {};
|
||||
|
||||
glob[PROCESS_EVENT] = (player: Player | string, rawData?: string) => {
|
||||
if(environment !== "server") rawData = player as string;
|
||||
const data: Event = util.parseData(rawData);
|
||||
|
||||
if(data.req){ // someone is trying to remotely call a procedure
|
||||
const info: ProcedureListenerInfo = {
|
||||
id: data.id,
|
||||
environment: data.fenv || data.env
|
||||
};
|
||||
if(environment === "server") info.player = player as Player;
|
||||
const part = {
|
||||
ret: 1,
|
||||
id: data.id,
|
||||
env: environment
|
||||
};
|
||||
let ret: (ev: Event) => void;
|
||||
switch(environment){
|
||||
case "server":
|
||||
ret = ev => info.player.call(PROCESS_EVENT, [util.stringifyData(ev)]);
|
||||
break;
|
||||
case "client": {
|
||||
if(data.env === "server"){
|
||||
ret = ev => mp.events.callRemote(PROCESS_EVENT, util.stringifyData(ev));
|
||||
}else if(data.env === "cef"){
|
||||
const browser = data.b && glob.__rpcBrowsers[data.b];
|
||||
info.browser = browser;
|
||||
ret = ev => browser && util.isBrowserValid(browser) && passEventToBrowser(browser, ev, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "cef": {
|
||||
ret = ev => mp.trigger(PROCESS_EVENT, util.stringifyData(ev));
|
||||
}
|
||||
}
|
||||
if(ret){
|
||||
const promise = callProcedure(data.name, data.args, info);
|
||||
if(!data.noRet) promise.then(res => ret({ ...part, res })).catch(err => ret({ ...part, err: err ? err : null }));
|
||||
}
|
||||
}else if(data.ret){ // a previously called remote procedure has returned
|
||||
const info = glob.__rpcPending[data.id];
|
||||
if(environment === "server" && info.player !== player) return;
|
||||
if(info){
|
||||
info.resolve(data.hasOwnProperty('err') ? util.promiseReject(data.err) : util.promiseResolve(data.res));
|
||||
delete glob.__rpcPending[data.id];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if(environment !== "cef"){
|
||||
mp.events.add(PROCESS_EVENT, glob[PROCESS_EVENT]);
|
||||
|
||||
if(environment === "client"){
|
||||
// set up internal pass-through events
|
||||
register('__rpc:callServer', ([name, args, noRet], info) => _callServer(name, args, { fenv: info.environment, noRet }));
|
||||
register('__rpc:callBrowsers', ([name, args, noRet], info) => _callBrowsers(null, name, args, { fenv: info.environment, noRet }));
|
||||
|
||||
// set up browser identifiers
|
||||
glob.__rpcBrowsers = {};
|
||||
const initBrowser = (browser: Browser): void => {
|
||||
const id = util.uid();
|
||||
Object.keys(glob.__rpcBrowsers).forEach(key => {
|
||||
const b = glob.__rpcBrowsers[key];
|
||||
if(!b || !util.isBrowserValid(b) || b === browser) delete glob.__rpcBrowsers[key];
|
||||
});
|
||||
glob.__rpcBrowsers[id] = browser;
|
||||
browser.execute(`
|
||||
window.name = '${id}';
|
||||
if(typeof window['${IDENTIFIER}'] === 'undefined'){
|
||||
window['${IDENTIFIER}'] = Promise.resolve(window.name);
|
||||
}else{
|
||||
window['${IDENTIFIER}:resolve'](window.name);
|
||||
}
|
||||
`);
|
||||
};
|
||||
mp.browsers.forEach(initBrowser);
|
||||
mp.events.add('browserCreated', initBrowser);
|
||||
|
||||
// set up browser registration map
|
||||
glob.__rpcBrowserProcedures = {};
|
||||
mp.events.add(BROWSER_REGISTER, (data: string) => {
|
||||
const [browserId, name] = JSON.parse(data);
|
||||
glob.__rpcBrowserProcedures[name] = browserId;
|
||||
});
|
||||
mp.events.add(BROWSER_UNREGISTER, (data: string) => {
|
||||
const [browserId, name] = JSON.parse(data);
|
||||
if(glob.__rpcBrowserProcedures[name] === browserId) delete glob.__rpcBrowserProcedures[name];
|
||||
});
|
||||
|
||||
register(TRIGGER_EVENT_BROWSERS, ([name, args], info) => {
|
||||
Object.values(glob.__rpcBrowsers).forEach(browser => {
|
||||
_callBrowser(browser, TRIGGER_EVENT, [name, args], { fenv: info.environment, noRet: 1 });
|
||||
});
|
||||
});
|
||||
}
|
||||
}else{
|
||||
if(typeof glob[IDENTIFIER] === 'undefined'){
|
||||
glob[IDENTIFIER] = new Promise(resolve => {
|
||||
if (window.name) {
|
||||
resolve(window.name);
|
||||
}else{
|
||||
glob[IDENTIFIER+':resolve'] = resolve;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
register(TRIGGER_EVENT, ([name, args], info) => callEvent(name, args, info));
|
||||
}
|
||||
|
||||
function passEventToBrowser(browser: Browser, data: Event, ignoreNotFound: boolean): void {
|
||||
const raw = util.stringifyData(data);
|
||||
browser.execute(`var process = window["${PROCESS_EVENT}"]; if(process){ process(${JSON.stringify(raw)}); }else{ ${ignoreNotFound ? '' : `mp.trigger("${PROCESS_EVENT}", '{"ret":1,"id":"${data.id}","err":"${ERR_NOT_FOUND}","env":"cef"}');`} }`);
|
||||
}
|
||||
|
||||
function callProcedure(name: string, args: any, info: ProcedureListenerInfo): Promise<any> {
|
||||
const listener = glob.__rpcListeners[name];
|
||||
if(!listener) return util.promiseReject(ERR_NOT_FOUND);
|
||||
return util.promiseResolve(listener(args, info));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a procedure.
|
||||
* @param {string} name - The name of the procedure.
|
||||
* @param {function} cb - The procedure's callback. The return value will be sent back to the caller.
|
||||
* @returns {Function} The function, which unregister the event.
|
||||
*/
|
||||
export function register(name: string, cb: ProcedureListener): Function {
|
||||
if(arguments.length !== 2) throw 'register expects 2 arguments: "name" and "cb"';
|
||||
if(environment === "cef") glob[IDENTIFIER].then((id: string) => mp.trigger(BROWSER_REGISTER, JSON.stringify([id, name])));
|
||||
glob.__rpcListeners[name] = cb;
|
||||
|
||||
return () => unregister(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister a procedure.
|
||||
* @param {string} name - The name of the procedure.
|
||||
*/
|
||||
export function unregister(name: string): void {
|
||||
if(arguments.length !== 1) throw 'unregister expects 1 argument: "name"';
|
||||
if(environment === "cef") glob[IDENTIFIER].then((id: string) => mp.trigger(BROWSER_UNREGISTER, JSON.stringify([id, name])));
|
||||
glob.__rpcListeners[name] = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a local procedure. Only procedures registered in the same context will be resolved.
|
||||
*
|
||||
* Can be called from any environment.
|
||||
*
|
||||
* @param name - The name of the locally registered procedure.
|
||||
* @param args - Any parameters for the procedure.
|
||||
* @param options - Any options.
|
||||
* @returns The result from the procedure.
|
||||
*/
|
||||
export function call(name: string, args?: any, options: CallOptions = {}): Promise<any> {
|
||||
if(arguments.length < 1 || arguments.length > 3) return util.promiseReject('call expects 1 to 3 arguments: "name", optional "args", and optional "options"');
|
||||
return util.promiseTimeout(callProcedure(name, args, { environment }), options.timeout);
|
||||
}
|
||||
|
||||
function _callServer(name: string, args?: any, extraData: any = {}): Promise<any> {
|
||||
switch(environment){
|
||||
case "server": {
|
||||
return call(name, args);
|
||||
}
|
||||
case "client": {
|
||||
const id = util.uid();
|
||||
return new Promise(resolve => {
|
||||
if(!extraData.noRet){
|
||||
glob.__rpcPending[id] = {
|
||||
resolve
|
||||
};
|
||||
}
|
||||
const event: Event = {
|
||||
req: 1,
|
||||
id,
|
||||
name,
|
||||
env: environment,
|
||||
args,
|
||||
...extraData
|
||||
};
|
||||
mp.events.callRemote(PROCESS_EVENT, util.stringifyData(event));
|
||||
});
|
||||
}
|
||||
case "cef": {
|
||||
return callClient('__rpc:callServer', [name, args, +extraData.noRet]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a remote procedure registered on the server.
|
||||
*
|
||||
* Can be called from any environment.
|
||||
*
|
||||
* @param name - The name of the registered procedure.
|
||||
* @param args - Any parameters for the procedure.
|
||||
* @param options - Any options.
|
||||
* @returns The result from the procedure.
|
||||
*/
|
||||
export function callServer(name: string, args?: any, options: CallOptions = {}): Promise<any> {
|
||||
if(arguments.length < 1 || arguments.length > 3) return util.promiseReject('callServer expects 1 to 3 arguments: "name", optional "args", and optional "options"');
|
||||
|
||||
let extraData: any = {};
|
||||
if(options.noRet) extraData.noRet = 1;
|
||||
|
||||
return util.promiseTimeout(_callServer(name, args, extraData), options.timeout);
|
||||
}
|
||||
|
||||
function _callClient(player: Player, name: string, args?: any, extraData: any = {}): Promise<any> {
|
||||
switch(environment){
|
||||
case 'client': {
|
||||
return call(name, args);
|
||||
}
|
||||
case 'server': {
|
||||
const id = util.uid();
|
||||
return new Promise(resolve => {
|
||||
if(!extraData.noRet){
|
||||
glob.__rpcPending[id] = {
|
||||
resolve,
|
||||
player
|
||||
};
|
||||
}
|
||||
const event: Event = {
|
||||
req: 1,
|
||||
id,
|
||||
name,
|
||||
env: environment,
|
||||
args,
|
||||
...extraData
|
||||
};
|
||||
player.call(PROCESS_EVENT, [util.stringifyData(event)]);
|
||||
});
|
||||
}
|
||||
case 'cef': {
|
||||
const id = util.uid();
|
||||
return glob[IDENTIFIER].then((browserId: string) => {
|
||||
return new Promise(resolve => {
|
||||
if(!extraData.noRet){
|
||||
glob.__rpcPending[id] = {
|
||||
resolve
|
||||
};
|
||||
}
|
||||
const event: Event = {
|
||||
b: browserId,
|
||||
req: 1,
|
||||
id,
|
||||
name,
|
||||
env: environment,
|
||||
args,
|
||||
...extraData
|
||||
};
|
||||
mp.trigger(PROCESS_EVENT, util.stringifyData(event));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a remote procedure registered on the client.
|
||||
*
|
||||
* Can be called from any environment.
|
||||
*
|
||||
* @param player - The player to call the procedure on.
|
||||
* @param name - The name of the registered procedure.
|
||||
* @param args - Any parameters for the procedure.
|
||||
* @param options - Any options.
|
||||
* @returns The result from the procedure.
|
||||
*/
|
||||
export function callClient(player: Player | string, name?: string | any, args?: any, options: CallOptions = {}): Promise<any> {
|
||||
switch(environment){
|
||||
case 'client': {
|
||||
options = args || {};
|
||||
args = name;
|
||||
name = player;
|
||||
player = null;
|
||||
if((arguments.length < 1 || arguments.length > 3) || typeof name !== 'string') return util.promiseReject('callClient from the client expects 1 to 3 arguments: "name", optional "args", and optional "options"');
|
||||
break;
|
||||
}
|
||||
case 'server': {
|
||||
if((arguments.length < 2 || arguments.length > 4) || typeof player !== 'object') return util.promiseReject('callClient from the server expects 2 to 4 arguments: "player", "name", optional "args", and optional "options"');
|
||||
break;
|
||||
}
|
||||
case 'cef': {
|
||||
options = args || {};
|
||||
args = name;
|
||||
name = player;
|
||||
player = null;
|
||||
if((arguments.length < 1 || arguments.length > 3) || typeof name !== 'string') return util.promiseReject('callClient from the browser expects 1 to 3 arguments: "name", optional "args", and optional "options"');
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
let extraData: any = {};
|
||||
if(options.noRet) extraData.noRet = 1;
|
||||
|
||||
return util.promiseTimeout(_callClient(player as Player, name, args, extraData), options.timeout);
|
||||
}
|
||||
|
||||
function _callBrowser(browser: Browser, name: string, args?: any, extraData: any = {}): Promise<any> {
|
||||
return new Promise(resolve => {
|
||||
const id = util.uid();
|
||||
if(!extraData.noRet){
|
||||
glob.__rpcPending[id] = {
|
||||
resolve
|
||||
};
|
||||
}
|
||||
passEventToBrowser(browser, {
|
||||
req: 1,
|
||||
id,
|
||||
name,
|
||||
env: environment,
|
||||
args,
|
||||
...extraData
|
||||
}, false);
|
||||
});
|
||||
}
|
||||
|
||||
function _callBrowsers(player: Player, name: string, args?: any, extraData: any = {}): Promise<any> {
|
||||
switch(environment){
|
||||
case 'client':
|
||||
const browserId = glob.__rpcBrowserProcedures[name];
|
||||
if(!browserId) return util.promiseReject(ERR_NOT_FOUND);
|
||||
const browser = glob.__rpcBrowsers[browserId];
|
||||
if(!browser || !util.isBrowserValid(browser)) return util.promiseReject(ERR_NOT_FOUND);
|
||||
return _callBrowser(browser, name, args, extraData);
|
||||
case 'server':
|
||||
return _callClient(player, '__rpc:callBrowsers', [name, args, +extraData.noRet], extraData);
|
||||
case 'cef':
|
||||
return _callClient(null, '__rpc:callBrowsers', [name, args, +extraData.noRet], extraData);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a remote procedure registered in any browser context.
|
||||
*
|
||||
* Can be called from any environment.
|
||||
*
|
||||
* @param player - The player to call the procedure on.
|
||||
* @param name - The name of the registered procedure.
|
||||
* @param args - Any parameters for the procedure.
|
||||
* @param options - Any options.
|
||||
* @returns The result from the procedure.
|
||||
*/
|
||||
export function callBrowsers(player: Player | string, name?: string | any, args?: any, options: CallOptions = {}): Promise<any> {
|
||||
let promise;
|
||||
let extraData: any = {};
|
||||
|
||||
switch(environment){
|
||||
case 'client':
|
||||
case 'cef':
|
||||
options = args || {};
|
||||
args = name;
|
||||
name = player;
|
||||
if(arguments.length < 1 || arguments.length > 3) return util.promiseReject('callBrowsers from the client or browser expects 1 to 3 arguments: "name", optional "args", and optional "options"');
|
||||
if(options.noRet) extraData.noRet = 1;
|
||||
promise = _callBrowsers(null, name, args, extraData);
|
||||
break;
|
||||
case 'server':
|
||||
if(arguments.length < 2 || arguments.length > 4) return util.promiseReject('callBrowsers from the server expects 2 to 4 arguments: "player", "name", optional "args", and optional "options"');
|
||||
if(options.noRet) extraData.noRet = 1;
|
||||
promise = _callBrowsers(player as Player, name, args, extraData);
|
||||
break;
|
||||
}
|
||||
|
||||
if(promise){
|
||||
return util.promiseTimeout(promise, options.timeout);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a remote procedure registered in a specific browser instance.
|
||||
*
|
||||
* Client-side environment only.
|
||||
*
|
||||
* @param browser - The browser instance.
|
||||
* @param name - The name of the registered procedure.
|
||||
* @param args - Any parameters for the procedure.
|
||||
* @param options - Any options.
|
||||
* @returns The result from the procedure.
|
||||
*/
|
||||
export function callBrowser(browser: Browser, name: string, args?: any, options: CallOptions = {}): Promise<any> {
|
||||
if(environment !== 'client') return util.promiseReject('callBrowser can only be used in the client environment');
|
||||
if(arguments.length < 2 || arguments.length > 4) return util.promiseReject('callBrowser expects 2 to 4 arguments: "browser", "name", optional "args", and optional "options"');
|
||||
|
||||
let extraData: any = {};
|
||||
if(options.noRet) extraData.noRet = 1;
|
||||
|
||||
return util.promiseTimeout(_callBrowser(browser, name, args, extraData), options.timeout);
|
||||
}
|
||||
|
||||
function callEvent(name: string, args: any, info: ProcedureListenerInfo){
|
||||
const listeners = glob.__rpcEvListeners[name];
|
||||
if(listeners){
|
||||
listeners.forEach(listener => listener(args, info));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an event handler.
|
||||
* @param {string} name - The name of the event.
|
||||
* @param cb - The callback for the event.
|
||||
* @returns {Function} The function, which off the event.
|
||||
*/
|
||||
export function on(name: string, cb: ProcedureListener): Function {
|
||||
if(arguments.length !== 2) throw 'on expects 2 arguments: "name" and "cb"';
|
||||
|
||||
const listeners = glob.__rpcEvListeners[name] || new Set();
|
||||
listeners.add(cb);
|
||||
glob.__rpcEvListeners[name] = listeners;
|
||||
|
||||
return () => off(name, cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister an event handler.
|
||||
* @param {string} name - The name of the event.
|
||||
* @param cb - The callback for the event.
|
||||
*/
|
||||
export function off(name: string, cb: ProcedureListener){
|
||||
if(arguments.length !== 2) throw 'off expects 2 arguments: "name" and "cb"';
|
||||
|
||||
const listeners = glob.__rpcEvListeners[name];
|
||||
if(listeners){
|
||||
listeners.delete(cb);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers a local event. Only events registered in the same context will be triggered.
|
||||
*
|
||||
* Can be called from any environment.
|
||||
*
|
||||
* @param name - The name of the locally registered event.
|
||||
* @param args - Any parameters for the event.
|
||||
*/
|
||||
export function trigger(name: string, args?: any){
|
||||
if(arguments.length < 1 || arguments.length > 2) throw 'trigger expects 1 or 2 arguments: "name", and optional "args"';
|
||||
callEvent(name, args, { environment });
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers an event registered on the client.
|
||||
*
|
||||
* Can be called from any environment.
|
||||
*
|
||||
* @param player - The player to call the procedure on.
|
||||
* @param name - The name of the event.
|
||||
* @param args - Any parameters for the event.
|
||||
*/
|
||||
export function triggerClient(player: Player | string, name?: string | any, args?: any){
|
||||
switch(environment){
|
||||
case 'client': {
|
||||
args = name;
|
||||
name = player;
|
||||
player = null;
|
||||
if((arguments.length < 1 || arguments.length > 2) || typeof name !== 'string') throw 'triggerClient from the client expects 1 or 2 arguments: "name", and optional "args"';
|
||||
break;
|
||||
}
|
||||
case 'server': {
|
||||
if((arguments.length < 2 || arguments.length > 3) || typeof player !== 'object') throw 'triggerClient from the server expects 2 or 3 arguments: "player", "name", and optional "args"';
|
||||
break;
|
||||
}
|
||||
case 'cef': {
|
||||
args = name;
|
||||
name = player;
|
||||
player = null;
|
||||
if((arguments.length < 1 || arguments.length > 2) || typeof name !== 'string') throw 'triggerClient from the browser expects 1 or 2 arguments: "name", and optional "args"';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_callClient(player as Player, TRIGGER_EVENT, [name, args], { noRet: 1 });
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers an event registered on the server.
|
||||
*
|
||||
* Can be called from any environment.
|
||||
*
|
||||
* @param name - The name of the event.
|
||||
* @param args - Any parameters for the event.
|
||||
*/
|
||||
export function triggerServer(name: string, args?: any){
|
||||
if(arguments.length < 1 || arguments.length > 2) throw 'triggerServer expects 1 or 2 arguments: "name", and optional "args"';
|
||||
|
||||
_callServer(TRIGGER_EVENT, [name, args], { noRet: 1 });
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers an event registered in any browser context.
|
||||
*
|
||||
* Can be called from any environment.
|
||||
*
|
||||
* @param player - The player to call the procedure on.
|
||||
* @param name - The name of the event.
|
||||
* @param args - Any parameters for the event.
|
||||
*/
|
||||
export function triggerBrowsers(player: Player | string, name?: string | any, args?: any){
|
||||
switch(environment){
|
||||
case 'client':
|
||||
case 'cef':
|
||||
args = name;
|
||||
name = player;
|
||||
player = null;
|
||||
if(arguments.length < 1 || arguments.length > 2) throw 'triggerBrowsers from the client or browser expects 1 or 2 arguments: "name", and optional "args"';
|
||||
break;
|
||||
case 'server':
|
||||
if(arguments.length < 2 || arguments.length > 3) throw 'triggerBrowsers from the server expects 2 or 3 arguments: "player", "name", and optional "args"';
|
||||
break;
|
||||
}
|
||||
|
||||
_callClient(player as Player, TRIGGER_EVENT_BROWSERS, [name, args], { noRet: 1 });
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers an event registered in a specific browser instance.
|
||||
*
|
||||
* Client-side environment only.
|
||||
*
|
||||
* @param browser - The browser instance.
|
||||
* @param name - The name of the event.
|
||||
* @param args - Any parameters for the event.
|
||||
*/
|
||||
export function triggerBrowser(browser: Browser, name: string, args?: any){
|
||||
if(environment !== 'client') throw 'callBrowser can only be used in the client environment';
|
||||
if(arguments.length < 2 || arguments.length > 4) throw 'callBrowser expects 2 or 3 arguments: "browser", "name", and optional "args"';
|
||||
|
||||
_callBrowser(browser, TRIGGER_EVENT, [name, args], { noRet: 1});
|
||||
}
|
||||
|
||||
export default {
|
||||
register,
|
||||
unregister,
|
||||
call,
|
||||
callServer,
|
||||
callClient,
|
||||
callBrowsers,
|
||||
callBrowser,
|
||||
on,
|
||||
off,
|
||||
trigger,
|
||||
triggerServer,
|
||||
triggerClient,
|
||||
triggerBrowsers,
|
||||
triggerBrowser
|
||||
};
|
122
rage-rpc/src/util.ts
Normal file
122
rage-rpc/src/util.ts
Normal file
@ -0,0 +1,122 @@
|
||||
enum MpTypes {
|
||||
Blip = 'b',
|
||||
Checkpoint = 'cp',
|
||||
Colshape = 'c',
|
||||
Label = 'l',
|
||||
Marker = 'm',
|
||||
Object = 'o',
|
||||
Pickup = 'p',
|
||||
Player = 'pl',
|
||||
Vehicle = 'v'
|
||||
}
|
||||
|
||||
function isObjectMpType(obj: any, type: MpTypes){
|
||||
const client = getEnvironment() === 'client';
|
||||
if(obj && typeof obj === 'object' && typeof obj.id !== 'undefined'){
|
||||
const test = (type, collection, mpType) => client ? obj.type === type && collection.at(obj.id) === obj : obj instanceof mpType;
|
||||
switch(type){
|
||||
case MpTypes.Blip: return test('blip', mp.blips, mp.Blip);
|
||||
case MpTypes.Checkpoint: return test('checkpoint', mp.checkpoints, mp.Checkpoint);
|
||||
case MpTypes.Colshape: return test('colshape', mp.colshapes, mp.Colshape);
|
||||
case MpTypes.Label: return test('textlabel', mp.labels, mp.TextLabel);
|
||||
case MpTypes.Marker: return test('marker', mp.markers, mp.Marker);
|
||||
case MpTypes.Object: return test('object', mp.objects, mp.Object);
|
||||
case MpTypes.Pickup: return test('pickup', mp.pickups, mp.Pickup);
|
||||
case MpTypes.Player: return test('player', mp.players, mp.Player);
|
||||
case MpTypes.Vehicle: return test('vehicle', mp.vehicles, mp.Vehicle);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function uid(): string {
|
||||
const first = (Math.random() * 46656) | 0;
|
||||
const second = (Math.random() * 46656) | 0;
|
||||
const firstPart = ('000' + first.toString(36)).slice(-3);
|
||||
const secondPart = ('000' + second.toString(36)).slice(-3);
|
||||
return firstPart + secondPart;
|
||||
}
|
||||
|
||||
export function getEnvironment(): string {
|
||||
if ('mp' in window) return 'cef';
|
||||
if (mp.joaat) return 'server';
|
||||
else if (mp.game && mp.game.joaat) return 'client';
|
||||
}
|
||||
|
||||
export function stringifyData(data: any): string {
|
||||
const env = getEnvironment();
|
||||
return JSON.stringify(data, (_, value) => {
|
||||
if(env === 'client' || env === 'server' && value && typeof value === 'object'){
|
||||
let type;
|
||||
|
||||
if(isObjectMpType(value, MpTypes.Blip)) type = MpTypes.Blip;
|
||||
else if(isObjectMpType(value, MpTypes.Checkpoint)) type = MpTypes.Checkpoint;
|
||||
else if(isObjectMpType(value, MpTypes.Colshape)) type = MpTypes.Colshape;
|
||||
else if(isObjectMpType(value, MpTypes.Marker)) type = MpTypes.Marker;
|
||||
else if(isObjectMpType(value, MpTypes.Object)) type = MpTypes.Object;
|
||||
else if(isObjectMpType(value, MpTypes.Pickup)) type = MpTypes.Pickup;
|
||||
else if(isObjectMpType(value, MpTypes.Player)) type = MpTypes.Player;
|
||||
else if(isObjectMpType(value, MpTypes.Vehicle)) type = MpTypes.Vehicle;
|
||||
|
||||
if(type) return {
|
||||
__t: type,
|
||||
i: typeof value.remoteId === 'number' ? value.remoteId : value.id
|
||||
};
|
||||
}
|
||||
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
export function parseData(data: string): any {
|
||||
const env = getEnvironment();
|
||||
return JSON.parse(data, (_, value) => {
|
||||
if((env === 'client' || env === 'server') && value && typeof value === 'object' && typeof value['__t'] === 'string' && typeof value.i === 'number' && Object.keys(value).length === 2){
|
||||
const id = value.i;
|
||||
const type = value['__t'];
|
||||
let collection;
|
||||
|
||||
switch(type){
|
||||
case MpTypes.Blip: collection = mp.blips; break;
|
||||
case MpTypes.Checkpoint: collection = mp.checkpoints; break;
|
||||
case MpTypes.Colshape: collection = mp.colshapes; break;
|
||||
case MpTypes.Label: collection = mp.labels; break;
|
||||
case MpTypes.Marker: collection = mp.markers; break;
|
||||
case MpTypes.Object: collection = mp.objects; break;
|
||||
case MpTypes.Pickup: collection = mp.pickups; break;
|
||||
case MpTypes.Player: collection = mp.players; break;
|
||||
case MpTypes.Vehicle: collection = mp.vehicles; break;
|
||||
}
|
||||
|
||||
if(collection) return collection[env === 'client' ? 'atRemoteId' : 'at'](id);
|
||||
}
|
||||
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
export function promiseResolve(result: any): Promise<any> {
|
||||
return new Promise(resolve => setTimeout(() => resolve(result), 0));
|
||||
}
|
||||
|
||||
export function promiseReject(error: any): Promise<any> {
|
||||
return new Promise((_, reject) => setTimeout(() => reject(error), 0));
|
||||
}
|
||||
|
||||
export function promiseTimeout(promise: Promise<any>, timeout?: number){
|
||||
if(typeof timeout === 'number'){
|
||||
return Promise.race([
|
||||
new Promise((_, reject) => {
|
||||
setTimeout(() => reject('TIMEOUT'), timeout);
|
||||
}),
|
||||
promise
|
||||
]);
|
||||
}else return promise;
|
||||
}
|
||||
|
||||
export function isBrowserValid(browser: Browser): boolean {
|
||||
try {
|
||||
browser.url;
|
||||
}catch(e){ return false; }
|
||||
return true;
|
||||
}
|
25
rage-rpc/tsconfig.json
Normal file
25
rage-rpc/tsconfig.json
Normal file
@ -0,0 +1,25 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/tsconfig",
|
||||
"display": "Base",
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
],
|
||||
"compilerOptions": {
|
||||
"incremental": false,
|
||||
"composite": false,
|
||||
"target": "ES2022",
|
||||
"experimentalDecorators": true,
|
||||
"moduleDetection": "auto",
|
||||
"module": "CommonJS",
|
||||
"resolveJsonModule": true,
|
||||
"declaration": false,
|
||||
"declarationMap": false,
|
||||
"sourceMap": false,
|
||||
"downlevelIteration": false,
|
||||
"inlineSourceMap": false,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
"skipLibCheck": true
|
||||
}
|
||||
}
|
12
rage-rpc/tsup.config.ts
Normal file
12
rage-rpc/tsup.config.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { defineConfig } from 'tsup'
|
||||
|
||||
export default defineConfig({
|
||||
entry: ['src/index.ts'],
|
||||
outDir: './dist',
|
||||
format: ['cjs'],
|
||||
noExternal: ['rage-rpc'],
|
||||
experimentalDts: true,
|
||||
splitting: false,
|
||||
sourcemap: false,
|
||||
clean: true,
|
||||
})
|
14
readme.md
14
readme.md
@ -9,7 +9,16 @@ RageFW is a type-safe framework for developing Rage:MP servers. Designed with de
|
||||
- **Logging System:** Keep track of server activities and debug like a pro with our built-in, feature-rich logging system. After all, even virtual cops need evidence
|
||||
|
||||
## Getting Started
|
||||
*soon*
|
||||
You can find out more about our CLI [here](https://git.entityseven.com/entityseven/rage-framework/wiki/CLI)
|
||||
|
||||
At the moment automation we have only works via [pnpm](https://pnpm.io/). To scaffold a basic project with minor settings you can use our CLI:
|
||||
|
||||
``pnpm create rage-fw``
|
||||
|
||||
This will give you a few options, among them, you can find ``Initialize new project``. Use that option to scaffold a new project for yourself using the preferred frontend framework
|
||||
|
||||
## Documentation
|
||||
[Available here](https://git.entityseven.com/entityseven/rage-framework/wiki/Docs+%40+0.0.30-alpha.0.-)
|
||||
|
||||
## Contributing
|
||||
Join our community of developers and contribute to the ongoing development of RageFW. At the moment the only way to contribute is opening issues
|
||||
@ -17,4 +26,7 @@ Join our community of developers and contribute to the ongoing development of Ra
|
||||
## Support
|
||||
Need help? Reach out via our community forums or contact us directly through our support channels. We're committed to help you as we can
|
||||
|
||||
## License
|
||||
Licensed under **Custom Attribution-NoDerivs Software License**
|
||||
|
||||
> *RageFW - because in the world of GTA:RP, nobody has time for type errors*
|
@ -1,10 +1,11 @@
|
||||
{
|
||||
"name": "rage-fw-server",
|
||||
"version": "0.0.20-alpha.0",
|
||||
"version": "0.1.0",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/src/index.d.ts",
|
||||
"files": [
|
||||
"dist/**/*"
|
||||
"dist/**/*",
|
||||
"readme.md"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsup"
|
||||
|
2
server/readme.md
Normal file
2
server/readme.md
Normal file
@ -0,0 +1,2 @@
|
||||
# RageFW Server
|
||||
[Read docs for details](https://git.entityseven.com/entityseven/rage-framework/wiki/Docs)
|
@ -34,7 +34,7 @@ class Server {
|
||||
rpc.register(
|
||||
eventName,
|
||||
async (args: RageFW_ServerEventArguments<EventName>, info) => {
|
||||
callback(info.player as PlayerMp, args)
|
||||
callback([info.player as PlayerMp, ...args])
|
||||
},
|
||||
)
|
||||
}
|
||||
@ -43,7 +43,11 @@ class Server {
|
||||
eventName: EventName,
|
||||
callback: RageFW_ServerEventCallbackNative<EventName>,
|
||||
): void {
|
||||
mp.events.add(eventName, callback)
|
||||
mp.events.add(
|
||||
eventName,
|
||||
(...args: Parameters<IServerEvents[EventName]>) =>
|
||||
callback([...args]),
|
||||
)
|
||||
}
|
||||
|
||||
public register<EventName extends RageFW_ServerEvent>(
|
||||
|
@ -54,8 +54,7 @@ export type RageFW_ServerEventReturn<K extends RageFW_ServerEvent> =
|
||||
export type RageFW_ServerEventCallbackCustom<
|
||||
K extends keyof RageFW_ICustomServerEvent = keyof RageFW_ICustomServerEvent,
|
||||
> = (
|
||||
player: PlayerMp,
|
||||
args: RageFW_ServerEventArguments<K>,
|
||||
payload: [player: PlayerMp, ...args: RageFW_ServerEventArguments<K>],
|
||||
) => RageFW_ServerEventReturn<K>
|
||||
|
||||
/**
|
||||
@ -64,7 +63,7 @@ export type RageFW_ServerEventCallbackCustom<
|
||||
*/
|
||||
export type RageFW_ServerEventCallbackNative<
|
||||
K extends keyof IServerEvents = keyof IServerEvents,
|
||||
> = IServerEvents[K]
|
||||
> = (payload: Parameters<IServerEvents[K]>) => ReturnType<IServerEvents[K]>
|
||||
|
||||
export type _ServerEventHasArgs<
|
||||
EventName extends keyof RageFW_ICustomServerEvent,
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "rage-fw-shared-types",
|
||||
"version": "0.0.20-alpha.0",
|
||||
"version": "0.1.0",
|
||||
"types": "types/types/index.d.ts",
|
||||
"files": [
|
||||
"types/**/*"
|
||||
|
2
shared-types/readme.md
Normal file
2
shared-types/readme.md
Normal file
@ -0,0 +1,2 @@
|
||||
# RageFW Shared types
|
||||
[Read docs for details](https://git.entityseven.com/entityseven/rage-framework/wiki/Docs)
|
4
shared-types/types/types/index.d.ts
vendored
4
shared-types/types/types/index.d.ts
vendored
@ -3,7 +3,5 @@ declare module 'rage-fw-shared-types' {
|
||||
|
||||
export interface RageFW_ICustomClientEvent {}
|
||||
|
||||
export interface RageFW_ICustomCefEvent {
|
||||
test(test: string): void
|
||||
}
|
||||
export interface RageFW_ICustomCefEvent {}
|
||||
}
|
||||
|
@ -1,7 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"lib": ["ESNext","ES2019"],
|
||||
"lib": [
|
||||
"ESNext",
|
||||
"ES2019",
|
||||
"dom"
|
||||
],
|
||||
"moduleResolution": "node",
|
||||
"module": "ESNext",
|
||||
"esModuleInterop": true,
|
||||
|
Loading…
Reference in New Issue
Block a user