/
plugins.ts
152 lines (129 loc) · 3.68 KB
/
plugins.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
import * as alt from 'alt-server';
import { SYSTEM_EVENTS } from '../../shared/enums/system';
import { ExtractStringKeys } from '@AthenaShared/utility/extractStringKeys';
const pluginRegistration: Array<{ name: string; callback: Function }> = [];
const pluginHooks: { [key: string]: Object } = {};
let callbacks: Array<Function> = [];
let hasInitialized = false;
let hasFinishedLoading = false;
declare global {
export interface ServerPluginAPI {}
}
async function loadPlugins() {
const promises = [];
for (let i = 0; i < pluginRegistration.length; i++) {
const plugin = pluginRegistration[i];
if (!plugin || typeof plugin.callback !== 'function') {
alt.logError(`Could not load plugin with name ${plugin.name}. Callback was incorrect.`);
continue;
}
alt.log(`~lc~Plugin: ~g~${plugin.name}`);
promises.push(plugin.callback());
}
await Promise.all(promises);
// Load after plugins are initialized...
// VehicleSystem.init();
for (let callback of callbacks) {
callback();
}
hasFinishedLoading = true;
alt.emit(SYSTEM_EVENTS.BOOTUP_ENABLE_ENTRY);
}
/**
* Loads all plugins.
*/
export function init(): void {
if (hasInitialized) {
return;
}
hasInitialized = true;
loadPlugins();
}
/**
* Register a callback for a plugin to begin its initialization period.
* This ensures that your plugin is ALWAYS loaded last.
* @static
* @param {Function} callback
*
*/
export function registerPlugin(name: string, callback: Function) {
pluginRegistration.push({ name, callback });
}
/**
* Returns a list of all plugin names that are currently being loaded.
*
* @static
* @return {Array<string>}
*
*/
export function getPlugins(): Array<string> {
return pluginRegistration.map((x) => {
return x.name;
});
}
/**
* After plugins are finished loading; call these callbacks.
* Useful for using 'Athena API' at the top level of a document.
*
* @param {Function} callback
*/
export function addCallback(callback: Function) {
if (!callbacks) {
callbacks = [];
}
callbacks.push(callback);
}
/**
* Verifies if all plugins are done loading.
*
* @return {Promise<void>}
*/
export async function isDoneLoading(): Promise<void> {
return new Promise((resolve: Function) => {
const interval = alt.setInterval(() => {
if (!hasFinishedLoading) {
return;
}
alt.clearInterval(interval);
resolve();
}, 100);
});
}
/**
* Injects a 'plugin' API into the runtime.
*
* The runtime injection can be obtained with `Athena.systems.plugins.use`.
*
* See that function for additional information.
*
* @export
* @param {string} pluginName
* @param {Object} functions
*/
export function addAPI(pluginName: string, functions: Object) {
if (pluginName.includes(' ')) {
throw new Error('Plugin name must be plain text and all lowercase. No spaces.');
}
pluginName = pluginName.toLowerCase();
pluginHooks[pluginName] = functions;
}
/**
* Used to obtain a runtime API and its valid functionality.
*
* This makes it so you can 'import' without knowing the plugin pathways.
*
* As long as you know the 'plugin name' you can import anything.
*
* @export
* @template K
* @param {K} apiName
* @return {Promise<ServerPluginAPI[K]>}
*/
export async function useAPI<K extends ExtractStringKeys<ServerPluginAPI>>(apiName: K): Promise<ServerPluginAPI[K]> {
await isDoneLoading();
if (!pluginHooks[apiName]) {
alt.logWarning(`Plugin hook for ${apiName} is not available.`);
return undefined;
}
return pluginHooks[apiName] as ServerPluginAPI[K];
}