Compare commits
161 Commits
v0.0.5-alp
...
master
Author | SHA1 | Date | |
---|---|---|---|
495217ecd5 | |||
7e43e0d106 | |||
2f1d1d9f0d | |||
cc40d90070 | |||
469d970654 | |||
217e0ddf01 | |||
ea572070ef | |||
7308fc26e0 | |||
ffd542c1de | |||
914300924a | |||
bc295a777b | |||
cd27764a30 | |||
30d125ce8e | |||
d56475d08a | |||
622676d189 | |||
d8df9fa7ef | |||
d9b917c024 | |||
cbbf4f38e6 | |||
3bbf1e2209 | |||
9fe9bad840 | |||
588bb42d04 | |||
3a4fe19df0 | |||
c8e5bdf375 | |||
a675114b41 | |||
54781d50b2 | |||
de33fe4763 | |||
d3d75b338d | |||
04eb724073 | |||
e4950b6c99 | |||
|
8f856d929f | ||
|
ee8210f140 | ||
|
74c0215366 | ||
19b1b770f6 | |||
|
96c92f9d19 | ||
2b287f06a2 | |||
2f2b1da99b | |||
c2684a48fc | |||
59910303f7 | |||
828a3deb33 | |||
39e6455271 | |||
44d985f498 | |||
2bcced5a56 | |||
830a69e91c | |||
e2e58e100a | |||
640adae8a5 | |||
|
7369ff8868 | ||
cd142e4414 | |||
ee4baca74a | |||
fafcdb50a8 | |||
cf9c4ce691 | |||
de6dbae3a8 | |||
|
5a92272eaf | ||
|
676ebbe827 | ||
|
b1adb809f8 | ||
|
5e8761dd05 | ||
bfc380227f | |||
70df94afa2 | |||
|
987bba717e | ||
|
f285f9c103 | ||
1467bb65b0 | |||
|
f08291eace | ||
75b528ca45 | |||
22ed5c4588 | |||
0059a41d0d | |||
cc1ebbd66b | |||
301a65e77f | |||
57d80d41d6 | |||
|
22e2c6f980 | ||
|
059dc7bed8 | ||
93b0cb1979 | |||
37fdfa6d90 | |||
7bf9433bef | |||
15254a35ba | |||
2b523fcbe5 | |||
4f4723625e | |||
93922288b1 | |||
|
630c06bb91 | ||
|
31136ad7e0 | ||
|
e9f77bf88d | ||
|
424513dd56 | ||
|
36c241a117 | ||
|
333bd9df13 | ||
|
6be93daa2d | ||
|
06f93e61a8 | ||
|
7357038c42 | ||
04412d7cbc | |||
9204eb81be | |||
1fd65c6b86 | |||
|
396e9c0ee6 | ||
839dff9b78 | |||
2054bc0a75 | |||
|
73dde02792 | ||
|
197de51a74 | ||
|
d3276278a5 | ||
|
1ad6f2c011 | ||
|
7ad4f2b7ae | ||
|
02c46389b3 | ||
2df12062d0 | |||
|
045614379d | ||
|
642545595b | ||
|
1766f047a4 | ||
|
95352908f8 | ||
|
7a506a02e2 | ||
|
c94bab24f2 | ||
|
a0e8c0b461 | ||
0520b869db | |||
e412aff01b | |||
c52cd8b4c8 | |||
|
a9486db3f5 | ||
|
61929d7b48 | ||
|
d6e9c92d0a | ||
|
301ef4ac57 | ||
|
79011e0fd2 | ||
|
57b4f236ac | ||
|
558005d7b0 | ||
a03cc01aa0 | |||
bad4d532f6 | |||
|
234bcecc7b | ||
|
2b26dbffc0 | ||
|
88e40a4635 | ||
fa3b1b1b0b | |||
1880f28eb7 | |||
|
c021ef3c59 | ||
|
22945357fd | ||
|
17ef98cbd2 | ||
|
39ab22f9aa | ||
|
97b094c3d4 | ||
|
acd7ad3406 | ||
|
0a81acf49e | ||
|
1b2f0d02ef | ||
|
3bb9256eb8 | ||
|
23c1e6080a | ||
|
33ebdaac84 | ||
|
8972fee22e | ||
828d74dad9 | |||
e1450397ab | |||
3f48215eb1 | |||
5205a9e245 | |||
4695f5dbd1 | |||
fa4c218a7a | |||
454fc12d2e | |||
|
2da34bd382 | ||
|
2113b5ae29 | ||
|
ff37d353bd | ||
|
3958fd458a | ||
|
44602be670 | ||
|
aed9bf2091 | ||
|
512b37cdbd | ||
|
c163ef6585 | ||
|
2775b42f59 | ||
|
19fdebd986 | ||
|
1923cb7a04 | ||
|
b336f1e1fe | ||
|
e649b46351 | ||
|
6d0ae3191f | ||
|
47ce0a6b16 | ||
|
77d667ce67 | ||
|
5064fb6347 | ||
|
bea9d570ad | ||
|
3b20276486 | ||
|
39dfe4c71d |
31
.eslintrc.yaml
Normal file
31
.eslintrc.yaml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
env:
|
||||||
|
node: true
|
||||||
|
es6: true
|
||||||
|
es2019: true
|
||||||
|
extends:
|
||||||
|
- 'eslint:recommended'
|
||||||
|
- 'plugin:@typescript-eslint/recommended'
|
||||||
|
# - 'prettier'
|
||||||
|
parser: '@typescript-eslint/parser'
|
||||||
|
parserOptions:
|
||||||
|
ecmaVersion: '2019'
|
||||||
|
sourceType: 'script'
|
||||||
|
plugins:
|
||||||
|
- '@typescript-eslint'
|
||||||
|
ignorePatterns:
|
||||||
|
- 'node_modules'
|
||||||
|
rules: {
|
||||||
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
|
'@typescript-eslint/no-unused-vars': [
|
||||||
|
'warn',
|
||||||
|
{
|
||||||
|
"argsIgnorePattern": '^_',
|
||||||
|
"varsIgnorePattern": '^_',
|
||||||
|
"caughtErrorsIgnorePattern": '^_'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'@typescript-eslint/ban-ts-comment': 'off',
|
||||||
|
'@typescript-eslint/ban-types': 'off',
|
||||||
|
'consistent-return': 'warn',
|
||||||
|
'no-empty': 'off',
|
||||||
|
}
|
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
|
||||||
|
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 (Optional)
|
||||||
|
description: Add any other information that might be useful in diagnosing the issue
|
||||||
|
validations:
|
||||||
|
required: false
|
13
LICENSE
Normal file
13
LICENSE
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.
|
15
browser/LICENSE
Normal file
15
browser/LICENSE
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
Custom Attribution-NoDerivs Software License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Entity Seven Group
|
||||||
|
|
||||||
|
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.
|
45
browser/package.json
Normal file
45
browser/package.json
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
"name": "@entityseven/rage-fw-browser",
|
||||||
|
"version": "0.2.0",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"types": "dist/src/index.d.ts",
|
||||||
|
"files": [
|
||||||
|
"dist/**/*",
|
||||||
|
"readme.md",
|
||||||
|
"LICENSE"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsup"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@entityseven/rage-fw-rpc": "0.2.5"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@entityseven/rage-fw-shared-types": "0.2.0",
|
||||||
|
"@ragempcommunity/types-cef": "^2.1.8"
|
||||||
|
},
|
||||||
|
"description": "Package used on a browser-side of your Rage:MP Server",
|
||||||
|
"keywords": [
|
||||||
|
"ragefw",
|
||||||
|
"rage-fw",
|
||||||
|
"ragemp",
|
||||||
|
"rage:mp",
|
||||||
|
"rage",
|
||||||
|
"gta5"
|
||||||
|
],
|
||||||
|
"author": "Entity Seven Group",
|
||||||
|
"contributors": [
|
||||||
|
{
|
||||||
|
"name": "Danya H",
|
||||||
|
"email": "dev.rilaxik@gmail.com",
|
||||||
|
"url": "https://github.com/rilaxik/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Oleksandr Honcharov",
|
||||||
|
"email": "0976053529@ukr.net",
|
||||||
|
"url": "https://github.com/SashaGoncharov19/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "Custom-Attribution-NoDerivs",
|
||||||
|
"gitHead": "ffd542c1deddb3033e16e0dae7557313ae09b05f"
|
||||||
|
}
|
2
browser/readme.md
Normal file
2
browser/readme.md
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
# RageFW Browser
|
||||||
|
[Read docs for details](https://git.entityseven.com/entityseven/rage-framework/wiki)
|
187
browser/src/core/browser.ts
Normal file
187
browser/src/core/browser.ts
Normal file
@ -0,0 +1,187 @@
|
|||||||
|
import { Helper } from './helper'
|
||||||
|
import { rpc } from './rpc'
|
||||||
|
import type * as T from '../types'
|
||||||
|
import {
|
||||||
|
RageFW_BrowserEvent,
|
||||||
|
RageFW_ClientEvent,
|
||||||
|
RageFW_ServerEvent,
|
||||||
|
} from '../types'
|
||||||
|
|
||||||
|
/** Browser-side interactions */
|
||||||
|
export class Browser extends Helper {
|
||||||
|
constructor() {
|
||||||
|
super()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setter. Enables console debug logs for events
|
||||||
|
*/
|
||||||
|
set debugLogs(debug: boolean) {
|
||||||
|
this.debugLogs_ = debug
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setter. Provides an ability to specify custom logger function to get special formatting. Using this enables ``debugLogs``
|
||||||
|
*/
|
||||||
|
set customLogger(
|
||||||
|
fn: (method: string, eventName: string, ...args: unknown[]) => unknown,
|
||||||
|
) {
|
||||||
|
this.customLogger_ = fn
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a browser event with an associated callback
|
||||||
|
*
|
||||||
|
* @param eventName - The name of the event to register
|
||||||
|
* @param callback - The callback function to be executed when the event is triggered
|
||||||
|
* @returns {Browser} The current browser instance, enabling method chaining
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Registering an event
|
||||||
|
* fw.event.register("showNotification", (message, color) => {
|
||||||
|
* // do something
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
* @see {@link https://git.entityseven.com/entityseven/rage-framework/wiki Wiki}
|
||||||
|
*/
|
||||||
|
public register<EventName extends T.RageFW_BrowserEvent>(
|
||||||
|
eventName: EventName,
|
||||||
|
callback: T.RageFW_BrowserCallback<EventName>,
|
||||||
|
): Browser {
|
||||||
|
this.log_('register', eventName, callback)
|
||||||
|
|
||||||
|
rpc.register<
|
||||||
|
Parameters<typeof callback>,
|
||||||
|
ReturnType<typeof callback>,
|
||||||
|
EventName
|
||||||
|
>(eventName, async (...data) => await callback(...data))
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters a browser event, removing the associated callback
|
||||||
|
*
|
||||||
|
* @param eventName - The name of the event to unregister
|
||||||
|
* @returns {Browser} The current browser instance, enabling method chaining
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Unregistering an event
|
||||||
|
* fw.event.unregister("showNotification")
|
||||||
|
*
|
||||||
|
* @see {@link https://git.entityseven.com/entityseven/rage-framework/wiki Wiki}
|
||||||
|
*/
|
||||||
|
public unregister<EventName extends T.RageFW_BrowserEvent>(
|
||||||
|
eventName: EventName,
|
||||||
|
): Browser {
|
||||||
|
rpc.unregister<EventName>(eventName)
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers a browser event from the browser with arguments from shared types
|
||||||
|
*
|
||||||
|
* Formerly known as ``call`` or ``emit``
|
||||||
|
*
|
||||||
|
* @param eventName - The name of the browser event to trigger
|
||||||
|
* @param [args] - Arguments for the browser event, if present
|
||||||
|
* @returns {Promise} resolving to the browser's response for the event
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Triggering a browser event without arguments
|
||||||
|
* fw.event.trigger("browserEventName")
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Triggering a browser event with arguments
|
||||||
|
* fw.event.trigger("browserEventName", ["message to me"])
|
||||||
|
*
|
||||||
|
* @see {@link https://git.entityseven.com/entityseven/rage-framework/wiki Wiki}
|
||||||
|
*/
|
||||||
|
public async trigger<EventName extends T.RageFW_BrowserEvent>(
|
||||||
|
eventName: EventName,
|
||||||
|
...args: T._BrowserEventHasArgs<EventName> extends true
|
||||||
|
? [T.RageFW_BrowserArgs<EventName>]
|
||||||
|
: []
|
||||||
|
): Promise<T.RageFW_BrowserReturn<EventName>> {
|
||||||
|
this.log_('[RPC](trigger):', eventName, ...args)
|
||||||
|
|
||||||
|
return await rpc.call<
|
||||||
|
typeof args,
|
||||||
|
EventName,
|
||||||
|
T.RageFW_BrowserReturn<EventName>
|
||||||
|
>(eventName, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers a server event from the browser with arguments from shared types
|
||||||
|
*
|
||||||
|
* Formerly known as ``callServer`` or ``emitServer``
|
||||||
|
*
|
||||||
|
* @param eventName - The name of the server event to trigger
|
||||||
|
* @param [args] - Arguments for the server event, if present
|
||||||
|
* @returns {Promise} resolving to the server's response for the event
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Triggering a server event without arguments
|
||||||
|
* fw.event.triggerServer("serverEventName")
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Triggering a server event with arguments
|
||||||
|
* fw.event.triggerServer("serverEventName", ["message to server"])
|
||||||
|
*
|
||||||
|
* @see {@link https://git.entityseven.com/entityseven/rage-framework/wiki Wiki}
|
||||||
|
*/
|
||||||
|
public async triggerServer<EventName extends T.RageFW_ServerEvent>(
|
||||||
|
eventName: EventName,
|
||||||
|
...args: T._ServerEventHasArgs<EventName> extends true
|
||||||
|
? [T.RageFW_ServerArgs<EventName>]
|
||||||
|
: []
|
||||||
|
): Promise<T.RageFW_ServerReturn<EventName>> {
|
||||||
|
this.log_('[RPC](triggerServer):', eventName, ...args)
|
||||||
|
|
||||||
|
return await rpc.callServer<
|
||||||
|
typeof args,
|
||||||
|
EventName,
|
||||||
|
T.RageFW_ServerReturn<EventName>
|
||||||
|
>(eventName, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers a client event from the browser with arguments from shared types
|
||||||
|
*
|
||||||
|
* Formerly known as ``callClient`` or ``emitClient``
|
||||||
|
*
|
||||||
|
* @param eventName - The name of the client event to trigger
|
||||||
|
* @param [args] - Arguments for the client event, if present
|
||||||
|
* @returns {Promise} resolving to the client's response for the event
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Triggering a client event without arguments
|
||||||
|
* fw.event.triggerClient("clientEventName")
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Triggering a client event with arguments
|
||||||
|
* fw.event.triggerClient("clientEventName", ["message to client"])
|
||||||
|
*
|
||||||
|
* @see {@link https://git.entityseven.com/entityseven/rage-framework/wiki Wiki}
|
||||||
|
*/
|
||||||
|
public async triggerClient<EventName extends T.RageFW_ClientEvent>(
|
||||||
|
eventName: EventName,
|
||||||
|
...args: T._ClientEventHasArgs<EventName> extends true
|
||||||
|
? [T.RageFW_ClientArgs<EventName>]
|
||||||
|
: []
|
||||||
|
): Promise<T.RageFW_ClientReturn<EventName>> {
|
||||||
|
this.log_('[RPC](triggerClient):', eventName, ...args)
|
||||||
|
|
||||||
|
return await rpc.callClient<
|
||||||
|
typeof args,
|
||||||
|
EventName,
|
||||||
|
T.RageFW_ClientReturn<EventName>
|
||||||
|
>(eventName, args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// new Browser()
|
||||||
|
// .register('customCefEvent', async (a, b) => true)
|
||||||
|
// .triggerServer('customServerEvent', ['', 1])
|
21
browser/src/core/helper.ts
Normal file
21
browser/src/core/helper.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
export class Helper {
|
||||||
|
protected debugLogs_: boolean = false
|
||||||
|
protected customLogger_:
|
||||||
|
| undefined
|
||||||
|
| ((method: string, eventName: string, ...args: unknown[]) => unknown) =
|
||||||
|
undefined
|
||||||
|
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
protected log_(
|
||||||
|
method: string,
|
||||||
|
eventName: string,
|
||||||
|
...args: unknown[]
|
||||||
|
): void {
|
||||||
|
if (this.customLogger_) {
|
||||||
|
this.customLogger_(method, eventName, ...args)
|
||||||
|
} else if (this.debugLogs_) {
|
||||||
|
console.log('[RPC](' + method + ')', eventName + ':', ...args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
3
browser/src/core/index.ts
Normal file
3
browser/src/core/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from './browser'
|
||||||
|
export * from './helper'
|
||||||
|
export * from './rpc'
|
6
browser/src/core/rpc.ts
Normal file
6
browser/src/core/rpc.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { Rpc } from '@entityseven/rage-fw-rpc'
|
||||||
|
|
||||||
|
export const rpc = new Rpc({
|
||||||
|
forceBrowserDevMode: process.env.RageFW_forceBrowserDevMode === 'true',
|
||||||
|
debugLogs: false,
|
||||||
|
})
|
16
browser/src/index.ts
Normal file
16
browser/src/index.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
import { Browser, rpc } from './core'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Package used on a browser-side of your Rage:MP Server
|
||||||
|
*
|
||||||
|
* @see {@link https://git.entityseven.com/entityseven/rage-framework/wiki Wiki}
|
||||||
|
*/
|
||||||
|
export const fw = {
|
||||||
|
/** Browser-side interactions */
|
||||||
|
event: new Browser(),
|
||||||
|
/** ``rage-fw-rpc`` instance used under the hood. It is highly recommended to use this one if you need it instead of creating a new instance */
|
||||||
|
rpc,
|
||||||
|
}
|
||||||
|
;(async () => {
|
||||||
|
await fw.event.triggerClient('cefReady')
|
||||||
|
})()
|
40
browser/src/types/browser.ts
Normal file
40
browser/src/types/browser.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
import type { RageFW_ICustomBrowserEvent } from '@entityseven/rage-fw-shared-types'
|
||||||
|
|
||||||
|
export type { RageFW_ICustomBrowserEvent } from '@entityseven/rage-fw-shared-types'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Union of all available browser event names
|
||||||
|
* These only include custom events
|
||||||
|
*/
|
||||||
|
export type RageFW_BrowserEvent = keyof RageFW_ICustomBrowserEvent
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of arguments of an event you pass as a generic
|
||||||
|
* These only include custom browser events
|
||||||
|
*/
|
||||||
|
export type RageFW_BrowserArgs<K extends RageFW_BrowserEvent> = Parameters<
|
||||||
|
RageFW_ICustomBrowserEvent[K]
|
||||||
|
>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return type of event you pass as a generic
|
||||||
|
* These only include custom browser events
|
||||||
|
*/
|
||||||
|
export type RageFW_BrowserReturn<K extends RageFW_BrowserEvent> = ReturnType<
|
||||||
|
RageFW_ICustomBrowserEvent[K]
|
||||||
|
>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback (function) of event you pass as a generic
|
||||||
|
* These only include custom browser events
|
||||||
|
*/
|
||||||
|
export type RageFW_BrowserCallback<K extends keyof RageFW_ICustomBrowserEvent> =
|
||||||
|
(...args: RageFW_BrowserArgs<K>) => Promise<RageFW_BrowserReturn<K>>
|
||||||
|
|
||||||
|
export type _BrowserEventHasArgs<
|
||||||
|
EventName extends keyof RageFW_ICustomBrowserEvent,
|
||||||
|
> = keyof RageFW_ICustomBrowserEvent extends never
|
||||||
|
? false
|
||||||
|
: Parameters<RageFW_ICustomBrowserEvent[EventName]>[0] extends undefined
|
||||||
|
? false
|
||||||
|
: true
|
33
browser/src/types/client.ts
Normal file
33
browser/src/types/client.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import type { RageFW_ICustomClientEvent } from '@entityseven/rage-fw-shared-types'
|
||||||
|
|
||||||
|
export type { RageFW_ICustomClientEvent } from '@entityseven/rage-fw-shared-types'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Union of all available client event names
|
||||||
|
* These only include custom events and some extras from RageFW
|
||||||
|
*/
|
||||||
|
export type RageFW_ClientEvent = keyof RageFW_ICustomClientEvent
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of arguments of event you pass as a generic
|
||||||
|
* These only include custom client events
|
||||||
|
*/
|
||||||
|
export type RageFW_ClientArgs<K extends RageFW_ClientEvent> = Parameters<
|
||||||
|
RageFW_ICustomClientEvent[K]
|
||||||
|
>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return type of event you pass as a generic
|
||||||
|
* These only include custom client events
|
||||||
|
*/
|
||||||
|
export type RageFW_ClientReturn<K extends RageFW_ClientEvent> = ReturnType<
|
||||||
|
RageFW_ICustomClientEvent[K]
|
||||||
|
>
|
||||||
|
|
||||||
|
export type _ClientEventHasArgs<
|
||||||
|
EventName extends keyof RageFW_ICustomClientEvent,
|
||||||
|
> = keyof RageFW_ICustomClientEvent extends never
|
||||||
|
? false
|
||||||
|
: Parameters<RageFW_ICustomClientEvent[EventName]>[0] extends undefined
|
||||||
|
? false
|
||||||
|
: true
|
3
browser/src/types/index.ts
Normal file
3
browser/src/types/index.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export * from './browser'
|
||||||
|
export * from './client'
|
||||||
|
export * from './server'
|
33
browser/src/types/server.ts
Normal file
33
browser/src/types/server.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import type { RageFW_ICustomServerEvent } from '@entityseven/rage-fw-shared-types'
|
||||||
|
|
||||||
|
export type { RageFW_ICustomServerEvent } from '@entityseven/rage-fw-shared-types'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Union of all available server event names
|
||||||
|
* These only include custom events
|
||||||
|
*/
|
||||||
|
export type RageFW_ServerEvent = keyof RageFW_ICustomServerEvent
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of arguments of event you pass as a generic
|
||||||
|
* These only include custom server events
|
||||||
|
*/
|
||||||
|
export type RageFW_ServerArgs<K extends RageFW_ServerEvent> = Parameters<
|
||||||
|
RageFW_ICustomServerEvent[K]
|
||||||
|
>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return type of event you pass as a generic
|
||||||
|
* These only include custom server events
|
||||||
|
*/
|
||||||
|
export type RageFW_ServerReturn<K extends RageFW_ServerEvent> = ReturnType<
|
||||||
|
RageFW_ICustomServerEvent[K]
|
||||||
|
>
|
||||||
|
|
||||||
|
export type _ServerEventHasArgs<
|
||||||
|
EventName extends keyof RageFW_ICustomServerEvent,
|
||||||
|
> = keyof RageFW_ICustomServerEvent extends never
|
||||||
|
? false
|
||||||
|
: Parameters<RageFW_ICustomServerEvent[EventName]>[0] extends undefined
|
||||||
|
? false
|
||||||
|
: true
|
25
browser/tsconfig.json
Normal file
25
browser/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
browser/tsup.config.ts
Normal file
12
browser/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,
|
||||||
|
})
|
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
|
21
cli/LICENSE
Normal file
21
cli/LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Entity Seven Group
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
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.
|
41
cli/package.json
Normal file
41
cli/package.json
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"name": "@entityseven/create-rage-fw",
|
||||||
|
"version": "0.1.2",
|
||||||
|
"bin": {
|
||||||
|
"rage-fw": "dist/index.js"
|
||||||
|
},
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"files": [
|
||||||
|
"dist/**/*",
|
||||||
|
"readme.md",
|
||||||
|
"LICENSE"
|
||||||
|
],
|
||||||
|
"scripts": {
|
||||||
|
"watch": "tsc -w",
|
||||||
|
"build": "tsup",
|
||||||
|
"start": "npx ./dist create"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@inquirer/prompts": "^5.0.5",
|
||||||
|
"ky": "^1.7.2",
|
||||||
|
"chalk": "4.1.2",
|
||||||
|
"yargs": "^17.7.2"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^20.14.2",
|
||||||
|
"@types/yargs": "^17.0.32",
|
||||||
|
"prettier": "^3.3.2",
|
||||||
|
"typescript": "^5.4.5"
|
||||||
|
},
|
||||||
|
"description": "CLI to scaffold a preview for Rage-FW",
|
||||||
|
"keywords": ["create-rage-fw","ragefw-cli", "ragefw", "rage-fw", "ragemp", "rage:mp", "rage", "gta5"],
|
||||||
|
"author": "Entity Seven Group",
|
||||||
|
"contributors": [
|
||||||
|
{
|
||||||
|
"name": "Danya H",
|
||||||
|
"email": "dev.rilaxik@gmail.com",
|
||||||
|
"url": "https://github.com/rilaxik/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT"
|
||||||
|
}
|
41
cli/readme.md
Normal file
41
cli/readme.md
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
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/) and [bun](https://bun.sh/)
|
||||||
|
|
||||||
|
``pnpm create @entityseven/rage-fw@latest``
|
||||||
|
|
||||||
|
``bun create @entityseven/rage-fw@latest``
|
||||||
|
|
||||||
|
# TL;DR
|
||||||
|
- ``Initialize new project`` - create new template project
|
||||||
|
- ``Test our RPC`` - scaffold an example for ``@entityseven/rage-fw-rpc``
|
||||||
|
- ``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``
|
||||||
|
- ``Test our RPC``
|
||||||
|
- ``Install RAGE:MP updater``
|
||||||
|
|
||||||
|
## Initialize new project
|
||||||
|
Using this option 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-example**
|
||||||
|
|
||||||
|
- ``Select front-end``
|
||||||
|
Use selector menu to choose which front-end framework you want to use. We will do our best to expand this menu with various solutions
|
||||||
|
|
||||||
|
## Test our RPC
|
||||||
|
Using this option 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-rpc-example**
|
||||||
|
|
||||||
|
- ``Select front-end``
|
||||||
|
Use selector menu to choose which front-end framework you want to use. We will do our best to expand this menu with various solutions
|
||||||
|
|
||||||
|
## Install Rage:MP updater
|
||||||
|
This option will simplify installation and update process of Rage:MP server files required to start your server
|
||||||
|
|
||||||
|
# Contribution
|
||||||
|
If you wish to help us in expanding examples selection with different framework you are very welcome to open PRs and Issues
|
61
cli/src/commands/create.ts
Normal file
61
cli/src/commands/create.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import c from 'chalk'
|
||||||
|
import { input, select } from '@inquirer/prompts'
|
||||||
|
import path from 'node:path'
|
||||||
|
import { cloneBranch } from '../utils/cloner'
|
||||||
|
|
||||||
|
export async function initProject() {
|
||||||
|
let folder
|
||||||
|
let framework
|
||||||
|
|
||||||
|
if (!folder) {
|
||||||
|
folder = await input({
|
||||||
|
message: c.gray('Enter project name:'),
|
||||||
|
default: 'rage-fw-example',
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.log(c.gray('Project name:'), folder)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!framework) {
|
||||||
|
framework = await select({
|
||||||
|
message: c.gray('Select front-end:'),
|
||||||
|
default: 'react-18',
|
||||||
|
loop: true,
|
||||||
|
choices: [
|
||||||
|
{
|
||||||
|
name: 'React 18',
|
||||||
|
value: 'react-18',
|
||||||
|
description: 'React 18 + TypeScript (Vite) as a front-end',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.log(c.gray('Front-end:'), framework)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
c.gray('\nScaffolding template project into'),
|
||||||
|
folder,
|
||||||
|
c.gray('with'),
|
||||||
|
framework,
|
||||||
|
c.gray('as a front-end..'),
|
||||||
|
)
|
||||||
|
|
||||||
|
cloneBranch(
|
||||||
|
'https://git.entityseven.com/entityseven/rage-framework-example',
|
||||||
|
path.join(process.cwd(), folder),
|
||||||
|
framework,
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
console.log(c.gray('Scaffolded project into'), folder)
|
||||||
|
console.log(
|
||||||
|
c.gray(
|
||||||
|
`Project was created ar dir: ${path.join(process.cwd(), folder)}`,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
console.log(c.red('Error occured: \n', e))
|
||||||
|
console.log(c.red('Please open an issue if you see this'))
|
||||||
|
})
|
||||||
|
}
|
44
cli/src/commands/download-updater.ts
Normal file
44
cli/src/commands/download-updater.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
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 ky = await import('ky').then(ky => ky.default)
|
||||||
|
const id = await getLatestReleaseID()
|
||||||
|
|
||||||
|
const latestAssets = `https://git.entityseven.com/api/v1/repos/entityseven/rage-server-downloader/releases/${id}/assets?page=1&limit=1`
|
||||||
|
|
||||||
|
ky.get<Asset[]>(latestAssets)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(async data => {
|
||||||
|
const downloadURL = data[0].browser_download_url
|
||||||
|
|
||||||
|
const file = await ky.get(data[0].browser_download_url)
|
||||||
|
const fileData = Buffer.from(
|
||||||
|
file as unknown as WithImplicitCoercion<string>,
|
||||||
|
'binary',
|
||||||
|
)
|
||||||
|
|
||||||
|
const fileSplit = downloadURL.split('/')
|
||||||
|
const fileName = fileSplit[fileSplit.length - 1]
|
||||||
|
|
||||||
|
fs.writeFileSync(`./${fileName}`, fileData)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getLatestReleaseID() {
|
||||||
|
const ky = await import('ky').then(ky => ky.default)
|
||||||
|
return ky
|
||||||
|
.get<Release[]>(latestReleases)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => data[0].id)
|
||||||
|
}
|
68
cli/src/commands/test-rpc.ts
Normal file
68
cli/src/commands/test-rpc.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import c from 'chalk'
|
||||||
|
import { input, select } from '@inquirer/prompts'
|
||||||
|
import path from 'node:path'
|
||||||
|
import { cloneBranch } from '../utils/cloner'
|
||||||
|
|
||||||
|
const choices = {
|
||||||
|
'rpc-react-18': {
|
||||||
|
name: 'React 18',
|
||||||
|
value: 'rpc-react-18',
|
||||||
|
description: 'Vite + React 18 + TypeScript as a front-end',
|
||||||
|
},
|
||||||
|
'rpc-svelte-5': {
|
||||||
|
name: 'Svelte 5',
|
||||||
|
value: 'rpc-svelte-5',
|
||||||
|
description: 'Vite + Svelte 5 + TypeScript as a front-end',
|
||||||
|
},
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export async function testRpc() {
|
||||||
|
let folder
|
||||||
|
let framework
|
||||||
|
|
||||||
|
if (!folder) {
|
||||||
|
folder = await input({
|
||||||
|
message: c.gray('Enter project name:'),
|
||||||
|
default: 'rage-fw-rpc-example',
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.log(c.gray('Project name:'), folder)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!framework) {
|
||||||
|
framework = await select({
|
||||||
|
message: c.gray('Select front-end:'),
|
||||||
|
default: 'rpc-react-18',
|
||||||
|
loop: true,
|
||||||
|
choices: Object.values(choices),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.log(c.gray('Front-end:'), framework)
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
c.gray('\nScaffolding template project into'),
|
||||||
|
folder,
|
||||||
|
c.gray('with'),
|
||||||
|
choices[framework].name,
|
||||||
|
c.gray('as a frontend..'),
|
||||||
|
)
|
||||||
|
|
||||||
|
cloneBranch(
|
||||||
|
'https://git.entityseven.com/entityseven/rage-framework-example',
|
||||||
|
path.join(process.cwd(), folder),
|
||||||
|
framework,
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
console.log(c.gray('Scaffolded project into'), folder)
|
||||||
|
console.log(
|
||||||
|
c.gray(
|
||||||
|
`Project was created at dir: ${path.join(process.cwd(), folder)}`,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.catch(e => {
|
||||||
|
console.log(c.red('Error occured: \n', e))
|
||||||
|
console.log(c.red('Please open an issue if you see this'))
|
||||||
|
})
|
||||||
|
}
|
67
cli/src/index.ts
Normal file
67
cli/src/index.ts
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
import c from 'chalk'
|
||||||
|
import { select } from '@inquirer/prompts'
|
||||||
|
|
||||||
|
import { checkForUpdates } from './utils/update'
|
||||||
|
import { initProject } from './commands/create'
|
||||||
|
import { downloadUpdater } from './commands/download-updater'
|
||||||
|
import { testRpc } from './commands/test-rpc'
|
||||||
|
|
||||||
|
enum Actions {
|
||||||
|
INIT_PROJECT = 'INIT_PROJECT',
|
||||||
|
TEST_RPC = 'TEST_RPC',
|
||||||
|
UPDATER = 'UPDATER',
|
||||||
|
}
|
||||||
|
|
||||||
|
process.on('exit', () => {
|
||||||
|
console.log(c.blueBright('\n\nRage FW CLI | Exiting..'))
|
||||||
|
process.exit(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
process.on('SIGINT', () => {
|
||||||
|
console.log(c.blueBright('\n\nRage FW CLI | Exiting..'))
|
||||||
|
process.exit(0)
|
||||||
|
})
|
||||||
|
;(async () => {
|
||||||
|
await checkForUpdates()
|
||||||
|
|
||||||
|
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 a new project',
|
||||||
|
value: Actions.INIT_PROJECT,
|
||||||
|
description: 'Initialize a new project and start developing',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Test our Rpc',
|
||||||
|
value: Actions.TEST_RPC,
|
||||||
|
description:
|
||||||
|
'Initialize a new skeleton project with our Rpc all set',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Install RAGE:MP updater',
|
||||||
|
value: Actions.UPDATER,
|
||||||
|
description:
|
||||||
|
'Use our tool to download or update RAGE:MP server files in just two clicks',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
loop: true,
|
||||||
|
})
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case Actions.INIT_PROJECT:
|
||||||
|
await initProject()
|
||||||
|
break
|
||||||
|
case Actions.TEST_RPC:
|
||||||
|
await testRpc()
|
||||||
|
break
|
||||||
|
case Actions.UPDATER:
|
||||||
|
await downloadUpdater()
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
console.log(c.red('Something went wrong..'))
|
||||||
|
console.log(c.red('Please open an issue if you see this'))
|
||||||
|
}
|
||||||
|
})()
|
24
cli/src/utils/cloner.ts
Normal file
24
cli/src/utils/cloner.ts
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
import { exec } from 'child_process'
|
||||||
|
|
||||||
|
export async function cloneBranch(link: string, path: string, branch: string) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const args = ['--single-branch', '-b', branch, '--', link, path]
|
||||||
|
const proc = exec('git clone ' + args.join(' '))
|
||||||
|
|
||||||
|
proc.on('close', (status: number) => {
|
||||||
|
if (status == 0) {
|
||||||
|
resolve(true)
|
||||||
|
} else if (status == 128) {
|
||||||
|
reject(
|
||||||
|
`Folder already exists. 'git clone' from branch ${branch} failed with status ` +
|
||||||
|
status,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
reject(
|
||||||
|
`'git clone' from branch ${branch} failed with status ` +
|
||||||
|
status,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
34
cli/src/utils/update.ts
Normal file
34
cli/src/utils/update.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
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 checkForUpdates(): Promise<void> {
|
||||||
|
const ky = await import('ky').then(ky => ky.default)
|
||||||
|
|
||||||
|
return new Promise(res => {
|
||||||
|
yargs.showVersion(version =>
|
||||||
|
ky
|
||||||
|
.get<Version[]>(latestVersionURL)
|
||||||
|
.then(response => response.json<Version[]>())
|
||||||
|
.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,
|
||||||
|
})
|
15
client/LICENSE
Normal file
15
client/LICENSE
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
Custom Attribution-NoDerivs Software License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Entity Seven Group
|
||||||
|
|
||||||
|
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.
|
@ -1,9 +0,0 @@
|
|||||||
import { build } from 'esbuild'
|
|
||||||
|
|
||||||
build({
|
|
||||||
entryPoints: ['./src/index.ts'],
|
|
||||||
format: 'esm',
|
|
||||||
platform: 'node',
|
|
||||||
target: 'node10.4',
|
|
||||||
outdir: './dist',
|
|
||||||
}).then(r => console.log('Successfully build.'))
|
|
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"compilationOptions": {
|
|
||||||
"followSymlinks": true,
|
|
||||||
"preferredConfigPath": "../tsconfig.json"
|
|
||||||
},
|
|
||||||
"entries": [
|
|
||||||
{
|
|
||||||
"filePath": "./src/index.ts",
|
|
||||||
"outFile": "./dist/index.d.ts"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,25 +1,38 @@
|
|||||||
{
|
{
|
||||||
"name": "rage-fw-client",
|
"name": "@entityseven/rage-fw-client",
|
||||||
"version": "0.0.5-alpha.0",
|
"version": "0.2.0",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"type": "module",
|
"types": "dist/src/index.d.ts",
|
||||||
"files": [
|
"files": [
|
||||||
"dist/**/*"
|
"dist/**/*",
|
||||||
|
"readme.md",
|
||||||
|
"LICENSE"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "node --es-module-specifier-resolution=node build.js",
|
"build": "tsup"
|
||||||
"types": "dts-bundle-generator --config dts.config.json"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"@ragempcommunity/types-client": "^2.1.8",
|
|
||||||
"rage-fw-shared-types": "workspace:^"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"rage-rpc": "^0.4.0"
|
"@entityseven/rage-fw-rpc": "0.2.5"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"peerDependencies": {
|
||||||
"author": "SashaGoncharov19",
|
"@entityseven/rage-fw-shared-types": "0.2.0",
|
||||||
"license": "MIT",
|
"@ragempcommunity/types-client": "^2.1.8"
|
||||||
"description": "Client side of rage-fw",
|
},
|
||||||
"gitHead": "053e4fd12aa120d53e11e0d2009c0df78c1a2ad0"
|
"description": "Package used on a client-side of your Rage:MP Server",
|
||||||
|
"keywords": ["rage-fw-client", "ragefw", "rage-fw", "ragemp", "rage:mp", "rage", "gta5"],
|
||||||
|
"author": "Entity Seven Group",
|
||||||
|
"contributors": [
|
||||||
|
{
|
||||||
|
"name": "Danya H",
|
||||||
|
"email": "dev.rilaxik@gmail.com",
|
||||||
|
"url": "https://github.com/rilaxik/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Oleksandr Honcharov",
|
||||||
|
"email": "0976053529@ukr.net",
|
||||||
|
"url": "https://github.com/SashaGoncharov19/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "Custom-Attribution-NoDerivs",
|
||||||
|
"gitHead": "ffd542c1deddb3033e16e0dae7557313ae09b05f"
|
||||||
}
|
}
|
||||||
|
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)
|
86
client/src/core/client.ts
Normal file
86
client/src/core/client.ts
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import { rpc } from './rpc'
|
||||||
|
import { Middleware } from './middleware'
|
||||||
|
import type * as T from '../types'
|
||||||
|
|
||||||
|
/** Client-side interactions */
|
||||||
|
export class Client {
|
||||||
|
/**
|
||||||
|
* Registers a client event with an associated callback
|
||||||
|
*
|
||||||
|
* @param eventName - The name of the event to register
|
||||||
|
* @param callback - The callback function to be executed when the event is triggered
|
||||||
|
* @param [options] - Optional settings for callback execution
|
||||||
|
* @param [options.middlewares] - Middleware functions to be checked before the callback executes
|
||||||
|
* @returns {Client} The current client instance, enabling method chaining
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Registering an event
|
||||||
|
* fw.event.register("playerDeath", (player, reason, killer) => {
|
||||||
|
* fw.system.log.info(player, reason, killer)
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Registering an event with middlewares
|
||||||
|
* fw.event.register("playerDeath", (player, reason, killer) => {
|
||||||
|
* fw.system.log.info(player, reason, killer)
|
||||||
|
* }, {
|
||||||
|
* middlewares: [ignoreSuicide] // <- your middlewares here
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
* // or
|
||||||
|
*
|
||||||
|
* fw.event.register("playerDeath", (player, reason, killer) => {
|
||||||
|
* fw.system.log.info(player, reason, killer)
|
||||||
|
* }, {
|
||||||
|
* middlewares: {
|
||||||
|
* executables: [ignoreSuicide], // <- your middlewares here
|
||||||
|
* onError: (msg) => fw.system.log.info(`${player.socialClub} has commited suicide`)
|
||||||
|
* }
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
* @see {@link https://git.entityseven.com/entityseven/rage-framework/wiki Wiki}
|
||||||
|
*/
|
||||||
|
public register<EventName extends T.RageFW_ClientEvent>(
|
||||||
|
eventName: EventName,
|
||||||
|
callback: T.RageFW_ClientCallback<EventName>,
|
||||||
|
options?: {
|
||||||
|
middlewares?: T.RageFW_MiddlewareOptions<EventName>
|
||||||
|
},
|
||||||
|
): Client {
|
||||||
|
rpc.register<
|
||||||
|
Parameters<typeof callback>,
|
||||||
|
ReturnType<typeof callback> | Promise<unknown>,
|
||||||
|
EventName
|
||||||
|
>(eventName, async (...data) => {
|
||||||
|
if (!options?.middlewares) return await callback(...data)
|
||||||
|
|
||||||
|
await Middleware.process(options.middlewares, callback, data)
|
||||||
|
})
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters a client event, removing the associated callback
|
||||||
|
*
|
||||||
|
* @param eventName - The name of the event to unregister
|
||||||
|
* @returns {Client} The current client instance, enabling method chaining
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Unregistering an event
|
||||||
|
* fw.event.unregister("playerDeath")
|
||||||
|
*
|
||||||
|
* @see {@link https://git.entityseven.com/entityseven/rage-framework/wiki Wiki}
|
||||||
|
*/
|
||||||
|
public unregister<EventName extends T.RageFW_ClientEvent>(
|
||||||
|
eventName: EventName,
|
||||||
|
): Client {
|
||||||
|
rpc.unregister<EventName>(eventName)
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// new Client()
|
||||||
|
// .register('customClientEvent', async (a, b) => true)
|
||||||
|
// .unregister('customClientEvent')
|
5
client/src/core/index.ts
Normal file
5
client/src/core/index.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export * from './client'
|
||||||
|
export * from './logger'
|
||||||
|
export * from './middleware'
|
||||||
|
export * from './player'
|
||||||
|
export * from './rpc'
|
40
client/src/core/logger.ts
Normal file
40
client/src/core/logger.ts
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
/**
|
||||||
|
* Used to log to a client in-game console
|
||||||
|
*/
|
||||||
|
export class Logger {
|
||||||
|
/**
|
||||||
|
* Informational logs. Colored in white
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* fw.system.log.info('some information to be logged')
|
||||||
|
*/
|
||||||
|
public info(...message: unknown[]) {
|
||||||
|
mp.console.logInfo(
|
||||||
|
`[${new Date().toLocaleTimeString()}] [INFO] ${message.join(' ')}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Warning logs. Colored in yellow
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* fw.system.log.warn('warning message')
|
||||||
|
*/
|
||||||
|
public warn(...message: unknown[]) {
|
||||||
|
mp.console.logWarning(
|
||||||
|
`[${new Date().toLocaleTimeString()}] [WARN] ${message.join(' ')}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error logs. Colored in red
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* fw.system.log.info('some error information')
|
||||||
|
*/
|
||||||
|
public error(...message: unknown[]) {
|
||||||
|
mp.console.logError(
|
||||||
|
`[${new Date().toLocaleTimeString()}] [ERROR] ${message.join(' ')}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
54
client/src/core/middleware.ts
Normal file
54
client/src/core/middleware.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import type * as T from '../types'
|
||||||
|
|
||||||
|
export class Middleware {
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
private static async execute<EventName extends T.RageFW_ClientEvent>(
|
||||||
|
middlewares: T.RageFW_MiddlewareFunction<EventName>[],
|
||||||
|
args: T.RageFW_ClientArgs<EventName>,
|
||||||
|
): Promise<T.RageFW_MiddlewareResponseInternal> {
|
||||||
|
for (let i = 0; i < middlewares.length; i++) {
|
||||||
|
const result = await middlewares[i](...args)
|
||||||
|
|
||||||
|
if (typeof result === 'boolean' && !result)
|
||||||
|
return { success: result, id: i }
|
||||||
|
if (typeof result !== 'boolean' && !result.success)
|
||||||
|
return { ...result, id: i }
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async process<EventName extends T.RageFW_ClientEvent>(
|
||||||
|
middlewareOptions: T.RageFW_MiddlewareOptions<EventName>,
|
||||||
|
callback: T.RageFW_ClientCallback<EventName>,
|
||||||
|
args: T.RageFW_ClientArgs<EventName>,
|
||||||
|
) {
|
||||||
|
if (Array.isArray(middlewareOptions)) {
|
||||||
|
const middlewaresResponse = await Middleware.execute(
|
||||||
|
middlewareOptions,
|
||||||
|
args,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (middlewaresResponse.success) return await callback(...args)
|
||||||
|
} else {
|
||||||
|
const middlewaresResponse = await Middleware.execute(
|
||||||
|
middlewareOptions.executables,
|
||||||
|
args,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (middlewaresResponse.success) {
|
||||||
|
return await callback(...args)
|
||||||
|
} else {
|
||||||
|
middlewareOptions.onError(
|
||||||
|
middlewaresResponse.message ??
|
||||||
|
'Middleware with id ' +
|
||||||
|
middlewaresResponse.id +
|
||||||
|
' failed',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
118
client/src/core/player.ts
Normal file
118
client/src/core/player.ts
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
import { rpc } from './rpc'
|
||||||
|
import type * as T from '../types'
|
||||||
|
|
||||||
|
/** Handles event manipulations that require player to be present in context */
|
||||||
|
export class Player {
|
||||||
|
private _browser: BrowserMp | undefined = undefined
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setter. Also shares browser with ``rage-fw-rpc``
|
||||||
|
*/
|
||||||
|
set browser(browser: BrowserMp) {
|
||||||
|
this._browser = browser
|
||||||
|
rpc.browser = browser
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers a client event from the client with arguments from shared types
|
||||||
|
*
|
||||||
|
* Formerly known as ``call`` or ``emit``
|
||||||
|
*
|
||||||
|
* @param eventName - The name of the client event to trigger
|
||||||
|
* @param [args] - Arguments for the client event, if present
|
||||||
|
* @returns {Promise} resolving to the client's response for the event
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Triggering a client event without arguments
|
||||||
|
* fw.player.trigger("clientEventName")
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Triggering a client event with arguments
|
||||||
|
* fw.player.trigger("clientEventName", ["message to me"])
|
||||||
|
*
|
||||||
|
* @see {@link https://git.entityseven.com/entityseven/rage-framework/wiki Wiki}
|
||||||
|
*/
|
||||||
|
public async trigger<EventName extends keyof T.RageFW_ICustomClientEvent>(
|
||||||
|
eventName: EventName,
|
||||||
|
...args: T._ClientEventHasArgs<EventName> extends true
|
||||||
|
? [T.RageFW_ClientArgs<EventName>]
|
||||||
|
: []
|
||||||
|
): Promise<T.RageFW_ClientReturn<EventName>> {
|
||||||
|
return await rpc.call<
|
||||||
|
typeof args,
|
||||||
|
EventName,
|
||||||
|
T.RageFW_ClientReturn<EventName>
|
||||||
|
>(eventName, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers a server event from the client with arguments from shared types
|
||||||
|
*
|
||||||
|
* Formerly known as ``callServer`` or ``emitServer``
|
||||||
|
*
|
||||||
|
* @param eventName - The name of the server event to trigger
|
||||||
|
* @param [args] - Arguments for the server event, if present
|
||||||
|
* @returns {Promise} resolving to the server's response for the event
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Triggering a server event without arguments
|
||||||
|
* fw.player.triggerServer("serverEventName")
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Triggering a server event with arguments
|
||||||
|
* fw.player.triggerServer("serverEventName", ["message to server"])
|
||||||
|
*
|
||||||
|
* @see {@link https://git.entityseven.com/entityseven/rage-framework/wiki Wiki}
|
||||||
|
*/
|
||||||
|
public async triggerServer<EventName extends T.RageFW_ServerEvent>(
|
||||||
|
eventName: EventName,
|
||||||
|
...args: T._ServerEventHasArgs<EventName> extends true
|
||||||
|
? [T.RageFW_ServerArgs<EventName>]
|
||||||
|
: []
|
||||||
|
): Promise<T.RageFW_ClientServerReturn<EventName>> {
|
||||||
|
return await rpc.callServer<
|
||||||
|
typeof args,
|
||||||
|
EventName,
|
||||||
|
T.RageFW_ClientServerReturn<EventName>
|
||||||
|
>(eventName, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers a browser event from the client with arguments from shared types
|
||||||
|
*
|
||||||
|
* Formerly known as ``callBrowser`` or ``emitBrowser``
|
||||||
|
*
|
||||||
|
* @param eventName - The name of the browser event to trigger
|
||||||
|
* @param [args] - Arguments for the browser event, if present
|
||||||
|
* @returns {Promise} resolving to the browser's response for the event
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Triggering a browser event without arguments
|
||||||
|
* fw.player.triggerBrowser("browserEventName")
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Triggering a browser event with arguments
|
||||||
|
* fw.player.triggerBrowser("browserEventName", ["message to browser"])
|
||||||
|
*
|
||||||
|
* @see {@link https://git.entityseven.com/entityseven/rage-framework/wiki Wiki}
|
||||||
|
*/
|
||||||
|
public async triggerBrowser<EventName extends T.RageFW_BrowserEvent>(
|
||||||
|
eventName: EventName,
|
||||||
|
...args: T._BrowserEventHasArgs<EventName> extends true
|
||||||
|
? [T.RageFW_BrowserArgs<EventName>]
|
||||||
|
: []
|
||||||
|
): Promise<T.RageFW_BrowserReturn<EventName>> {
|
||||||
|
if (!this._browser)
|
||||||
|
throw new Error('You need to initialize browser first')
|
||||||
|
|
||||||
|
return await rpc.callBrowser<
|
||||||
|
typeof args,
|
||||||
|
EventName,
|
||||||
|
T.RageFW_BrowserReturn<EventName>
|
||||||
|
>(eventName, args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// new Player().trigger('customClientEvent', ['', 1])
|
||||||
|
// new Player().triggerServer('customServerEvent', ['', 1])
|
||||||
|
// new Player().triggerBrowser('customCefEvent', ['', 1])
|
5
client/src/core/rpc.ts
Normal file
5
client/src/core/rpc.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { Rpc } from '@entityseven/rage-fw-rpc'
|
||||||
|
|
||||||
|
export const rpc = new Rpc({
|
||||||
|
debugLogs: false,
|
||||||
|
})
|
99
client/src/data/keys.ts
Normal file
99
client/src/data/keys.ts
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
export const KEY_NONE = 0
|
||||||
|
export const KEY_ENTER = 0x0d
|
||||||
|
export const KEY_TAB = 0x09
|
||||||
|
export const KEY_BACKSPACE = 0x08
|
||||||
|
export const KEY_SHIFT = 0x10
|
||||||
|
export const KEY_CTRL = 0x11
|
||||||
|
export const KEY_ALT = 0x12
|
||||||
|
export const KEY_PAUSE = 0x13
|
||||||
|
export const KEY_CAPS_LOCK = 0x14
|
||||||
|
export const KEY_ESCAPE = 0x1b
|
||||||
|
export const KEY_SPACE = 0x20
|
||||||
|
export const KEY_PAGE_UP = 0x21
|
||||||
|
export const KEY_PAGE_DOWN = 0x22
|
||||||
|
export const KEY_END = 0x23
|
||||||
|
export const KEY_HOME = 0x24
|
||||||
|
export const KEY_LEFT = 0x25
|
||||||
|
export const KEY_UP = 0x26
|
||||||
|
export const KEY_RIGHT = 0x27
|
||||||
|
export const KEY_DOWN = 0x28
|
||||||
|
export const KEY_INSERT = 0x2d
|
||||||
|
export const KEY_DELETE = 0x2e
|
||||||
|
export const KEY_0 = 0x30
|
||||||
|
export const KEY_1 = 0x31
|
||||||
|
export const KEY_2 = 0x32
|
||||||
|
export const KEY_3 = 0x33
|
||||||
|
export const KEY_4 = 0x34
|
||||||
|
export const KEY_5 = 0x35
|
||||||
|
export const KEY_6 = 0x36
|
||||||
|
export const KEY_7 = 0x37
|
||||||
|
export const KEY_8 = 0x38
|
||||||
|
export const KEY_9 = 0x39
|
||||||
|
export const KEY_A = 0x41
|
||||||
|
export const KEY_B = 0x42
|
||||||
|
export const KEY_C = 0x43
|
||||||
|
export const KEY_D = 0x44
|
||||||
|
export const KEY_E = 0x45
|
||||||
|
export const KEY_F = 0x46
|
||||||
|
export const KEY_G = 0x47
|
||||||
|
export const KEY_H = 0x48
|
||||||
|
export const KEY_I = 0x49
|
||||||
|
export const KEY_J = 0x4a
|
||||||
|
export const KEY_K = 0x4b
|
||||||
|
export const KEY_L = 0x4c
|
||||||
|
export const KEY_M = 0x4d
|
||||||
|
export const KEY_N = 0x4e
|
||||||
|
export const KEY_O = 0x4f
|
||||||
|
export const KEY_P = 0x50
|
||||||
|
export const KEY_Q = 0x51
|
||||||
|
export const KEY_R = 0x52
|
||||||
|
export const KEY_S = 0x53
|
||||||
|
export const KEY_T = 0x54
|
||||||
|
export const KEY_U = 0x55
|
||||||
|
export const KEY_V = 0x56
|
||||||
|
export const KEY_W = 0x57
|
||||||
|
export const KEY_X = 0x58
|
||||||
|
export const KEY_Y = 0x59
|
||||||
|
export const KEY_Z = 0x5a
|
||||||
|
export const KEY_LEFT_WINDOWS = 0x5b
|
||||||
|
export const KEY_RIGHT_WINDOWS = 0x5c
|
||||||
|
export const KEY_CONTEXT_MENU = 0x5d
|
||||||
|
export const KEY_NUMPAD_0 = 0x60
|
||||||
|
export const KEY_NUMPAD_1 = 0x61
|
||||||
|
export const KEY_NUMPAD_2 = 0x62
|
||||||
|
export const KEY_NUMPAD_3 = 0x63
|
||||||
|
export const KEY_NUMPAD_4 = 0x64
|
||||||
|
export const KEY_NUMPAD_5 = 0x65
|
||||||
|
export const KEY_NUMPAD_6 = 0x66
|
||||||
|
export const KEY_NUMPAD_7 = 0x67
|
||||||
|
export const KEY_NUMPAD_8 = 0x68
|
||||||
|
export const KEY_NUMPAD_9 = 0x69
|
||||||
|
export const KEY_MULTIPLY = 0x6a
|
||||||
|
export const KEY_ADD = 0x6b
|
||||||
|
export const KEY_SEPARATOR = 0x6c
|
||||||
|
export const KEY_SUBTRACT = 0x6d
|
||||||
|
export const KEY_DECIMAL = 0x6e
|
||||||
|
export const KEY_DIVIDE = 0x6f
|
||||||
|
export const KEY_F1 = 0x70
|
||||||
|
export const KEY_F2 = 0x71
|
||||||
|
export const KEY_F3 = 0x72
|
||||||
|
export const KEY_F4 = 0x73
|
||||||
|
export const KEY_F5 = 0x74
|
||||||
|
export const KEY_F6 = 0x75
|
||||||
|
export const KEY_F7 = 0x76
|
||||||
|
export const KEY_F8 = 0x77
|
||||||
|
export const KEY_F9 = 0x78
|
||||||
|
export const KEY_F10 = 0x79
|
||||||
|
export const KEY_F11 = 0x7a
|
||||||
|
export const KEY_F12 = 0x7b
|
||||||
|
export const KEY_NUM_LOCK = 0x90
|
||||||
|
export const KEY_SCROLL_LOCK = 0x91
|
||||||
|
export const KEY_LEFT_SHIFT = 0xa0
|
||||||
|
export const KEY_RIGHT_SHIFT = 0xa1
|
||||||
|
export const KEY_LEFT_CTRL = 0xa2
|
||||||
|
export const KEY_RIGHT_CTRL = 0xa3
|
||||||
|
export const KEY_LEFT_ALT = 0xa4
|
||||||
|
export const KEY_RIGHT_ALT = 0xa5
|
||||||
|
export const VK_TILDE = 0xc0
|
||||||
|
export const VK_LBUTTON = 0x01
|
||||||
|
export const VK_RBUTTON = 0x02
|
@ -1,19 +1,22 @@
|
|||||||
import rpc from 'rage-rpc'
|
import { Client, Logger, Player, rpc } from './core'
|
||||||
import type {
|
|
||||||
RageFW_ClientEventReturn,
|
|
||||||
RageFW_ClientEvent,
|
|
||||||
RageFW_ClientEventArguments,
|
|
||||||
} from './types'
|
|
||||||
|
|
||||||
class Player {
|
export type { RageFW_MiddlewareFunction } from './types'
|
||||||
public triggerServer<EventName extends RageFW_ClientEvent>(
|
|
||||||
eventName: EventName,
|
|
||||||
...args: RageFW_ClientEventArguments<EventName>
|
|
||||||
): Promise<RageFW_ClientEventReturn<EventName>> {
|
|
||||||
return rpc.callServer(eventName, ...args)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const rage = {
|
/**
|
||||||
|
* Package used on a client-side of your Rage:MP Server
|
||||||
|
*
|
||||||
|
* @see {@link https://git.entityseven.com/entityseven/rage-framework/wiki Wiki}
|
||||||
|
*/
|
||||||
|
export const fw = {
|
||||||
|
/** Client-side interactions */
|
||||||
|
event: new Client(),
|
||||||
|
/** Handles event manipulations that require player to be present in context */
|
||||||
player: new Player(),
|
player: new Player(),
|
||||||
|
/** Handles functions used to interact with the client environment */
|
||||||
|
system: {
|
||||||
|
/** Used to log in a client in-game console */
|
||||||
|
log: new Logger(),
|
||||||
|
},
|
||||||
|
/** ``rage-fw-rpc`` instance used under the hood. It is highly recommended to use this one if you need it instead of creating a new instance */
|
||||||
|
rpc,
|
||||||
}
|
}
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
/// <reference types="@ragempcommunity/types-client" />
|
|
||||||
|
|
||||||
import type { RageFW_ICustomClientEvent } from 'rage-fw-shared-types'
|
|
||||||
|
|
||||||
export type RageFW_ClientEvent =
|
|
||||||
| keyof RageFW_ICustomClientEvent
|
|
||||||
| keyof IClientEvents
|
|
||||||
|
|
||||||
export type RageFW_ClientEventArguments<K extends RageFW_ClientEvent> =
|
|
||||||
K extends keyof RageFW_ICustomClientEvent
|
|
||||||
? Parameters<RageFW_ICustomClientEvent[K]>
|
|
||||||
: (K extends keyof IClientEvents ? IClientEvents[K] : never)[]
|
|
||||||
|
|
||||||
export type RageFW_ClientEventReturn<K extends RageFW_ClientEvent> =
|
|
||||||
K extends keyof RageFW_ICustomClientEvent
|
|
||||||
? ReturnType<RageFW_ICustomClientEvent[K]>
|
|
||||||
: never
|
|
29
client/src/types/browser.ts
Normal file
29
client/src/types/browser.ts
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
/// <reference types="@ragempcommunity/types-client" />
|
||||||
|
|
||||||
|
import type { RageFW_ICustomBrowserEvent } from '@entityseven/rage-fw-shared-types'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Union of all available browser event names callable from client
|
||||||
|
* These only include custom events
|
||||||
|
*/
|
||||||
|
export type RageFW_BrowserEvent = keyof RageFW_ICustomBrowserEvent
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of arguments for an event, name of which you pass as a generic
|
||||||
|
* These only include custom events
|
||||||
|
*/
|
||||||
|
export type RageFW_BrowserArgs<K extends RageFW_BrowserEvent> = Parameters<
|
||||||
|
RageFW_ICustomBrowserEvent[K]
|
||||||
|
>
|
||||||
|
|
||||||
|
export type RageFW_BrowserReturn<K extends RageFW_BrowserEvent> = ReturnType<
|
||||||
|
RageFW_ICustomBrowserEvent[K]
|
||||||
|
>
|
||||||
|
|
||||||
|
export type _BrowserEventHasArgs<
|
||||||
|
EventName extends keyof RageFW_ICustomBrowserEvent,
|
||||||
|
> = keyof RageFW_ICustomBrowserEvent extends never
|
||||||
|
? false
|
||||||
|
: Parameters<RageFW_ICustomBrowserEvent[EventName]>[0] extends undefined
|
||||||
|
? false
|
||||||
|
: true
|
54
client/src/types/client.ts
Normal file
54
client/src/types/client.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/// <reference types="@ragempcommunity/types-client" />
|
||||||
|
|
||||||
|
import type { RageFW_ICustomClientEvent } from '@entityseven/rage-fw-shared-types'
|
||||||
|
|
||||||
|
export type { RageFW_ICustomClientEvent } from '@entityseven/rage-fw-shared-types'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Union of all available client event names
|
||||||
|
* These include custom and system events
|
||||||
|
*/
|
||||||
|
export type RageFW_ClientEvent =
|
||||||
|
| keyof RageFW_ICustomClientEvent
|
||||||
|
| keyof IClientEvents
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of arguments for an event, name of which you pass as a generic
|
||||||
|
* These include custom and system events
|
||||||
|
*/
|
||||||
|
export type RageFW_ClientArgs<K extends RageFW_ClientEvent> =
|
||||||
|
K extends keyof RageFW_ICustomClientEvent
|
||||||
|
? Parameters<RageFW_ICustomClientEvent[K]>
|
||||||
|
: K extends keyof IClientEvents
|
||||||
|
? Parameters<IClientEvents[K]>
|
||||||
|
: never
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return type for an event, name of which you pass as a generic
|
||||||
|
* These include custom and system events
|
||||||
|
*/
|
||||||
|
export type RageFW_ClientReturn<K extends RageFW_ClientEvent> =
|
||||||
|
K extends keyof RageFW_ICustomClientEvent
|
||||||
|
? ReturnType<RageFW_ICustomClientEvent[K]>
|
||||||
|
: K extends keyof IClientEvents
|
||||||
|
? ReturnType<IClientEvents[K]>
|
||||||
|
: void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback (function) for an event, name of which you pass as a generic
|
||||||
|
* These include custom and system events
|
||||||
|
*/
|
||||||
|
export type RageFW_ClientCallback<K extends RageFW_ClientEvent> = (
|
||||||
|
...args: RageFW_ClientArgs<K>
|
||||||
|
) => Promise<RageFW_ClientReturn<K>>
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export type _ClientEventHasArgs<
|
||||||
|
EventName extends keyof RageFW_ICustomClientEvent,
|
||||||
|
> = keyof RageFW_ICustomClientEvent extends never
|
||||||
|
? false
|
||||||
|
: Parameters<RageFW_ICustomClientEvent[EventName]>[0] extends undefined
|
||||||
|
? false
|
||||||
|
: true
|
4
client/src/types/index.ts
Normal file
4
client/src/types/index.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export * from './browser'
|
||||||
|
export * from './client'
|
||||||
|
export * from './middleware'
|
||||||
|
export * from './server'
|
26
client/src/types/middleware.ts
Normal file
26
client/src/types/middleware.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import type * as T from './client'
|
||||||
|
|
||||||
|
export type RageFW_MiddlewareResponse =
|
||||||
|
| {
|
||||||
|
success: boolean
|
||||||
|
message?: string
|
||||||
|
}
|
||||||
|
| boolean
|
||||||
|
|
||||||
|
export type RageFW_MiddlewareResponseInternal = {
|
||||||
|
success: boolean
|
||||||
|
message?: string
|
||||||
|
id?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RageFW_MiddlewareFunction<EventName extends T.RageFW_ClientEvent> =
|
||||||
|
(
|
||||||
|
...args: T.RageFW_ClientArgs<EventName>
|
||||||
|
) => Promise<RageFW_MiddlewareResponse>
|
||||||
|
|
||||||
|
export type RageFW_MiddlewareOptions<EventName extends T.RageFW_ClientEvent> =
|
||||||
|
| RageFW_MiddlewareFunction<EventName>[]
|
||||||
|
| {
|
||||||
|
executables: RageFW_MiddlewareFunction<EventName>[]
|
||||||
|
onError: (error: string) => unknown
|
||||||
|
}
|
38
client/src/types/server.ts
Normal file
38
client/src/types/server.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/// <reference types="@ragempcommunity/types-client" />
|
||||||
|
|
||||||
|
import type {
|
||||||
|
RageFW_ICustomClientEvent,
|
||||||
|
RageFW_ICustomServerEvent,
|
||||||
|
} from '@entityseven/rage-fw-shared-types'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Union of all available server event names callable from client
|
||||||
|
* These only include custom events
|
||||||
|
*/
|
||||||
|
export type RageFW_ServerEvent = keyof RageFW_ICustomServerEvent
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of arguments for an event, name of which you pass as a generic
|
||||||
|
* These only include custom events
|
||||||
|
*/
|
||||||
|
export type RageFW_ServerArgs<K extends RageFW_ServerEvent> =
|
||||||
|
K extends keyof RageFW_ICustomServerEvent
|
||||||
|
? Parameters<RageFW_ICustomServerEvent[K]>
|
||||||
|
: never
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return type for an event, name of which you pass as a generic
|
||||||
|
* These only include custom events
|
||||||
|
*/
|
||||||
|
export type RageFW_ClientServerReturn<K extends RageFW_ServerEvent> =
|
||||||
|
K extends keyof RageFW_ICustomServerEvent
|
||||||
|
? ReturnType<RageFW_ICustomServerEvent[K]>
|
||||||
|
: never
|
||||||
|
|
||||||
|
export type _ServerEventHasArgs<
|
||||||
|
EventName extends keyof RageFW_ICustomServerEvent,
|
||||||
|
> = keyof RageFW_ICustomClientEvent extends never
|
||||||
|
? false
|
||||||
|
: Parameters<RageFW_ICustomServerEvent[EventName]>[0] extends undefined
|
||||||
|
? false
|
||||||
|
: true
|
@ -1,9 +1,25 @@
|
|||||||
{
|
{
|
||||||
"extends": "../tsconfig.json",
|
"$schema": "https://json.schemastore.org/tsconfig",
|
||||||
|
"display": "Base",
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"typeRoots": [
|
"incremental": false,
|
||||||
"@ragempcommunity/types-client"
|
"composite": false,
|
||||||
],
|
"target": "ES2022",
|
||||||
"baseUrl": "./src"
|
"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
client/tsup.config.ts
Normal file
12
client/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,
|
||||||
|
})
|
@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
|
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
|
||||||
"version": "0.0.5-alpha.0",
|
"version": "0.2.1-0.2.0-alpha.2.0",
|
||||||
"npmClient": "pnpm"
|
"npmClient": "pnpm"
|
||||||
}
|
}
|
||||||
|
39
package.json
39
package.json
@ -1,15 +1,44 @@
|
|||||||
{
|
{
|
||||||
"private": true,
|
"scripts": {
|
||||||
|
"publish": "lerna publish --force-publish",
|
||||||
|
"build": "lerna run build",
|
||||||
|
"lint": "eslint --c .eslintrc.yaml --ext .ts client/ server/ shared-types/",
|
||||||
|
|
||||||
|
"rebuild:browser": "cd browser && pnpm build",
|
||||||
|
"rebuild:client": "cd client && pnpm build",
|
||||||
|
"rebuild:server": "cd server && pnpm build",
|
||||||
|
"rebuild": "pnpm rebuild:browser && pnpm rebuild:client && pnpm rebuild:server"
|
||||||
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@microsoft/api-extractor": "^7.47.0",
|
||||||
"@ragempcommunity/types-cef": "^2.1.8",
|
"@ragempcommunity/types-cef": "^2.1.8",
|
||||||
"@ragempcommunity/types-client": "^2.1.8",
|
"@ragempcommunity/types-client": "^2.1.8",
|
||||||
"@ragempcommunity/types-server": "^2.1.8",
|
"@ragempcommunity/types-server": "^2.1.8",
|
||||||
"dts-bundle-generator": "^9.5.1",
|
"@typescript-eslint/eslint-plugin": "^7.13.0",
|
||||||
"esbuild": "^0.21.5",
|
"@typescript-eslint/parser": "^7.13.0",
|
||||||
|
"@types/node": "^22.8.1",
|
||||||
|
"eslint": "^8.56.0",
|
||||||
|
"lerna": "^8.1.3",
|
||||||
"prettier": "^3.3.1",
|
"prettier": "^3.3.1",
|
||||||
"rage-rpc": "^0.4.0",
|
"rage-rpc": "^0.4.0",
|
||||||
|
"tsup": "^8.1.0",
|
||||||
"typescript": "^5.4.5",
|
"typescript": "^5.4.5",
|
||||||
"lerna": "^8.1.3"
|
"winston": "^3.13.0"
|
||||||
},
|
},
|
||||||
"type": "module"
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"license": "SEE INDIVIDUALLY FOR EACH PACKAGE",
|
||||||
|
"author": "Entity Seven Group",
|
||||||
|
"contributors": [
|
||||||
|
{
|
||||||
|
"name": "Danya H",
|
||||||
|
"email": "dev.rilaxik@gmail.com",
|
||||||
|
"url": "https://github.com/rilaxik/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Oleksandr Honcharov",
|
||||||
|
"email": "0976053529@ukr.net",
|
||||||
|
"url": "https://github.com/SashaGoncharov19/"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
2231
pnpm-lock.yaml
generated
2231
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
|||||||
packages:
|
packages:
|
||||||
- "server"
|
- "server"
|
||||||
- "client"
|
- "client"
|
||||||
- "shared"
|
- "browser"
|
||||||
- "shared-types"
|
- "shared-types"
|
32
readme.md
Normal file
32
readme.md
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
# Rage Framework (RageFW)
|
||||||
|
RageFW is a type-safe framework for developing Rage:MP servers. Designed with developers in mind, RageFW brings structure and efficiency to your Rage:MP servers, ensuring robust and maintainable code
|
||||||
|
|
||||||
|
## Features
|
||||||
|
- **Type-Safe Development:** Eliminate runtime errors and enhance code reliability with RageFW comprehensive type safety, making your RP server's development smoother than a Sunday drive through Los Santos
|
||||||
|
|
||||||
|
- **Wrapped RPC client:** Communicate effortlessly between server, client and cef with RPC system, wrapped in a cozy custom-typed blanket for your peace of mind
|
||||||
|
|
||||||
|
- **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
|
||||||
|
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 @entityseven/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
|
||||||
|
|
||||||
|
## 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*
|
6
rpc/.prettierrc.yaml
Normal file
6
rpc/.prettierrc.yaml
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
tabWidth: 4
|
||||||
|
printWidth: 80
|
||||||
|
singleQuote: true
|
||||||
|
semi: false
|
||||||
|
arrowParens: avoid
|
||||||
|
endOfLine: auto
|
21
rpc/LICENSE
Normal file
21
rpc/LICENSE
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Entity Seven Group
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
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.
|
26
rpc/index.d.ts
vendored
Normal file
26
rpc/index.d.ts
vendored
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
export {}
|
||||||
|
|
||||||
|
interface Mp {
|
||||||
|
trigger(event: string, data?: any): void
|
||||||
|
events: {
|
||||||
|
add(event: string, data: any): void
|
||||||
|
call(event: string, data: any): void
|
||||||
|
callRemote(event: string, data: any): void
|
||||||
|
remove(event: string): void
|
||||||
|
}
|
||||||
|
joaat?: unknown
|
||||||
|
game: {
|
||||||
|
joaat?: unknown
|
||||||
|
}
|
||||||
|
console: {
|
||||||
|
logInfo: (...args: unknown[]) => void
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
declare global {
|
||||||
|
const mp: Mp
|
||||||
|
const global: Record<string, (...args: any[]) => unknown>
|
||||||
|
interface Window {
|
||||||
|
[p: string]: any
|
||||||
|
}
|
||||||
|
}
|
44
rpc/package.json
Normal file
44
rpc/package.json
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
{
|
||||||
|
"name": "@entityseven/rage-fw-rpc",
|
||||||
|
"version": "0.2.5",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"types": "dist/src/index.d.ts",
|
||||||
|
"scripts": {
|
||||||
|
"build": "tsup",
|
||||||
|
"start": "npx ./dist create"
|
||||||
|
},
|
||||||
|
"files": [
|
||||||
|
"dist/**/*",
|
||||||
|
"readme.md",
|
||||||
|
"LICENSE"
|
||||||
|
],
|
||||||
|
"devDependencies": {
|
||||||
|
"@microsoft/api-extractor": "^7.47.9",
|
||||||
|
"prettier": "^3.3.2",
|
||||||
|
"tsup": "^8.3.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"typescript": "^5"
|
||||||
|
},
|
||||||
|
"description": "Rage-FW RPC (Remote procedure caller) for Rage:MP",
|
||||||
|
"keywords": [
|
||||||
|
"ragefw",
|
||||||
|
"rage-fw",
|
||||||
|
"ragemp",
|
||||||
|
"rage",
|
||||||
|
"rpc",
|
||||||
|
"rage-rpc",
|
||||||
|
"ragerpc",
|
||||||
|
"gta5"
|
||||||
|
],
|
||||||
|
"author": "Entity Seven Group",
|
||||||
|
"contributors": [
|
||||||
|
{
|
||||||
|
"name": "Danya H",
|
||||||
|
"email": "dev.rilaxik@gmail.com",
|
||||||
|
"url": "https://github.com/rilaxik/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"gitHead": "04eb7240735c4a0e4855ebabbe8d5b326819fa76"
|
||||||
|
}
|
98
rpc/readme.md
Normal file
98
rpc/readme.md
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
# Rage-FW-RPC
|
||||||
|
is an all-in package with asynchronous RPC implementation for RageMP servers in JS/TS
|
||||||
|
|
||||||
|
# Installation
|
||||||
|
``` shell
|
||||||
|
npm i @entityseven/rage-fw-rpc
|
||||||
|
```
|
||||||
|
```shell
|
||||||
|
pnpm i @entityseven/rage-fw-rpc
|
||||||
|
```
|
||||||
|
```shell
|
||||||
|
yarn add @entityseven/rage-fw-rpc
|
||||||
|
```
|
||||||
|
|
||||||
|
Import installed package and initialize rpc:
|
||||||
|
```ts
|
||||||
|
// lib/rpc.js
|
||||||
|
|
||||||
|
import { Rpc } from 'rage-fw-rpc'
|
||||||
|
export const rpc = new Rpc(/* options */)
|
||||||
|
```
|
||||||
|
|
||||||
|
# Motivation
|
||||||
|
The idea was to create an extensible package, with various features to simplify the development process and provide as much comfort as possible. It should also be using similar architecture as the framework it was specially built for
|
||||||
|
|
||||||
|
Inspired by usage of [rage-rpc](https://github.com/micaww/rage-rpc)
|
||||||
|
|
||||||
|
# Features
|
||||||
|
- Type-safe events via [TS generics](https://www.typescriptlang.org/docs/handbook/2/generics.html), avoiding type wrappers
|
||||||
|
- Built-in logging options for each environment
|
||||||
|
- Error-safe developer mode for browser
|
||||||
|
- Calls can receive response from called environments via Promises (browser -> server -> browser, etc.)
|
||||||
|
- Actual human-readable errors
|
||||||
|
|
||||||
|
# Docs
|
||||||
|
## [Extended version available here](https://git.entityseven.com/entityseven/rage-framework/wiki/RPC%400.2.5)
|
||||||
|
|
||||||
|
## register
|
||||||
|
Registers a callback function for a specified event
|
||||||
|
```ts
|
||||||
|
rpc.register('playerJoin', (player) => {
|
||||||
|
console.log(`Connected: ${player.socialClub}`)
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## unregister
|
||||||
|
Unregisters callback function for a specified event
|
||||||
|
```ts
|
||||||
|
rpc.unregister('playerDamage')
|
||||||
|
```
|
||||||
|
|
||||||
|
## callClient
|
||||||
|
Calls a client-side event from server or browser
|
||||||
|
|
||||||
|
From browser:
|
||||||
|
```ts
|
||||||
|
rpc.callClient('updatePlayerData', ['argument']).then(response => {
|
||||||
|
console.log(`Received: ${response}`)
|
||||||
|
})
|
||||||
|
```
|
||||||
|
From server (requires player):
|
||||||
|
```ts
|
||||||
|
rpc.callClient(player, 'updatePlayerData', ['argument']).then(response => {
|
||||||
|
console.log(`Received: ${response}`)
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## callServer
|
||||||
|
Calls a server-side event from browser or client
|
||||||
|
```ts
|
||||||
|
rpc.callServer('updatePlayerData', ['argument']).then(response => {
|
||||||
|
console.log(`Received: ${response}`)
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## callBrowser
|
||||||
|
Calls a server-side event from browser or client
|
||||||
|
|
||||||
|
From client:
|
||||||
|
```ts
|
||||||
|
rpc.callBrowser('updatePlayerData', ['argument']).then(response => {
|
||||||
|
console.log(`Received: ${response}`)
|
||||||
|
})
|
||||||
|
```
|
||||||
|
From client (requires player):
|
||||||
|
```ts
|
||||||
|
rpc.callBrowser(player, 'updatePlayerData', ['argument']).then(response => {
|
||||||
|
console.log(`Received: ${response}`)
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## call
|
||||||
|
Calls an event in current environment
|
||||||
|
```ts
|
||||||
|
rpc.call('triggerSomething').then(response => {
|
||||||
|
console.log(`Received: ${response}`)
|
||||||
|
})
|
||||||
|
```
|
88
rpc/src/browser.ts
Normal file
88
rpc/src/browser.ts
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
import { Wrapper } from './wrapper'
|
||||||
|
import {
|
||||||
|
Environment,
|
||||||
|
Events,
|
||||||
|
RPCEventType,
|
||||||
|
RPCState,
|
||||||
|
RpcWrapperConfig,
|
||||||
|
Utils,
|
||||||
|
} from './utils'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NOT INTENDED FOR OUT-OF-CONTEXT USE
|
||||||
|
*/
|
||||||
|
export class Browser extends Wrapper {
|
||||||
|
constructor(
|
||||||
|
options: RpcWrapperConfig = {
|
||||||
|
forceBrowserDevMode: false,
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
super(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NOT INTENDED FOR OUT-OF-CONTEXT USE
|
||||||
|
*/
|
||||||
|
public _resolveEmitDestination(dataRaw: string) {
|
||||||
|
let state = Utils.prepareExecution(dataRaw)
|
||||||
|
|
||||||
|
switch (state.calledTo) {
|
||||||
|
case Environment.BROWSER:
|
||||||
|
this.emit(dataRaw)
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
this.emitClient(dataRaw)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private emitClient(dataRaw: string) {
|
||||||
|
mp.trigger(Events.LOCAL_EVENT_LISTENER, dataRaw)
|
||||||
|
}
|
||||||
|
|
||||||
|
// called to browser
|
||||||
|
private async emit(dataRaw: string) {
|
||||||
|
let state = Utils.prepareExecution(dataRaw)
|
||||||
|
const responseEventName = Utils.generateResponseEventName(state.uuid)
|
||||||
|
|
||||||
|
// check availability
|
||||||
|
state = this.verifyEvent_(state)
|
||||||
|
if (state.knownError) {
|
||||||
|
this.triggerError_(state, state.knownError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// execute + generate response
|
||||||
|
const response = await this.state_[state.eventName](
|
||||||
|
...(Array.isArray(state.data) ? state.data : []),
|
||||||
|
)
|
||||||
|
const responseState: RPCState = {
|
||||||
|
uuid: Utils.generateUUID(),
|
||||||
|
eventName: state.eventName,
|
||||||
|
calledFrom: Environment.SERVER,
|
||||||
|
calledTo: state.calledFrom,
|
||||||
|
knownError: undefined,
|
||||||
|
data: response,
|
||||||
|
type: RPCEventType.RESPONSE,
|
||||||
|
}
|
||||||
|
const responseDataRaw = Utils.prepareTransfer(responseState)
|
||||||
|
|
||||||
|
// send response
|
||||||
|
switch (state.calledFrom) {
|
||||||
|
case Environment.BROWSER:
|
||||||
|
try {
|
||||||
|
mp.events.call(responseEventName, responseDataRaw)
|
||||||
|
} catch (e) {
|
||||||
|
void e
|
||||||
|
}
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
try {
|
||||||
|
mp.trigger(responseEventName, responseDataRaw)
|
||||||
|
} catch (e) {
|
||||||
|
void e
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
175
rpc/src/client.ts
Normal file
175
rpc/src/client.ts
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
import { Wrapper } from './wrapper'
|
||||||
|
import {
|
||||||
|
Environment,
|
||||||
|
Errors,
|
||||||
|
Events,
|
||||||
|
RPCEventType,
|
||||||
|
RPCState,
|
||||||
|
RpcWrapperConfig,
|
||||||
|
Utils,
|
||||||
|
} from './utils'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NOT INTENDED FOR OUT-OF-CONTEXT USE
|
||||||
|
*/
|
||||||
|
export class Client extends Wrapper {
|
||||||
|
private _browser: any = null
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
options: RpcWrapperConfig = {
|
||||||
|
forceBrowserDevMode: false,
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
super(options)
|
||||||
|
}
|
||||||
|
|
||||||
|
set browser(browser: any) {
|
||||||
|
this._browser = browser
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NOT INTENDED FOR OUT-OF-CONTEXT USE
|
||||||
|
*/
|
||||||
|
public _resolveEmitDestination(dataRaw: string) {
|
||||||
|
const state = Utils.prepareExecution(dataRaw)
|
||||||
|
|
||||||
|
switch (state.calledTo) {
|
||||||
|
case Environment.SERVER:
|
||||||
|
this.emitServer(dataRaw)
|
||||||
|
break
|
||||||
|
|
||||||
|
case Environment.BROWSER:
|
||||||
|
this.emitBrowser(dataRaw)
|
||||||
|
break
|
||||||
|
|
||||||
|
case Environment.CLIENT:
|
||||||
|
this.emit(state)
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
this.triggerError_(state, Errors.UNKNOWN_ENVIRONMENT)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// called to client
|
||||||
|
private async emit(state: RPCState) {
|
||||||
|
this.errorNoBrowser()
|
||||||
|
|
||||||
|
// check availability
|
||||||
|
state = this.verifyEvent_(state)
|
||||||
|
if (state.knownError) {
|
||||||
|
this.triggerError_(state, state.knownError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// execute + generate response
|
||||||
|
const responseEventName = Utils.generateResponseEventName(state.uuid)
|
||||||
|
const response = await this.state_[state.eventName](
|
||||||
|
...(Array.isArray(state.data) ? state.data : []),
|
||||||
|
)
|
||||||
|
const responseState: RPCState = {
|
||||||
|
uuid: Utils.generateUUID(),
|
||||||
|
eventName: state.eventName,
|
||||||
|
calledFrom: state.calledTo,
|
||||||
|
calledTo: state.calledFrom,
|
||||||
|
knownError: undefined,
|
||||||
|
data: response,
|
||||||
|
type: RPCEventType.RESPONSE,
|
||||||
|
}
|
||||||
|
|
||||||
|
// send response
|
||||||
|
switch (state.calledFrom) {
|
||||||
|
case Environment.CLIENT:
|
||||||
|
try {
|
||||||
|
mp.events.call(
|
||||||
|
responseEventName,
|
||||||
|
Utils.prepareTransfer(responseState),
|
||||||
|
)
|
||||||
|
} catch (e) {
|
||||||
|
void e
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case Environment.SERVER:
|
||||||
|
try {
|
||||||
|
mp.events.callRemote(
|
||||||
|
responseEventName,
|
||||||
|
Utils.prepareTransfer(responseState),
|
||||||
|
)
|
||||||
|
} catch (e) {
|
||||||
|
void e
|
||||||
|
}
|
||||||
|
break
|
||||||
|
|
||||||
|
case Environment.BROWSER:
|
||||||
|
try {
|
||||||
|
this._browser.call(
|
||||||
|
responseEventName,
|
||||||
|
Utils.prepareTransfer(responseState),
|
||||||
|
)
|
||||||
|
} catch (e) {
|
||||||
|
void e
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// called to server
|
||||||
|
private emitServer(dataRaw: string) {
|
||||||
|
this.errorNoBrowser()
|
||||||
|
|
||||||
|
const state = Utils.prepareExecution(dataRaw)
|
||||||
|
|
||||||
|
// if event is called from browser we will forward response through client via this
|
||||||
|
if (state.calledFrom === Environment.BROWSER) {
|
||||||
|
const responseEventName = Utils.generateResponseEventName(
|
||||||
|
state.uuid,
|
||||||
|
)
|
||||||
|
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
clearTimeout(timeout)
|
||||||
|
mp.events.remove(responseEventName)
|
||||||
|
}, 10000)
|
||||||
|
|
||||||
|
mp.events.add(responseEventName, (responseDataRaw: string) => {
|
||||||
|
this._browser.call(responseEventName, responseDataRaw)
|
||||||
|
|
||||||
|
clearTimeout(timeout)
|
||||||
|
mp.events.remove(responseEventName)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
mp.events.callRemote(Events.SERVER_EVENT_LISTENER, dataRaw)
|
||||||
|
}
|
||||||
|
|
||||||
|
// called to browser
|
||||||
|
private emitBrowser(dataRaw: string) {
|
||||||
|
this.errorNoBrowser()
|
||||||
|
|
||||||
|
const state = Utils.prepareExecution(dataRaw)
|
||||||
|
|
||||||
|
// if event is called from server we will forward response through client via this
|
||||||
|
if (state.calledFrom === Environment.SERVER) {
|
||||||
|
const responseEventName = Utils.generateResponseEventName(
|
||||||
|
state.uuid,
|
||||||
|
)
|
||||||
|
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
clearTimeout(timeout)
|
||||||
|
mp.events.remove(responseEventName)
|
||||||
|
}, 10000)
|
||||||
|
|
||||||
|
mp.events.add(responseEventName, (responseDataRaw: string) => {
|
||||||
|
mp.events.callRemote(responseEventName, responseDataRaw)
|
||||||
|
|
||||||
|
clearTimeout(timeout)
|
||||||
|
mp.events.remove(responseEventName)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
this._browser.call(Events.LOCAL_EVENT_LISTENER, dataRaw)
|
||||||
|
}
|
||||||
|
|
||||||
|
private errorNoBrowser() {
|
||||||
|
if (!this._browser) throw new Error(Errors.NO_BROWSER)
|
||||||
|
}
|
||||||
|
}
|
536
rpc/src/index.ts
Normal file
536
rpc/src/index.ts
Normal file
@ -0,0 +1,536 @@
|
|||||||
|
import { Wrapper } from './wrapper'
|
||||||
|
import {
|
||||||
|
Environment,
|
||||||
|
Errors,
|
||||||
|
Events,
|
||||||
|
nativeClientEvents,
|
||||||
|
nativeServerEvents,
|
||||||
|
type PlayerMp,
|
||||||
|
RpcConfig,
|
||||||
|
RPCEventType,
|
||||||
|
RPCState,
|
||||||
|
Utils,
|
||||||
|
} from './utils'
|
||||||
|
|
||||||
|
import { Server } from './server'
|
||||||
|
import { Client } from './client'
|
||||||
|
import { Browser } from './browser'
|
||||||
|
|
||||||
|
class Rpc extends Wrapper {
|
||||||
|
private _server: Server
|
||||||
|
private _client: Client
|
||||||
|
private _browser: Browser
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
options: RpcConfig = {
|
||||||
|
forceBrowserDevMode: false,
|
||||||
|
debugLogs: false,
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
super(options)
|
||||||
|
|
||||||
|
this._server = new Server(options)
|
||||||
|
this._client = new Client(options)
|
||||||
|
this._browser = new Browser(options)
|
||||||
|
this.debug_ = !!options.debugLogs
|
||||||
|
|
||||||
|
if (options.forceBrowserDevMode) return
|
||||||
|
|
||||||
|
if (this.environment_ === Environment.UNKNOWN)
|
||||||
|
throw new Error(Errors.UNKNOWN_ENVIRONMENT)
|
||||||
|
|
||||||
|
mp.events.add(
|
||||||
|
Events.LOCAL_EVENT_LISTENER,
|
||||||
|
async (player: PlayerMp | string, dataRaw: string) => {
|
||||||
|
switch (this.environment_) {
|
||||||
|
case Environment.SERVER:
|
||||||
|
this._server._resolveEmitDestination(
|
||||||
|
player as PlayerMp,
|
||||||
|
dataRaw,
|
||||||
|
)
|
||||||
|
break
|
||||||
|
|
||||||
|
case Environment.CLIENT:
|
||||||
|
dataRaw = player as string
|
||||||
|
this._client._resolveEmitDestination(dataRaw)
|
||||||
|
break
|
||||||
|
|
||||||
|
case Environment.BROWSER:
|
||||||
|
dataRaw = player as string
|
||||||
|
this._browser._resolveEmitDestination(dataRaw)
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
void { player, dataRaw }
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
set browser(browser: any) {
|
||||||
|
this._client.browser = browser
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a callback function for a specified event
|
||||||
|
*
|
||||||
|
* @template CallbackArguments - An array of argument types that the callback function accepts
|
||||||
|
* @template CallbackReturn - The type of the value returned by the callback function
|
||||||
|
* @template EventName - A string representing the event name or union of names
|
||||||
|
*
|
||||||
|
* @param {EventName} eventName - The name of the event to register the callback for
|
||||||
|
* @param {(...args: CallbackArguments) => CallbackReturn} cb - The callback function that is called when the event is triggered
|
||||||
|
*
|
||||||
|
* @returns {void}
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* register<[PlayerMp]>('playerJoin', (player) => {
|
||||||
|
* console.log(`Connected: ${player.socialClub}`)
|
||||||
|
* })
|
||||||
|
*/
|
||||||
|
public register<
|
||||||
|
CallbackArguments extends unknown[] = unknown[],
|
||||||
|
CallbackReturn extends unknown = unknown,
|
||||||
|
EventName extends string = string,
|
||||||
|
>(
|
||||||
|
eventName: EventName,
|
||||||
|
cb: (...args: CallbackArguments) => CallbackReturn,
|
||||||
|
): void {
|
||||||
|
this.log('register', eventName, cb)
|
||||||
|
if (this.forceBrowserDevMode_) return
|
||||||
|
Utils.errorUnknownEnvironment(this.environment_)
|
||||||
|
|
||||||
|
if (
|
||||||
|
(this.environment_ === Environment.CLIENT &&
|
||||||
|
nativeClientEvents.has(eventName)) ||
|
||||||
|
(this.environment_ === Environment.SERVER &&
|
||||||
|
nativeServerEvents.has(eventName))
|
||||||
|
) {
|
||||||
|
mp.events.add(eventName, cb)
|
||||||
|
} else {
|
||||||
|
this.state_[eventName] = cb
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters callback function for a specified event
|
||||||
|
*
|
||||||
|
* @template EventName - A string representing the event name or union of names
|
||||||
|
*
|
||||||
|
* @param {EventName} eventName - The name of the event to register the callback for
|
||||||
|
*
|
||||||
|
* @returns {void}
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* unregister('playerJoin')
|
||||||
|
*/
|
||||||
|
public unregister<EventName extends string = string>(
|
||||||
|
eventName: EventName,
|
||||||
|
): void {
|
||||||
|
this.log('unregister', eventName)
|
||||||
|
if (this.forceBrowserDevMode_) return
|
||||||
|
Utils.errorUnknownEnvironment(this.environment_)
|
||||||
|
|
||||||
|
delete this.state_[eventName]
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls a client-side event from server or browser
|
||||||
|
*
|
||||||
|
* @template Arguments - An array of argument types to be passed to the client event
|
||||||
|
* @template EventName - A string representing the client event name or union of names
|
||||||
|
* @template Return - The type of the value returned by the client event
|
||||||
|
*
|
||||||
|
* @param {EventName} eventName - The name of the client event to be called
|
||||||
|
* @param {Arguments} [args] - Optional arguments to pass to the client event
|
||||||
|
* @returns {Promise<Return>} A promise resolving to the return value of the client event
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Calls an event on client without specifying a player
|
||||||
|
* callClient<[], string, object>('onDataRequest').then(response => {
|
||||||
|
* console.log(`Received: ${response}`) // ^ object
|
||||||
|
* })
|
||||||
|
*/
|
||||||
|
public async callClient<
|
||||||
|
Arguments extends unknown[] = unknown[],
|
||||||
|
EventName extends string = string,
|
||||||
|
Return extends unknown = unknown,
|
||||||
|
>(eventName: EventName, args?: Arguments): Promise<Return>
|
||||||
|
/**
|
||||||
|
* Calls a client-side event from server or browser
|
||||||
|
*
|
||||||
|
* @template Arguments - An array of argument types to be passed to the client event
|
||||||
|
* @template EventName - A string representing the client event name or union of names
|
||||||
|
* @template Return - The type of the value returned by the client event
|
||||||
|
*
|
||||||
|
* @param {PlayerMp} player - The player for whom the client event is called
|
||||||
|
* @param {EventName} eventName - The name of the client event to be called
|
||||||
|
* @param {Arguments} [args] - Optional arguments to pass to the client event
|
||||||
|
* @returns {Promise<Return>} A promise resolving to the return value of the client event
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Calls an event on client for a specific player
|
||||||
|
* callClient<[string, number], string, boolean>(player, 'onPlayerAction', ['jump', 2]).then(result => {
|
||||||
|
* console.log(`Action success: ${result}`) // ^ boolean
|
||||||
|
* })
|
||||||
|
*/
|
||||||
|
public async callClient<
|
||||||
|
Arguments extends unknown[] = unknown[],
|
||||||
|
EventName extends string = string,
|
||||||
|
Return extends unknown = unknown,
|
||||||
|
>(player: PlayerMp, eventName: EventName, args?: Arguments): Promise<Return>
|
||||||
|
public async callClient(
|
||||||
|
playerOrEventName: PlayerMp | string,
|
||||||
|
eventNameOrArgs?: string | unknown[],
|
||||||
|
args?: unknown[],
|
||||||
|
) {
|
||||||
|
_is1StParamPlayer(playerOrEventName)
|
||||||
|
? this.log(
|
||||||
|
'callClient',
|
||||||
|
eventNameOrArgs as string,
|
||||||
|
playerOrEventName,
|
||||||
|
eventNameOrArgs,
|
||||||
|
args,
|
||||||
|
)
|
||||||
|
: this.log(
|
||||||
|
'callClient',
|
||||||
|
playerOrEventName as string,
|
||||||
|
eventNameOrArgs,
|
||||||
|
)
|
||||||
|
if (this.forceBrowserDevMode_) return
|
||||||
|
Utils.errorUnknownEnvironment(this.environment_)
|
||||||
|
|
||||||
|
function _is1StParamPlayer(x: unknown): x is PlayerMp {
|
||||||
|
return typeof x === 'object'
|
||||||
|
}
|
||||||
|
|
||||||
|
function _is2NdParamEventName(x: unknown): x is string {
|
||||||
|
return typeof x === 'string'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.environment_ === Environment.CLIENT) {
|
||||||
|
// client
|
||||||
|
return await this.call(
|
||||||
|
playerOrEventName as string,
|
||||||
|
args as unknown[],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// server
|
||||||
|
if (
|
||||||
|
this.environment_ === Environment.SERVER &&
|
||||||
|
_is1StParamPlayer(playerOrEventName) &&
|
||||||
|
_is2NdParamEventName(eventNameOrArgs)
|
||||||
|
) {
|
||||||
|
const state: RPCState = {
|
||||||
|
uuid: Utils.generateUUID(),
|
||||||
|
eventName: eventNameOrArgs,
|
||||||
|
calledTo: Environment.CLIENT,
|
||||||
|
calledFrom: this.environment_,
|
||||||
|
knownError: undefined,
|
||||||
|
data: args as unknown[],
|
||||||
|
type: RPCEventType.EVENT,
|
||||||
|
}
|
||||||
|
|
||||||
|
const dataRaw = Utils.prepareTransfer(state)
|
||||||
|
|
||||||
|
playerOrEventName.call(Events.LOCAL_EVENT_LISTENER, [dataRaw])
|
||||||
|
return (await this.responseHandler(state.uuid)).data
|
||||||
|
}
|
||||||
|
|
||||||
|
// browser
|
||||||
|
if (
|
||||||
|
this.environment_ === Environment.BROWSER &&
|
||||||
|
!_is1StParamPlayer(playerOrEventName) &&
|
||||||
|
!_is2NdParamEventName(eventNameOrArgs)
|
||||||
|
) {
|
||||||
|
const state: RPCState = {
|
||||||
|
uuid: Utils.generateUUID(),
|
||||||
|
eventName: playerOrEventName,
|
||||||
|
calledTo: Environment.CLIENT,
|
||||||
|
calledFrom: this.environment_,
|
||||||
|
knownError: undefined,
|
||||||
|
data: eventNameOrArgs,
|
||||||
|
type: RPCEventType.EVENT,
|
||||||
|
}
|
||||||
|
|
||||||
|
const dataRaw = Utils.prepareTransfer(state)
|
||||||
|
|
||||||
|
mp.trigger(Events.LOCAL_EVENT_LISTENER, dataRaw)
|
||||||
|
return (await this.responseHandler(state.uuid)).data
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls a server-side event from browser or client
|
||||||
|
*
|
||||||
|
* @template Arguments - An array of argument types to be passed to the server event
|
||||||
|
* @template EventName - A string representing the server event name or union of names
|
||||||
|
* @template Return - The type of the value returned by the server event
|
||||||
|
*
|
||||||
|
* @param {EventName} eventName - The name of the server event to be called
|
||||||
|
* @param {Arguments} [args] - Optional arguments to pass to the server event
|
||||||
|
* @returns {Promise<Return>} A promise resolving to the return value of the server event
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Calls an event on server
|
||||||
|
* callServer<[], string, object>('onDataRequest').then(response => {
|
||||||
|
* console.log(`Received: ${response}`) // ^ object
|
||||||
|
* })
|
||||||
|
*/
|
||||||
|
public async callServer<
|
||||||
|
Arguments extends unknown[] = unknown[],
|
||||||
|
EventName extends string = string,
|
||||||
|
Return extends unknown = unknown,
|
||||||
|
>(eventName: EventName, args?: Arguments): Promise<Return> {
|
||||||
|
this.log('callServer', eventName, args)
|
||||||
|
if (this.forceBrowserDevMode_)
|
||||||
|
return undefined as unknown as Promise<Return>
|
||||||
|
Utils.errorUnknownEnvironment(this.environment_)
|
||||||
|
|
||||||
|
const state: RPCState = {
|
||||||
|
uuid: Utils.generateUUID(),
|
||||||
|
eventName,
|
||||||
|
calledTo: Environment.SERVER,
|
||||||
|
calledFrom: this.environment_,
|
||||||
|
knownError: undefined,
|
||||||
|
data: args,
|
||||||
|
type: RPCEventType.EVENT,
|
||||||
|
}
|
||||||
|
|
||||||
|
const dataRaw = Utils.prepareTransfer(state)
|
||||||
|
|
||||||
|
switch (this.environment_) {
|
||||||
|
case Environment.SERVER:
|
||||||
|
return this.callSelf(state)
|
||||||
|
|
||||||
|
case Environment.CLIENT:
|
||||||
|
mp.events.callRemote(Events.LOCAL_EVENT_LISTENER, dataRaw)
|
||||||
|
break
|
||||||
|
|
||||||
|
case Environment.BROWSER:
|
||||||
|
mp.trigger(Events.LOCAL_EVENT_LISTENER, dataRaw)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return (await this.responseHandler(state.uuid)).data
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls a browser-side event from server or client
|
||||||
|
*
|
||||||
|
* @template Arguments - An array of argument types to be passed to the browser event
|
||||||
|
* @template EventName - A string representing the browser event name or union of names
|
||||||
|
* @template Return - The type of the value returned by the browser event
|
||||||
|
*
|
||||||
|
* @param {EventName} eventName - The name of the browser event to be called
|
||||||
|
* @param {Arguments} [args] - Optional arguments to pass to the browser event
|
||||||
|
* @returns {Promise<Return>} A promise resolving to the return value of the browser event
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Calls an event on browser without specifying a player
|
||||||
|
* callBrowser<[], string, object>('onDataRequest').then(response => {
|
||||||
|
* console.log(`Received: ${response}`) // ^ object
|
||||||
|
* })
|
||||||
|
*/
|
||||||
|
public async callBrowser<
|
||||||
|
Arguments extends unknown[] = unknown[],
|
||||||
|
EventName extends string = string,
|
||||||
|
Return extends unknown = unknown,
|
||||||
|
>(eventName: EventName, args?: Arguments): Promise<Return>
|
||||||
|
/**
|
||||||
|
* Calls a browser-side event from server or client
|
||||||
|
*
|
||||||
|
* @template Arguments - An array of argument types to be passed to the browser event
|
||||||
|
* @template EventName - A string representing the browser event name or union of names
|
||||||
|
* @template Return - The type of the value returned by the browser event
|
||||||
|
*
|
||||||
|
* @param {PlayerMp} player - The player for whom the browser event is called
|
||||||
|
* @param {EventName} eventName - The name of the browser event to be called
|
||||||
|
* @param {Arguments} [args] - Optional arguments to pass to the browser event
|
||||||
|
* @returns {Promise<Return>} A promise resolving to the return value of the browser event
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Calls an event on a browser for a specific player
|
||||||
|
* callBrowser<[string, number], string, boolean>(player, 'onPlayerAction', ['jump', 2]).then(result => {
|
||||||
|
* console.log(`Action success: ${result}`) // ^ boolean
|
||||||
|
* })
|
||||||
|
*/
|
||||||
|
public async callBrowser<
|
||||||
|
Arguments extends unknown[] = unknown[],
|
||||||
|
EventName extends string = string,
|
||||||
|
Return extends unknown = unknown,
|
||||||
|
>(player: PlayerMp, eventName: EventName, args?: Arguments): Promise<Return>
|
||||||
|
public async callBrowser(
|
||||||
|
playerOrEventName: PlayerMp | string,
|
||||||
|
eventNameOrArgs?: string | unknown[],
|
||||||
|
args?: unknown[],
|
||||||
|
) {
|
||||||
|
_is1StParamPlayer(playerOrEventName)
|
||||||
|
? this.log(
|
||||||
|
'DEV callClient',
|
||||||
|
eventNameOrArgs as string,
|
||||||
|
playerOrEventName,
|
||||||
|
eventNameOrArgs,
|
||||||
|
args,
|
||||||
|
)
|
||||||
|
: this.log(
|
||||||
|
'DEV callClient',
|
||||||
|
playerOrEventName as string,
|
||||||
|
eventNameOrArgs,
|
||||||
|
)
|
||||||
|
if (this.forceBrowserDevMode_) return
|
||||||
|
Utils.errorUnknownEnvironment(this.environment_)
|
||||||
|
|
||||||
|
function _is1StParamPlayer(x: unknown): x is PlayerMp {
|
||||||
|
return typeof x === 'object'
|
||||||
|
}
|
||||||
|
|
||||||
|
function _is2NdParamEventName(x: unknown): x is string {
|
||||||
|
return typeof x === 'string'
|
||||||
|
}
|
||||||
|
|
||||||
|
const state: RPCState = {
|
||||||
|
uuid: Utils.generateUUID(),
|
||||||
|
eventName: !_is1StParamPlayer(playerOrEventName)
|
||||||
|
? playerOrEventName
|
||||||
|
: _is2NdParamEventName(eventNameOrArgs)
|
||||||
|
? eventNameOrArgs
|
||||||
|
: '',
|
||||||
|
calledTo: Environment.BROWSER,
|
||||||
|
calledFrom: this.environment_,
|
||||||
|
knownError: undefined,
|
||||||
|
data: _is1StParamPlayer(playerOrEventName) ? args : eventNameOrArgs,
|
||||||
|
type: RPCEventType.EVENT,
|
||||||
|
}
|
||||||
|
|
||||||
|
const dataRaw = Utils.prepareTransfer(state)
|
||||||
|
|
||||||
|
switch (this.environment_) {
|
||||||
|
case Environment.BROWSER:
|
||||||
|
return this.callSelf(state)
|
||||||
|
|
||||||
|
case Environment.CLIENT:
|
||||||
|
mp.events.callRemote(Events.LOCAL_EVENT_LISTENER, dataRaw)
|
||||||
|
break
|
||||||
|
|
||||||
|
case Environment.SERVER:
|
||||||
|
;(playerOrEventName as PlayerMp).call(
|
||||||
|
Events.LOCAL_EVENT_LISTENER,
|
||||||
|
[dataRaw],
|
||||||
|
)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
return (await this.responseHandler(state.uuid)).data
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calls an event in current environment
|
||||||
|
*
|
||||||
|
* @template Arguments - An array of argument types to be passed to the event
|
||||||
|
* @template EventName - A string representing the event name or union of names
|
||||||
|
* @template Return - The type of the value returned by the event
|
||||||
|
*
|
||||||
|
* @param {EventName} eventName - The name of the event to be called
|
||||||
|
* @param {Arguments} [args] - Optional arguments to pass to the event
|
||||||
|
* @returns {Promise<Return>} A promise resolving to the return value of the event
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Calls an event in current environment
|
||||||
|
* call<[], string, number>('getSomething').then(response => {
|
||||||
|
* console.log(`Received: ${response}`) // ^ number
|
||||||
|
* })
|
||||||
|
*/
|
||||||
|
public async call<
|
||||||
|
Arguments extends unknown[] = unknown[],
|
||||||
|
EventName extends string = string,
|
||||||
|
Return extends unknown = unknown,
|
||||||
|
>(eventName: EventName, args?: Arguments): Promise<Return> {
|
||||||
|
this.log('call', eventName, args)
|
||||||
|
if (this.forceBrowserDevMode_)
|
||||||
|
return undefined as unknown as Promise<Return>
|
||||||
|
Utils.errorUnknownEnvironment(this.environment_)
|
||||||
|
|
||||||
|
let state: RPCState = {
|
||||||
|
uuid: Utils.generateUUID(),
|
||||||
|
eventName,
|
||||||
|
calledTo: this.environment_,
|
||||||
|
calledFrom: this.environment_,
|
||||||
|
knownError: undefined,
|
||||||
|
data: args,
|
||||||
|
type: RPCEventType.EVENT,
|
||||||
|
}
|
||||||
|
|
||||||
|
return await this.callSelf<Return>(state)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* redirects an event in cases of it calling its own environment
|
||||||
|
*/
|
||||||
|
private async callSelf<Return extends unknown = unknown>(
|
||||||
|
state: RPCState,
|
||||||
|
): Promise<Return> {
|
||||||
|
state = this.verifyEvent_(state)
|
||||||
|
if (state.knownError) {
|
||||||
|
this.triggerError_(state, state.knownError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return await this.state_[state.eventName](...state.data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* returns cross-environment response
|
||||||
|
*/
|
||||||
|
private async responseHandler(uuid: string): Promise<RPCState> {
|
||||||
|
const responseEventName = Utils.generateResponseEventName(uuid)
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const timeout = setTimeout(() => {
|
||||||
|
clearTimeout(timeout)
|
||||||
|
mp.events.remove(responseEventName)
|
||||||
|
reject(Errors.EVENT_RESPONSE_TIMEOUT)
|
||||||
|
}, 10000)
|
||||||
|
|
||||||
|
mp.events.add(
|
||||||
|
responseEventName,
|
||||||
|
(player: PlayerMp | string, dataRaw: string) => {
|
||||||
|
switch (this.environment_) {
|
||||||
|
case Environment.SERVER:
|
||||||
|
resolve(Utils.prepareExecution(dataRaw))
|
||||||
|
|
||||||
|
clearTimeout(timeout)
|
||||||
|
mp.events.remove(responseEventName)
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
case Environment.CLIENT:
|
||||||
|
dataRaw = player as string
|
||||||
|
resolve(Utils.prepareExecution(dataRaw))
|
||||||
|
|
||||||
|
clearTimeout(timeout)
|
||||||
|
mp.events.remove(responseEventName)
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
case Environment.BROWSER:
|
||||||
|
dataRaw = player as string
|
||||||
|
resolve(Utils.prepareExecution(dataRaw))
|
||||||
|
|
||||||
|
clearTimeout(timeout)
|
||||||
|
mp.events.remove(responseEventName)
|
||||||
|
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
void { player, dataRaw }
|
||||||
|
break
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Rpc }
|
104
rpc/src/server.ts
Normal file
104
rpc/src/server.ts
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
import { Wrapper } from './wrapper'
|
||||||
|
import {
|
||||||
|
Environment,
|
||||||
|
Events,
|
||||||
|
type PlayerMp,
|
||||||
|
RPCEventType,
|
||||||
|
RPCState,
|
||||||
|
RpcWrapperConfig,
|
||||||
|
Utils,
|
||||||
|
} from './utils'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NOT INTENDED FOR OUT-OF-CONTEXT USE
|
||||||
|
*/
|
||||||
|
export class Server extends Wrapper {
|
||||||
|
constructor(
|
||||||
|
options: RpcWrapperConfig = {
|
||||||
|
forceBrowserDevMode: false,
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
super(options)
|
||||||
|
|
||||||
|
if (!!options.forceBrowserDevMode) return
|
||||||
|
|
||||||
|
// specific event to save player in context as it is not available on server -> server calls
|
||||||
|
mp.events.add(
|
||||||
|
Events.SERVER_EVENT_LISTENER,
|
||||||
|
async (player: PlayerMp, dataRaw: string) => {
|
||||||
|
this.emit(player, dataRaw)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* NOT INTENDED FOR OUT-OF-CONTEXT USE
|
||||||
|
*/
|
||||||
|
public _resolveEmitDestination(player: PlayerMp, dataRaw: string) {
|
||||||
|
let state = Utils.prepareExecution(dataRaw)
|
||||||
|
|
||||||
|
switch (state.calledTo) {
|
||||||
|
case Environment.SERVER:
|
||||||
|
this.emit(player, dataRaw)
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
this.emitClient(player as PlayerMp, dataRaw)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private emitClient(player: PlayerMp, dataRaw: string) {
|
||||||
|
player.call(Events.LOCAL_EVENT_LISTENER, [dataRaw])
|
||||||
|
}
|
||||||
|
|
||||||
|
// called to server
|
||||||
|
private async emit(player: PlayerMp, dataRaw: string) {
|
||||||
|
let state = Utils.prepareExecution(dataRaw)
|
||||||
|
const responseEventName = Utils.generateResponseEventName(state.uuid)
|
||||||
|
|
||||||
|
// check availability
|
||||||
|
state = this.verifyEvent_(state)
|
||||||
|
if (state.knownError) {
|
||||||
|
this.triggerError_(state, state.knownError)
|
||||||
|
}
|
||||||
|
|
||||||
|
// execute + generate response
|
||||||
|
const response = await this.state_[state.eventName](
|
||||||
|
player,
|
||||||
|
...(Array.isArray(state.data) ? state.data : []),
|
||||||
|
)
|
||||||
|
const responseState: RPCState = {
|
||||||
|
uuid: Utils.generateUUID(),
|
||||||
|
eventName: state.eventName,
|
||||||
|
calledFrom: Environment.SERVER,
|
||||||
|
calledTo: state.calledFrom,
|
||||||
|
knownError: undefined,
|
||||||
|
data: response,
|
||||||
|
type: RPCEventType.RESPONSE,
|
||||||
|
}
|
||||||
|
|
||||||
|
// send response
|
||||||
|
switch (state.calledFrom) {
|
||||||
|
case Environment.SERVER:
|
||||||
|
try {
|
||||||
|
mp.events.call(
|
||||||
|
responseEventName,
|
||||||
|
Utils.prepareTransfer(responseState),
|
||||||
|
)
|
||||||
|
} catch (e) {
|
||||||
|
void e
|
||||||
|
}
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
try {
|
||||||
|
player.call(responseEventName, [
|
||||||
|
Utils.prepareTransfer(responseState),
|
||||||
|
])
|
||||||
|
} catch (e) {
|
||||||
|
void e
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
171
rpc/src/utils.ts
Normal file
171
rpc/src/utils.ts
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
export enum Environment {
|
||||||
|
BROWSER = 'BROWSER',
|
||||||
|
CLIENT = 'CLIENT',
|
||||||
|
SERVER = 'SERVER',
|
||||||
|
UNKNOWN = 'UNKNOWN',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum Events {
|
||||||
|
LOCAL_EVENT_LISTENER = '__rpc:listener',
|
||||||
|
SERVER_EVENT_LISTENER = '__rpc:serverListener',
|
||||||
|
EVENT_RESPONSE = '__rpc:response',
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum Errors {
|
||||||
|
EVENT_NOT_REGISTERED = 'Event not registered',
|
||||||
|
UNKNOWN_ENVIRONMENT = 'Unknown environment',
|
||||||
|
NO_BROWSER = 'You need to initialize browser first',
|
||||||
|
EVENT_RESPONSE_TIMEOUT = 'Response was timed out after 10s of inactivity',
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RPCState = {
|
||||||
|
eventName: string
|
||||||
|
uuid: string
|
||||||
|
calledFrom: Environment
|
||||||
|
calledTo: Environment
|
||||||
|
knownError?: string
|
||||||
|
data?: any
|
||||||
|
type: RPCEventType
|
||||||
|
}
|
||||||
|
|
||||||
|
export type PlayerMp = {
|
||||||
|
call: (event: string, args?: unknown[]) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RpcWrapperConfig {
|
||||||
|
forceBrowserDevMode?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RpcConfig extends RpcWrapperConfig {
|
||||||
|
debugLogs?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Utils {
|
||||||
|
// todo type for dev browser
|
||||||
|
public static getEnvironment(): Environment {
|
||||||
|
if ('joaat' in mp) return Environment.SERVER
|
||||||
|
if (
|
||||||
|
'game' in mp &&
|
||||||
|
'joaat' in (mp as { game: { joaat?: unknown } }).game
|
||||||
|
)
|
||||||
|
return Environment.CLIENT
|
||||||
|
if (window && 'mp' in window) return Environment.BROWSER
|
||||||
|
return Environment.UNKNOWN
|
||||||
|
}
|
||||||
|
|
||||||
|
public static prepareExecution(data: string): RPCState {
|
||||||
|
return JSON.parse(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static prepareTransfer(data: RPCState): string {
|
||||||
|
return JSON.stringify(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
public static generateUUID(): string {
|
||||||
|
let uuid = '',
|
||||||
|
random
|
||||||
|
|
||||||
|
for (let i = 0; i < 32; i++) {
|
||||||
|
random = (Math.random() * 16) | 0
|
||||||
|
|
||||||
|
if (i === 8 || i === 12 || i === 16 || i === 20) {
|
||||||
|
uuid += '-'
|
||||||
|
}
|
||||||
|
|
||||||
|
uuid += (
|
||||||
|
i === 12 ? 4 : i === 16 ? (random & 3) | 8 : random
|
||||||
|
).toString(16)
|
||||||
|
}
|
||||||
|
|
||||||
|
return uuid
|
||||||
|
}
|
||||||
|
|
||||||
|
public static generateResponseEventName(uuid: string): string {
|
||||||
|
return `${Events.EVENT_RESPONSE}_${uuid}`
|
||||||
|
}
|
||||||
|
|
||||||
|
public static errorUnknownEnvironment(environment: Environment) {
|
||||||
|
if (environment === Environment.UNKNOWN)
|
||||||
|
throw new Error(Errors.UNKNOWN_ENVIRONMENT)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum RPCEventType {
|
||||||
|
EVENT = 'event',
|
||||||
|
RESPONSE = 'response',
|
||||||
|
}
|
||||||
|
|
||||||
|
export const nativeClientEvents = new Set([
|
||||||
|
'browserCreated',
|
||||||
|
'browserDomReady',
|
||||||
|
'browserLoadingFailed',
|
||||||
|
'playerEnterCheckpoint',
|
||||||
|
'playerExitCheckpoint',
|
||||||
|
'consoleCommand',
|
||||||
|
'click',
|
||||||
|
'playerChat',
|
||||||
|
'playerCommand',
|
||||||
|
'playerDeath',
|
||||||
|
'playerJoin',
|
||||||
|
'playerQuit',
|
||||||
|
'playerReady',
|
||||||
|
'playerResurrect',
|
||||||
|
'playerRuleTriggered',
|
||||||
|
'playerSpawn',
|
||||||
|
'playerWeaponShot',
|
||||||
|
'dummyEntityCreated',
|
||||||
|
'dummyEntityDestroyed',
|
||||||
|
'entityControllerChange',
|
||||||
|
'incomingDamage',
|
||||||
|
'outgoingDamage',
|
||||||
|
'meleeActionDamage',
|
||||||
|
'playerEnterVehicle',
|
||||||
|
'playerLeaveVehicle',
|
||||||
|
'playerStartTalking',
|
||||||
|
'playerStopTalking',
|
||||||
|
'entityStreamIn',
|
||||||
|
'entityStreamOut',
|
||||||
|
'render',
|
||||||
|
'playerCreateWaypoint',
|
||||||
|
'playerReachWaypoint',
|
||||||
|
'playerEnterColshape',
|
||||||
|
'playerExitColshape',
|
||||||
|
'explosion',
|
||||||
|
'projectile',
|
||||||
|
'uncaughtException',
|
||||||
|
'unhandledRejection',
|
||||||
|
])
|
||||||
|
|
||||||
|
export const nativeServerEvents = new Set([
|
||||||
|
'entityCreated',
|
||||||
|
// 'entityDestroyed',
|
||||||
|
'entityModelChange',
|
||||||
|
'incomingConnection',
|
||||||
|
'packagesLoaded',
|
||||||
|
'playerChat',
|
||||||
|
'playerCommand',
|
||||||
|
'playerDamage',
|
||||||
|
'playerDeath',
|
||||||
|
'playerEnterCheckpoint',
|
||||||
|
'playerEnterColshape',
|
||||||
|
'playerEnterVehicle',
|
||||||
|
'playerExitCheckpoint',
|
||||||
|
'playerExitColshape',
|
||||||
|
'playerExitVehicle',
|
||||||
|
'playerJoin',
|
||||||
|
'playerQuit',
|
||||||
|
'playerReachWaypoint',
|
||||||
|
'playerReady',
|
||||||
|
'playerSpawn',
|
||||||
|
'playerStartEnterVehicle',
|
||||||
|
'playerStartExitVehicle',
|
||||||
|
'playerStreamIn',
|
||||||
|
'playerStreamOut',
|
||||||
|
'playerWeaponChange',
|
||||||
|
'serverShutdown',
|
||||||
|
'trailerAttached',
|
||||||
|
'vehicleDamage',
|
||||||
|
'vehicleDeath',
|
||||||
|
'vehicleHornToggle',
|
||||||
|
'vehicleSirenToggle',
|
||||||
|
])
|
61
rpc/src/wrapper.ts
Normal file
61
rpc/src/wrapper.ts
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
import { Environment, Errors, RPCState, RpcWrapperConfig, Utils } from './utils'
|
||||||
|
|
||||||
|
export class Wrapper {
|
||||||
|
protected environment_ = Environment.UNKNOWN
|
||||||
|
protected state_: any
|
||||||
|
protected console_ =
|
||||||
|
this.environment_ === Environment.CLIENT
|
||||||
|
? mp.console.logInfo
|
||||||
|
: console.log
|
||||||
|
protected debug_ = false
|
||||||
|
protected forceBrowserDevMode_ = false
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
options: RpcWrapperConfig = {
|
||||||
|
forceBrowserDevMode: false,
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
if (options.forceBrowserDevMode) {
|
||||||
|
this.environment_ = Environment.UNKNOWN
|
||||||
|
this.state_ = window
|
||||||
|
} else {
|
||||||
|
this.environment_ = Utils.getEnvironment()
|
||||||
|
this.state_ =
|
||||||
|
this.environment_ === Environment.BROWSER ? window : global
|
||||||
|
}
|
||||||
|
|
||||||
|
this.forceBrowserDevMode_ = !!options.forceBrowserDevMode
|
||||||
|
}
|
||||||
|
|
||||||
|
// checks if event is available (registered) in current environment
|
||||||
|
protected verifyEvent_(data: string | RPCState): RPCState {
|
||||||
|
let rpcData =
|
||||||
|
typeof data === 'string' ? Utils.prepareExecution(data) : data
|
||||||
|
|
||||||
|
if (!this.state_[rpcData.eventName]) {
|
||||||
|
rpcData.knownError = Errors.EVENT_NOT_REGISTERED
|
||||||
|
}
|
||||||
|
|
||||||
|
return rpcData
|
||||||
|
}
|
||||||
|
|
||||||
|
protected triggerError_(rpcData: RPCState, error?: any) {
|
||||||
|
const errorMessage = [
|
||||||
|
`${rpcData.knownError}`,
|
||||||
|
`Caller: ${rpcData.calledFrom}`,
|
||||||
|
`Receiver: ${this.environment_}`,
|
||||||
|
`Event: ${rpcData.eventName}`,
|
||||||
|
]
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
errorMessage.push(`Additional Info: ${error}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(errorMessage.join('\n | '))
|
||||||
|
}
|
||||||
|
|
||||||
|
protected log(method: string, eventName: string, ...args: unknown[]): void {
|
||||||
|
if (this.debug_)
|
||||||
|
this.console_('RPC | [' + method + '] ' + eventName + ':', ...args)
|
||||||
|
}
|
||||||
|
}
|
29
rpc/tsconfig.json
Normal file
29
rpc/tsconfig.json
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es6",
|
||||||
|
"module": "commonjs",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"lib": [
|
||||||
|
"ES6",
|
||||||
|
"dom"
|
||||||
|
],
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
|
||||||
|
"outDir": "bin",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
|
||||||
|
"strict": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"src/**/*",
|
||||||
|
"./index.d.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules",
|
||||||
|
"dist"
|
||||||
|
]
|
||||||
|
}
|
11
rpc/tsup.config.ts
Normal file
11
rpc/tsup.config.ts
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
import { defineConfig } from 'tsup'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
entry: ['src/index.ts'],
|
||||||
|
outDir: './dist',
|
||||||
|
format: ['cjs'],
|
||||||
|
experimentalDts: true,
|
||||||
|
splitting: false,
|
||||||
|
sourcemap: false,
|
||||||
|
clean: true,
|
||||||
|
})
|
15
server/LICENSE
Normal file
15
server/LICENSE
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
Custom Attribution-NoDerivs Software License
|
||||||
|
|
||||||
|
Copyright (c) 2024 Entity Seven Group
|
||||||
|
|
||||||
|
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.
|
@ -1,9 +0,0 @@
|
|||||||
import { build } from 'esbuild'
|
|
||||||
|
|
||||||
build({
|
|
||||||
entryPoints: ['./src/index.ts'],
|
|
||||||
format: 'esm',
|
|
||||||
platform: 'node',
|
|
||||||
target: 'node10.4',
|
|
||||||
outdir: './dist',
|
|
||||||
}).then(r => console.log('Successfully build.'))
|
|
@ -1,15 +0,0 @@
|
|||||||
{
|
|
||||||
"compilationOptions": {
|
|
||||||
"followSymlinks": true,
|
|
||||||
"preferredConfigPath": "../tsconfig.json"
|
|
||||||
},
|
|
||||||
"entries": [
|
|
||||||
{
|
|
||||||
"filePath": "./src/index.ts",
|
|
||||||
"outFile": "./dist/index.d.ts",
|
|
||||||
"libraries": {
|
|
||||||
"inlinedLibraries": ["@ragempcommunity/types-server"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,25 +1,38 @@
|
|||||||
{
|
{
|
||||||
"name": "rage-fw-server",
|
"name": "@entityseven/rage-fw-server",
|
||||||
"version": "0.0.5-alpha.0",
|
"version": "0.2.0",
|
||||||
"main": "dist/index.js",
|
"main": "dist/index.js",
|
||||||
"types": "dist/index.d.ts",
|
"types": "dist/src/index.d.ts",
|
||||||
"type": "module",
|
|
||||||
"files": [
|
"files": [
|
||||||
"dist/**/*"
|
"dist/**/*",
|
||||||
|
"readme.md",
|
||||||
|
"LICENSE"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "node --es-module-specifier-resolution=node build.js",
|
"build": "tsup"
|
||||||
"types": "dts-bundle-generator --config dts.config.json"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"rage-fw-shared-types": "workspace:^"
|
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"rage-rpc": "^0.4.0"
|
"@entityseven/rage-fw-rpc": "0.2.5"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"peerDependencies": {
|
||||||
"author": "SashaGoncharov19",
|
"@entityseven/rage-fw-shared-types": "0.2.0",
|
||||||
"license": "MIT",
|
"@ragempcommunity/types-server": "^2.1.8"
|
||||||
"description": "Server side for rage-fw",
|
},
|
||||||
"gitHead": "053e4fd12aa120d53e11e0d2009c0df78c1a2ad0"
|
"description": "Package used on a server-side of your Rage:MP Server",
|
||||||
|
"keywords": ["rage-fw-server", "ragefw", "rage-fw", "ragemp", "rage:mp", "rage", "gta5"],
|
||||||
|
"author": "Entity Seven Group",
|
||||||
|
"contributors": [
|
||||||
|
{
|
||||||
|
"name": "Danya H",
|
||||||
|
"email": "dev.rilaxik@gmail.com",
|
||||||
|
"url": "https://github.com/rilaxik/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Oleksandr Honcharov",
|
||||||
|
"email": "0976053529@ukr.net",
|
||||||
|
"url": "https://github.com/SashaGoncharov19/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "Custom-Attribution-NoDerivs",
|
||||||
|
"gitHead": "ffd542c1deddb3033e16e0dae7557313ae09b05f"
|
||||||
}
|
}
|
||||||
|
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)
|
5
server/src/core/index.ts
Normal file
5
server/src/core/index.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
export * from './logger'
|
||||||
|
export * from './middleware'
|
||||||
|
export * from './player'
|
||||||
|
export * from './rpc'
|
||||||
|
export * from './server'
|
56
server/src/core/logger.ts
Normal file
56
server/src/core/logger.ts
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
import winston, { format } from 'winston'
|
||||||
|
|
||||||
|
const { timestamp, printf, colorize } = format
|
||||||
|
|
||||||
|
/** Used to log in a server console */
|
||||||
|
export class Logger {
|
||||||
|
private format = printf(({ message, level, timestamp }) => {
|
||||||
|
return `[${new Date(timestamp).toLocaleTimeString()}] [${level}]: ${message}`
|
||||||
|
})
|
||||||
|
|
||||||
|
private systemLogger = winston.createLogger({
|
||||||
|
transports: [new winston.transports.Console()],
|
||||||
|
format: format.combine(
|
||||||
|
colorize({
|
||||||
|
level: true,
|
||||||
|
colors: {
|
||||||
|
error: 'red',
|
||||||
|
warn: 'yellow',
|
||||||
|
info: 'white',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
timestamp(),
|
||||||
|
this.format,
|
||||||
|
),
|
||||||
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Informational logs. Colored in white
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* fw.system.log.info('some information to be logged')
|
||||||
|
*/
|
||||||
|
public info(...message: unknown[]) {
|
||||||
|
this.systemLogger.info(message.join(' '))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Warning logs. Colored in yellow
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* fw.system.log.warn('warning message')
|
||||||
|
*/
|
||||||
|
public warn(...message: unknown[]) {
|
||||||
|
this.systemLogger.warn(message.join(' '))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Error logs. Colored in red
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* fw.system.log.info('some error information')
|
||||||
|
*/
|
||||||
|
public error(...message: unknown[]) {
|
||||||
|
this.systemLogger.error(message.join(' '))
|
||||||
|
}
|
||||||
|
}
|
54
server/src/core/middleware.ts
Normal file
54
server/src/core/middleware.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import type * as T from '../types'
|
||||||
|
|
||||||
|
export class Middleware {
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
private static async execute<EventName extends T.RageFW_ServerEvent>(
|
||||||
|
middlewares: T.RageFW_MiddlewareFunction<EventName>[],
|
||||||
|
args: T.RageFW_ServerArgs<EventName>,
|
||||||
|
): Promise<T.RageFW_MiddlewareResponseInternal> {
|
||||||
|
for (let i = 0; i < middlewares.length; i++) {
|
||||||
|
const result = await middlewares[i](...args)
|
||||||
|
|
||||||
|
if (typeof result === 'boolean' && !result)
|
||||||
|
return { success: result, id: i }
|
||||||
|
if (typeof result !== 'boolean' && !result.success)
|
||||||
|
return { ...result, id: i }
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
success: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async process<EventName extends T.RageFW_ServerEvent>(
|
||||||
|
middlewareOptions: T.RageFW_MiddlewareOptions<EventName>,
|
||||||
|
callback: T.RageFW_ServerCallback<EventName>,
|
||||||
|
args: T.RageFW_ServerArgs<EventName>,
|
||||||
|
) {
|
||||||
|
if (Array.isArray(middlewareOptions)) {
|
||||||
|
const middlewaresResponse = await Middleware.execute(
|
||||||
|
middlewareOptions,
|
||||||
|
args,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (middlewaresResponse.success) return await callback(...args)
|
||||||
|
} else {
|
||||||
|
const middlewaresResponse = await Middleware.execute(
|
||||||
|
middlewareOptions.executables,
|
||||||
|
args,
|
||||||
|
)
|
||||||
|
|
||||||
|
if (middlewaresResponse.success) {
|
||||||
|
return await callback(...args)
|
||||||
|
} else {
|
||||||
|
middlewareOptions.onError(
|
||||||
|
middlewaresResponse.message ??
|
||||||
|
'Middleware with id ' +
|
||||||
|
middlewaresResponse.id +
|
||||||
|
' failed',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
68
server/src/core/player.ts
Normal file
68
server/src/core/player.ts
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
import { rpc } from './rpc'
|
||||||
|
import type * as T from '../types'
|
||||||
|
|
||||||
|
/** Handles event manipulations that require player to be present in context */
|
||||||
|
export class Player {
|
||||||
|
/**
|
||||||
|
* Triggers a client event from the server with arguments from shared types
|
||||||
|
*
|
||||||
|
* Formerly known as ``callClient`` or ``emitClient``
|
||||||
|
*
|
||||||
|
* @param {PlayerMp} player - Player object as an event target
|
||||||
|
* @param eventName - The name of the client event to trigger
|
||||||
|
* @param [args] - Arguments for the client event, if present
|
||||||
|
* @returns {Promise} resolving to the client's response for the event
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Triggering a client event without arguments
|
||||||
|
* fw.player.triggerClient("clientEventName")
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Triggering a client event with arguments
|
||||||
|
* fw.player.triggerClient("clientEventName", ["message to client"])
|
||||||
|
*
|
||||||
|
* @see {@link https://git.entityseven.com/entityseven/rage-framework/wiki Wiki}
|
||||||
|
*/
|
||||||
|
public async triggerClient<EventName extends T.RageFW_ClientEvent>(
|
||||||
|
player: PlayerMp,
|
||||||
|
eventName: EventName,
|
||||||
|
...args: T._ClientEventHasArgs<EventName> extends true
|
||||||
|
? [T.RageFW_ClientArgs<EventName>]
|
||||||
|
: []
|
||||||
|
): Promise<T.RageFW_ClientReturn<EventName>> {
|
||||||
|
return await rpc.callClient(player, eventName, args)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Triggers a browser event from the server with arguments from shared types
|
||||||
|
*
|
||||||
|
* Formerly known as ``callBrowser`` or ``emitBrowser``
|
||||||
|
*
|
||||||
|
* @param {PlayerMp} player - Player object as an event target
|
||||||
|
* @param eventName - The name of the browser event to trigger
|
||||||
|
* @param [args] - Arguments for the browser event, if present
|
||||||
|
* @returns {Promise} resolving to the browser's response for the event
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Triggering a browser event without arguments
|
||||||
|
* fw.player.triggerBrowser("browserEventName")
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Triggering a browser event with arguments
|
||||||
|
* fw.player.triggerBrowser("browserEventName", ["message to browser"])
|
||||||
|
*
|
||||||
|
* @see {@link https://git.entityseven.com/entityseven/rage-framework/wiki Wiki}
|
||||||
|
*/
|
||||||
|
public async triggerBrowser<EventName extends T.RageFW_BrowserEvent>(
|
||||||
|
player: PlayerMp,
|
||||||
|
eventName: EventName,
|
||||||
|
...args: T._BrowserEventHasArgs<EventName> extends true
|
||||||
|
? [T.RageFW_BrowserArgs<EventName>]
|
||||||
|
: []
|
||||||
|
): Promise<T.RageFW_BrowserReturn<EventName>> {
|
||||||
|
return await rpc.callBrowser(player, eventName, args)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// new Player().triggerBrowser({} as PlayerMp, 'customCefEvent', ['', 1])
|
||||||
|
// new Player().triggerClient({} as PlayerMp, 'customClientEvent', ['', 1])
|
5
server/src/core/rpc.ts
Normal file
5
server/src/core/rpc.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { Rpc } from '@entityseven/rage-fw-rpc'
|
||||||
|
|
||||||
|
export const rpc = new Rpc({
|
||||||
|
debugLogs: false,
|
||||||
|
})
|
96
server/src/core/server.ts
Normal file
96
server/src/core/server.ts
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
import { rpc } from './rpc'
|
||||||
|
import { Middleware } from './middleware'
|
||||||
|
import type * as T from '../types'
|
||||||
|
|
||||||
|
/** Server-side interactions */
|
||||||
|
export class Server {
|
||||||
|
/**
|
||||||
|
* Registers a server event with an associated callback
|
||||||
|
*
|
||||||
|
* @param eventName - The name of the event to register
|
||||||
|
* @param callback - The callback function to be executed when the event is triggered
|
||||||
|
* @param [options] - Optional settings for callback execution
|
||||||
|
* @param [options.middlewares] - Middleware functions to be checked before the callback executes
|
||||||
|
* @returns {Server} The current server instance, enabling method chaining
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Registering an event
|
||||||
|
* fw.event.register("playerJoin", (player) => {
|
||||||
|
* fw.system.log.info(`${player.socialClub} has joined the game`)
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Registering an event with middlewares
|
||||||
|
* fw.event.register("playerJoin", (player) => {
|
||||||
|
* fw.system.log.info(`${player.name} has joined the game`)
|
||||||
|
* }, {
|
||||||
|
* middlewares: [ignoreBots] // <- your middlewares here
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
* // or
|
||||||
|
*
|
||||||
|
* fw.event.register("playerJoin", (player) => {
|
||||||
|
* fw.system.log.info(`${player.socialClub} has joined the game`)
|
||||||
|
* }, {
|
||||||
|
* middlewares: {
|
||||||
|
* executables: [ignoreBots], // <- your middlewares here
|
||||||
|
* onError: (msg) => fw.system.log.info(`[BOT] ${player.socialClub} has joined the game`)
|
||||||
|
* }
|
||||||
|
* })
|
||||||
|
*
|
||||||
|
* @see {@link https://git.entityseven.com/entityseven/rage-framework/wiki Wiki}
|
||||||
|
*/
|
||||||
|
public register<EventName extends T.RageFW_ServerEvent>(
|
||||||
|
eventName: EventName,
|
||||||
|
callback: T.RageFW_ServerCallback<EventName>,
|
||||||
|
options?: {
|
||||||
|
middlewares?: T.RageFW_MiddlewareOptions<EventName>
|
||||||
|
},
|
||||||
|
): Server {
|
||||||
|
rpc.register<
|
||||||
|
Parameters<typeof callback>,
|
||||||
|
ReturnType<typeof callback> | Promise<unknown>,
|
||||||
|
EventName
|
||||||
|
>(eventName, async (...data) => {
|
||||||
|
if (!options?.middlewares) return await callback(...data)
|
||||||
|
|
||||||
|
await Middleware.process(options.middlewares, callback, data)
|
||||||
|
})
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregisters a server event, removing the associated callback
|
||||||
|
*
|
||||||
|
* @param eventName - The name of the event to unregister
|
||||||
|
* @returns {Server} The current server instance, enabling method chaining
|
||||||
|
*
|
||||||
|
* @example
|
||||||
|
* // Unregistering an event
|
||||||
|
* fw.event.unregister("playerJoin")
|
||||||
|
*
|
||||||
|
* @see {@link https://git.entityseven.com/entityseven/rage-framework/wiki Wiki}
|
||||||
|
*/
|
||||||
|
public unregister<EventName extends T.RageFW_ServerEvent>(
|
||||||
|
eventName: EventName,
|
||||||
|
): Server {
|
||||||
|
rpc.unregister<EventName>(eventName)
|
||||||
|
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
// fixme
|
||||||
|
// public trigger<EventName extends keyof T.RageFW_ICustomServerEvent>(
|
||||||
|
// eventName: EventName,
|
||||||
|
// ...args: T._ServerEventHasArgs<EventName> extends true
|
||||||
|
// ? [T.RageFW_ServerArgs<EventName>]
|
||||||
|
// : []
|
||||||
|
// ): Promise<T.RageFW_ServerReturn<EventName>> {
|
||||||
|
// return rpc.call(eventName, args)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// new Server()
|
||||||
|
// .register('customServerEvent', async (a, b, c) => true)
|
||||||
|
// .unregister('customServerEvent')
|
33
server/src/data/nativeEvents.ts
Normal file
33
server/src/data/nativeEvents.ts
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
export const nativeEvents = [
|
||||||
|
'entityCreated',
|
||||||
|
'entityDestroyed',
|
||||||
|
'entityModelChange',
|
||||||
|
'incomingConnection',
|
||||||
|
'packagesLoaded',
|
||||||
|
'playerChat',
|
||||||
|
'playerCommand',
|
||||||
|
'playerDamage',
|
||||||
|
'playerDeath',
|
||||||
|
'playerEnterCheckpoint',
|
||||||
|
'playerEnterColshape',
|
||||||
|
'playerEnterVehicle',
|
||||||
|
'playerExitCheckpoint',
|
||||||
|
'playerExitColshape',
|
||||||
|
'playerExitVehicle',
|
||||||
|
'playerJoin',
|
||||||
|
'playerQuit',
|
||||||
|
'playerReachWaypoint',
|
||||||
|
'playerReady',
|
||||||
|
'playerSpawn',
|
||||||
|
'playerStartEnterVehicle',
|
||||||
|
'playerStartExitVehicle',
|
||||||
|
'playerStreamIn',
|
||||||
|
'playerStreamOut',
|
||||||
|
'playerWeaponChange',
|
||||||
|
'serverShutdown',
|
||||||
|
'trailerAttached',
|
||||||
|
'vehicleDamage',
|
||||||
|
'vehicleDeath',
|
||||||
|
'vehicleHornToggle',
|
||||||
|
'vehicleSirenToggle',
|
||||||
|
]
|
@ -1,27 +1,26 @@
|
|||||||
import rpc from 'rage-rpc'
|
import { Logger, Player, Server, rpc } from './core'
|
||||||
import type { RageFW_ServerEvent, RageFW_ServerEventCallback } from './types.js'
|
|
||||||
|
|
||||||
class Server {
|
export type { RageFW_MiddlewareFunction } from './types'
|
||||||
public register<EventName extends RageFW_ServerEvent>(
|
|
||||||
eventName: EventName,
|
|
||||||
callback: RageFW_ServerEventCallback<EventName>,
|
|
||||||
): void {
|
|
||||||
rpc.register(eventName, callback as rpc.ProcedureListener)
|
|
||||||
}
|
|
||||||
|
|
||||||
public registerMany<EventName extends RageFW_ServerEvent>(events: {
|
/**
|
||||||
[event in EventName]: RageFW_ServerEventCallback<event>
|
* Package used on a server-side of your Rage:MP Server
|
||||||
}): void {
|
*
|
||||||
Object.entries(events).map(([eventName, callback]) =>
|
* @see {@link https://git.entityseven.com/entityseven/rage-framework/wiki Wiki}
|
||||||
rpc.register(eventName, (args: unknown[]) => {
|
*/
|
||||||
return Array.isArray(args)
|
export const fw = {
|
||||||
? (callback as (...arg: typeof args) => void)(...args)
|
/** Server-side interactions */
|
||||||
: (callback as (arg: typeof args) => void)(args)
|
|
||||||
}),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export const rage = {
|
|
||||||
event: new Server(),
|
event: new Server(),
|
||||||
|
/** Handles event manipulations that require player to be present in context */
|
||||||
|
player: new Player(),
|
||||||
|
/** Handles functions used to interact with the client environment */
|
||||||
|
system: {
|
||||||
|
/** Used to log in a server console */
|
||||||
|
log: new Logger(),
|
||||||
|
},
|
||||||
|
/** ``rage-fw-rpc`` instance used under the hood. It is highly recommended to use this one if you need it instead of creating a new instance */
|
||||||
|
rpc,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fw.system.log.info(
|
||||||
|
'Working on Rage Framework. RageFW © Powered by Entity Seven Group',
|
||||||
|
)
|
||||||
|
@ -1,18 +0,0 @@
|
|||||||
/// <reference types="@ragempcommunity/types-server" />
|
|
||||||
|
|
||||||
import type { RageFW_ICustomServerEvent } from 'rage-fw-shared-types'
|
|
||||||
|
|
||||||
export type RageFW_ServerEvent =
|
|
||||||
| keyof RageFW_ICustomServerEvent
|
|
||||||
| keyof IServerEvents
|
|
||||||
|
|
||||||
export type RageFW_ServerEventCallback<
|
|
||||||
K extends keyof RageFW_ICustomServerEvent | keyof IServerEvents,
|
|
||||||
> = K extends keyof RageFW_ICustomServerEvent
|
|
||||||
? (
|
|
||||||
player: PlayerMp,
|
|
||||||
...args: Parameters<RageFW_ICustomServerEvent[K]>
|
|
||||||
) => ReturnType<RageFW_ICustomServerEvent[K]>
|
|
||||||
: K extends keyof IServerEvents
|
|
||||||
? ThisifyServerEvents[K]
|
|
||||||
: never
|
|
34
server/src/types/browser.ts
Normal file
34
server/src/types/browser.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
import type { RageFW_ICustomBrowserEvent } from '@entityseven/rage-fw-shared-types'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Union of all available browser event names
|
||||||
|
* These only include custom events
|
||||||
|
*/
|
||||||
|
export type RageFW_BrowserEvent = keyof RageFW_ICustomBrowserEvent
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of arguments of an event you pass as a generic
|
||||||
|
* These only include custom events
|
||||||
|
*/
|
||||||
|
export type RageFW_BrowserArgs<K extends RageFW_BrowserEvent> = Parameters<
|
||||||
|
RageFW_ICustomBrowserEvent[K]
|
||||||
|
>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return type of event you pass as a generic
|
||||||
|
* These only include custom events
|
||||||
|
*/
|
||||||
|
export type RageFW_BrowserReturn<K extends RageFW_BrowserEvent> = ReturnType<
|
||||||
|
RageFW_ICustomBrowserEvent[K]
|
||||||
|
>
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export type _BrowserEventHasArgs<
|
||||||
|
EventName extends keyof RageFW_ICustomBrowserEvent,
|
||||||
|
> = keyof RageFW_ICustomBrowserEvent extends never
|
||||||
|
? false
|
||||||
|
: Parameters<RageFW_ICustomBrowserEvent[EventName]>[0] extends undefined
|
||||||
|
? false
|
||||||
|
: true
|
38
server/src/types/client.ts
Normal file
38
server/src/types/client.ts
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/// <reference types="@ragempcommunity/types-server" />
|
||||||
|
|
||||||
|
import type { RageFW_ICustomClientEvent } from '@entityseven/rage-fw-shared-types'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Union of all available client event names
|
||||||
|
* These only include custom events
|
||||||
|
*/
|
||||||
|
export type RageFW_ClientEvent = keyof RageFW_ICustomClientEvent
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of arguments of an event you pass as a generic
|
||||||
|
* These only include custom events
|
||||||
|
*/
|
||||||
|
export type RageFW_ClientArgs<K extends RageFW_ClientEvent> =
|
||||||
|
K extends RageFW_ClientEvent
|
||||||
|
? Parameters<RageFW_ICustomClientEvent[K]>
|
||||||
|
: never
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return type of event you pass as a generic
|
||||||
|
* These only include custom events
|
||||||
|
*/
|
||||||
|
export type RageFW_ClientReturn<K extends RageFW_ClientEvent> =
|
||||||
|
K extends RageFW_ClientEvent
|
||||||
|
? ReturnType<RageFW_ICustomClientEvent[K]>
|
||||||
|
: never
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export type _ClientEventHasArgs<
|
||||||
|
EventName extends keyof RageFW_ICustomClientEvent,
|
||||||
|
> = keyof RageFW_ICustomClientEvent extends never
|
||||||
|
? false
|
||||||
|
: Parameters<RageFW_ICustomClientEvent[EventName]>[0] extends undefined
|
||||||
|
? false
|
||||||
|
: true
|
4
server/src/types/index.ts
Normal file
4
server/src/types/index.ts
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
export * from './browser'
|
||||||
|
export * from './client'
|
||||||
|
export * from './middleware'
|
||||||
|
export * from './server'
|
26
server/src/types/middleware.ts
Normal file
26
server/src/types/middleware.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import type * as T from './server'
|
||||||
|
|
||||||
|
export type RageFW_MiddlewareResponse =
|
||||||
|
| {
|
||||||
|
success: boolean
|
||||||
|
message?: string
|
||||||
|
}
|
||||||
|
| boolean
|
||||||
|
|
||||||
|
export type RageFW_MiddlewareResponseInternal = {
|
||||||
|
success: boolean
|
||||||
|
message?: string
|
||||||
|
id?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export type RageFW_MiddlewareFunction<EventName extends T.RageFW_ServerEvent> =
|
||||||
|
(
|
||||||
|
...args: T.RageFW_ServerArgs<EventName>
|
||||||
|
) => Promise<RageFW_MiddlewareResponse>
|
||||||
|
|
||||||
|
export type RageFW_MiddlewareOptions<EventName extends T.RageFW_ServerEvent> =
|
||||||
|
| RageFW_MiddlewareFunction<EventName>[]
|
||||||
|
| {
|
||||||
|
executables: RageFW_MiddlewareFunction<EventName>[]
|
||||||
|
onError: (error: string) => unknown
|
||||||
|
}
|
66
server/src/types/server.ts
Normal file
66
server/src/types/server.ts
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
/// <reference types="@ragempcommunity/types-server" />
|
||||||
|
|
||||||
|
import type {
|
||||||
|
RageFW_ICustomClientEvent,
|
||||||
|
RageFW_ICustomServerEvent,
|
||||||
|
} from '@entityseven/rage-fw-shared-types'
|
||||||
|
|
||||||
|
export type { RageFW_ICustomServerEvent } from '@entityseven/rage-fw-shared-types'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Union of all available server event names
|
||||||
|
* These also include system events
|
||||||
|
*/
|
||||||
|
export type RageFW_ServerEvent =
|
||||||
|
| keyof RageFW_ICustomServerEvent
|
||||||
|
| keyof IServerEvents
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Array of arguments for an event, name of which you pass as a generic
|
||||||
|
* These also include system events
|
||||||
|
*/
|
||||||
|
export type RageFW_ServerArgs<K extends RageFW_ServerEvent> =
|
||||||
|
K extends keyof RageFW_ICustomServerEvent
|
||||||
|
? [PlayerMp, ...Parameters<RageFW_ICustomServerEvent[K]>]
|
||||||
|
: K extends keyof IServerEvents
|
||||||
|
? [PlayerMp, Parameters<IServerEvents[K]>]
|
||||||
|
: never
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return type for an event, name of which you pass as a generic
|
||||||
|
* These include system and custom events
|
||||||
|
*/
|
||||||
|
export type RageFW_ServerReturn<K extends RageFW_ServerEvent> =
|
||||||
|
K extends keyof RageFW_ICustomServerEvent
|
||||||
|
? ReturnType<RageFW_ICustomServerEvent[K]>
|
||||||
|
: K extends keyof IServerEvents
|
||||||
|
? ReturnType<IServerEvents[K]>
|
||||||
|
: void
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Callback (function) for an event, name of which you pass as a generic
|
||||||
|
* These include system and custom events
|
||||||
|
*/
|
||||||
|
export type RageFW_ServerCallback<K extends RageFW_ServerEvent> = (
|
||||||
|
...args: RageFW_ServerArgs<K>
|
||||||
|
) => Promise<RageFW_ServerReturn<K>>
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export type _ServerEventHasArgs<EventName extends RageFW_ServerEvent> =
|
||||||
|
EventName extends keyof RageFW_ICustomServerEvent
|
||||||
|
? keyof RageFW_ICustomClientEvent extends never
|
||||||
|
? false
|
||||||
|
: Parameters<
|
||||||
|
RageFW_ICustomServerEvent[EventName]
|
||||||
|
>[0] extends undefined
|
||||||
|
? false
|
||||||
|
: true
|
||||||
|
: EventName extends keyof IServerEvents
|
||||||
|
? keyof IServerEvents extends never
|
||||||
|
? false
|
||||||
|
: Parameters<IServerEvents[EventName]>[0] extends undefined
|
||||||
|
? false
|
||||||
|
: true
|
||||||
|
: false
|
@ -1,9 +1,25 @@
|
|||||||
{
|
{
|
||||||
"extends": "../tsconfig.json",
|
"$schema": "https://json.schemastore.org/tsconfig",
|
||||||
|
"display": "Base",
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
],
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"typeRoots": [
|
"incremental": false,
|
||||||
"@ragempcommunity/types-server"
|
"composite": false,
|
||||||
],
|
"target": "ES2022",
|
||||||
"baseUrl": "./src"
|
"experimentalDecorators": true,
|
||||||
|
"moduleDetection": "auto",
|
||||||
|
"module": "CommonJS",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"declaration": true,
|
||||||
|
"declarationMap": false,
|
||||||
|
"sourceMap": false,
|
||||||
|
"downlevelIteration": false,
|
||||||
|
"inlineSourceMap": false,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"strict": true,
|
||||||
|
"skipLibCheck": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
12
server/tsup.config.ts
Normal file
12
server/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,
|
||||||
|
})
|
13
shared-types/LICENSE
Normal file
13
shared-types/LICENSE
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.
|
@ -1,12 +1,28 @@
|
|||||||
{
|
{
|
||||||
"name": "rage-fw-shared-types",
|
"name": "@entityseven/rage-fw-shared-types",
|
||||||
"version": "0.0.5-alpha.0",
|
"version": "0.2.0",
|
||||||
"types": "types/types/index.d.ts",
|
"types": "types/types/index.d.ts",
|
||||||
"files": [
|
"files": [
|
||||||
"types/**/*"
|
"types/**/*",
|
||||||
|
"readme.md",
|
||||||
|
"LICENSE"
|
||||||
],
|
],
|
||||||
"author": "SashaGoncharov19",
|
"description": "Package used among all environments of your Rage-FW based server",
|
||||||
"license": "MIT",
|
"keywords": ["rage-fw-shared-types", "rage-fw-shared","ragefw", "rage-fw", "ragemp", "rage:mp", "rage", "gta5"],
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"gitHead": "053e4fd12aa120d53e11e0d2009c0df78c1a2ad0"
|
"author": "Entity Seven Group",
|
||||||
|
"contributors": [
|
||||||
|
{
|
||||||
|
"name": "Danya H",
|
||||||
|
"email": "dev.rilaxik@gmail.com",
|
||||||
|
"url": "https://github.com/rilaxik/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Oleksandr Honcharov",
|
||||||
|
"email": "0976053529@ukr.net",
|
||||||
|
"url": "https://github.com/SashaGoncharov19/"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "Custom-Attribution-NoDerivs",
|
||||||
|
"gitHead": "ffd542c1deddb3033e16e0dae7557313ae09b05f"
|
||||||
}
|
}
|
||||||
|
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)
|
15
shared-types/types/types/index.d.ts
vendored
15
shared-types/types/types/index.d.ts
vendored
@ -1,5 +1,14 @@
|
|||||||
declare module 'rage-fw-shared-types' {
|
declare module '@entityseven/rage-fw-shared-types' {
|
||||||
export interface RageFW_ICustomServerEvent {}
|
export interface RageFW_ICustomServerEvent {
|
||||||
|
customServerEvent(arg1: string, arg2: number): boolean
|
||||||
|
}
|
||||||
|
|
||||||
export interface RageFW_ICustomClientEvent {}
|
export interface RageFW_ICustomClientEvent {
|
||||||
|
cefReady(): void
|
||||||
|
customClientEvent(arg1: string, arg2: number): boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RageFW_ICustomBrowserEvent {
|
||||||
|
customCefEvent(arg1: string, arg2: number): boolean
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "rage-fw-shared",
|
|
||||||
"version": "0.0.5-alpha.0",
|
|
||||||
"type": "module",
|
|
||||||
"main": "index.d.ts",
|
|
||||||
"files": [
|
|
||||||
"index.d.ts"
|
|
||||||
],
|
|
||||||
"scripts": {
|
|
||||||
"test": "tsup"
|
|
||||||
},
|
|
||||||
"keywords": [],
|
|
||||||
"author": "SashaGoncharov19",
|
|
||||||
"license": "MIT",
|
|
||||||
"description": "Shared client types for rage-fw",
|
|
||||||
"gitHead": "053e4fd12aa120d53e11e0d2009c0df78c1a2ad0"
|
|
||||||
}
|
|
@ -1,16 +1,18 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "ESNext",
|
"target": "ESNext",
|
||||||
|
"lib": [
|
||||||
|
"ESNext",
|
||||||
|
"ES2019",
|
||||||
|
"dom"
|
||||||
|
],
|
||||||
|
"moduleResolution": "node",
|
||||||
"module": "ESNext",
|
"module": "ESNext",
|
||||||
"strict": true,
|
|
||||||
"allowSyntheticDefaultImports": true,
|
|
||||||
"esModuleInterop": true,
|
"esModuleInterop": true,
|
||||||
|
"strict": true,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"emitDecoratorMetadata": true,
|
"emitDecoratorMetadata": true,
|
||||||
"moduleResolution": "node",
|
|
||||||
"resolveJsonModule": true,
|
|
||||||
"isolatedModules": true,
|
"isolatedModules": true,
|
||||||
"declaration": true,
|
|
||||||
"useUnknownInCatchVariables": false,
|
"useUnknownInCatchVariables": false,
|
||||||
"exactOptionalPropertyTypes": true,
|
"exactOptionalPropertyTypes": true,
|
||||||
"typeRoots": [
|
"typeRoots": [
|
||||||
|
Loading…
Reference in New Issue
Block a user