@thigasdevelopment/luam 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +616 -0
- package/lua/async.lua +119 -0
- package/lua/class.lua +178 -0
- package/lua/development-logs-client.lua +13 -0
- package/lua/development-logs-server.lua +44 -0
- package/lua/dotenv.lua +160 -0
- package/lua/env.lua +18 -0
- package/lua/math.lua +24 -0
- package/lua/string.lua +82 -0
- package/lua/table.lua +63 -0
- package/lua/threads.lua +274 -0
- package/luam.mjs +9910 -0
- package/package.json +38 -0
- package/template/README.md +120 -0
- package/template/config.lua +14 -0
- package/template/env +11 -0
- package/template/framework/bootstrap-client.luam +9 -0
- package/template/framework/bootstrap-server.luam +9 -0
- package/template/framework/command.luam +54 -0
- package/template/framework/core.luam +58 -0
- package/template/framework/event.luam +39 -0
- package/template/framework/listener.luam +40 -0
- package/template/framework/loader.luam +73 -0
- package/template/framework/thread-pool.luam +27 -0
- package/template/gitignore +7 -0
- package/template/luam.json +11 -0
- package/template/src/client/commands/ping-command.luam +8 -0
- package/template/src/client/main.luam +5 -0
- package/template/src/server/commands/hello-command.luam +9 -0
- package/template/src/server/handlers/player-join-listener.luam +9 -0
- package/template/src/server/main.luam +11 -0
- package/template/src/shared/config.luam +5 -0
- package/template/src/shared/framework/command.luam +54 -0
- package/template/src/shared/framework/core.luam +58 -0
- package/template/src/shared/framework/event.luam +39 -0
- package/template/src/shared/framework/listener.luam +40 -0
- package/template/src/shared/framework/loader.luam +73 -0
- package/template/src/shared/framework/thread-pool.luam +27 -0
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@thigasdevelopment/luam",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "The Luam compiler for Multi Theft Auto resources.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"mta",
|
|
7
|
+
"mtasa",
|
|
8
|
+
"multi-theft-auto",
|
|
9
|
+
"lua",
|
|
10
|
+
"lua5.1",
|
|
11
|
+
"luau",
|
|
12
|
+
"compiler",
|
|
13
|
+
"transpiler",
|
|
14
|
+
"typed-lua"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://github.com/ThigasDevelopment/luam#readme",
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/ThigasDevelopment/luam/issues"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/ThigasDevelopment/luam.git"
|
|
23
|
+
},
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"author": "Thigas",
|
|
26
|
+
"type": "module",
|
|
27
|
+
"bin": {
|
|
28
|
+
"luam": "luam.mjs"
|
|
29
|
+
},
|
|
30
|
+
"engines": {
|
|
31
|
+
"node": ">=20"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"luam.mjs",
|
|
35
|
+
"lua",
|
|
36
|
+
"template"
|
|
37
|
+
]
|
|
38
|
+
}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
# luam-resource
|
|
2
|
+
|
|
3
|
+
A Luam resource scaffolded by `luam init`. Write `.luam` sources under `src`, run
|
|
4
|
+
`luam build`, and MTA gets a plain Lua 5.1 resource in `build/luam-resource`.
|
|
5
|
+
|
|
6
|
+
## Commands
|
|
7
|
+
|
|
8
|
+
| Command | Behavior |
|
|
9
|
+
| ------- | -------- |
|
|
10
|
+
| `luam check` | Compiles and reports diagnostics. Writes nothing. |
|
|
11
|
+
| `luam build` | Writes the resource into `build/luam-resource`. |
|
|
12
|
+
| `luam ensure` | Builds, syncs into the MTA server, restarts, and watches sources. |
|
|
13
|
+
|
|
14
|
+
Set `serverPath` in `luam.json` before running `luam ensure`.
|
|
15
|
+
|
|
16
|
+
## Layout
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
.env Declares deployment keys and safe defaults
|
|
20
|
+
config.lua Structural settings the resource owns
|
|
21
|
+
assets/ Files copied verbatim and downloaded by clients
|
|
22
|
+
src/
|
|
23
|
+
shared/
|
|
24
|
+
config.luam Constants and helpers both sides use
|
|
25
|
+
framework/ Core, Event, Listener, Command, Loader, ThreadPool
|
|
26
|
+
server/
|
|
27
|
+
main.luam Creates the server Core and starts it
|
|
28
|
+
handlers/ One file per server listener
|
|
29
|
+
commands/ One file per server command
|
|
30
|
+
client/
|
|
31
|
+
main.luam Creates the client Core and starts it
|
|
32
|
+
commands/ One file per client command
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The generated resource mirrors this tree. `src/server/main.luam` becomes
|
|
36
|
+
`src/server/main.lua`, and runtime helpers land in `src/<environment>/lib`, so a
|
|
37
|
+
server-only helper is never downloaded by a client.
|
|
38
|
+
|
|
39
|
+
## Configuration
|
|
40
|
+
|
|
41
|
+
Two files hold settings, and they have different owners.
|
|
42
|
+
|
|
43
|
+
`config.lua` belongs to the resource author. It is plain Lua, copied verbatim,
|
|
44
|
+
listed in `meta.xml` as a shared script, and readable by clients. Anything a
|
|
45
|
+
player may see belongs here.
|
|
46
|
+
|
|
47
|
+
`.env` belongs to the deployment. It declares the keys and safe defaults, and it
|
|
48
|
+
is the source of truth for their types: an unquoted number is a number, `true`
|
|
49
|
+
and `false` are booleans, and quoting forces a string. Override values locally in
|
|
50
|
+
`.env.local`, which is never committed.
|
|
51
|
+
|
|
52
|
+
The first `luam build` writes `build/<resource>/.env` from those keys, leaving
|
|
53
|
+
sensitive values blank, and never overwrites it again — that file belongs to the
|
|
54
|
+
server administrator.
|
|
55
|
+
|
|
56
|
+
Values reach Luam through `process.env`, which exists only on the server:
|
|
57
|
+
|
|
58
|
+
```lua
|
|
59
|
+
outputServerLog(tostring(process.env.SERVER_NAME))
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
A key that `.env` does not declare is a compile error, and `process` in a client
|
|
63
|
+
or shared file is a compile error too.
|
|
64
|
+
|
|
65
|
+
## Framework
|
|
66
|
+
|
|
67
|
+
`Core` owns the resource lifecycle. `main.luam` creates it with the side it runs
|
|
68
|
+
on and calls `start()` once the resource has finished loading. `start()` scans
|
|
69
|
+
the class registry, instantiates every `Listener` and `Command` subclass with the
|
|
70
|
+
`Core` instance, and registers them.
|
|
71
|
+
|
|
72
|
+
### Listeners
|
|
73
|
+
|
|
74
|
+
A listener declares the MTA event it handles and overrides `handle`. Nothing
|
|
75
|
+
registers it by hand — being a `Listener` subclass is enough.
|
|
76
|
+
|
|
77
|
+
```lua
|
|
78
|
+
class PlayerQuitListener extends Listener {
|
|
79
|
+
event: string = 'onPlayerQuit'
|
|
80
|
+
|
|
81
|
+
handle(...): void {
|
|
82
|
+
outputDebugString(getPlayerName(source) .. ' left.')
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
`element` defaults to `root`. Set it to narrow the handler to one element.
|
|
88
|
+
|
|
89
|
+
### Commands
|
|
90
|
+
|
|
91
|
+
A command declares its name, optional aliases, and overrides `execute`. Every
|
|
92
|
+
name and alias is registered.
|
|
93
|
+
|
|
94
|
+
```lua
|
|
95
|
+
class KickCommand extends Command {
|
|
96
|
+
name: string = 'kick'
|
|
97
|
+
aliases: string[] = { 'k' }
|
|
98
|
+
description: string = 'Kicks a player by name.'
|
|
99
|
+
|
|
100
|
+
execute(player: any, ...): void {
|
|
101
|
+
local args: any = { ... }
|
|
102
|
+
|
|
103
|
+
kickPlayer(getPlayerFromName(args[1]), player, 'kicked')
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
On the server `execute` receives the calling player; on the client the first
|
|
109
|
+
parameter is `nil`.
|
|
110
|
+
|
|
111
|
+
### Threads
|
|
112
|
+
|
|
113
|
+
`ThreadPool` wraps the `threads.lua` runtime helper, which is opt-in. Add it to
|
|
114
|
+
`luam.json` before using the class:
|
|
115
|
+
|
|
116
|
+
```json
|
|
117
|
+
{
|
|
118
|
+
"helpers": ["threads"]
|
|
119
|
+
}
|
|
120
|
+
```
|
package/template/env
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# Deployment values. This file is versioned and declares the keys and safe
|
|
2
|
+
# defaults. Types come from this file: an unquoted number is a number, "true"
|
|
3
|
+
# and "false" are booleans, and quoting forces a string.
|
|
4
|
+
#
|
|
5
|
+
# Override values on your machine in ".env.local", which is never committed.
|
|
6
|
+
# The server administrator edits the generated "build/.env" instead.
|
|
7
|
+
|
|
8
|
+
# Server
|
|
9
|
+
SERVER_NAME="Luam Server"
|
|
10
|
+
MAX_PLAYERS=32
|
|
11
|
+
DEBUG=false
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
class Command {
|
|
2
|
+
core: any = nil
|
|
3
|
+
name: string = ''
|
|
4
|
+
aliases: string[] = {}
|
|
5
|
+
description: string = ''
|
|
6
|
+
|
|
7
|
+
constructor(core: any) {
|
|
8
|
+
self.core = core
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
execute(player: any, ...): void {
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
names(): string[] {
|
|
15
|
+
local found: string[] = {}
|
|
16
|
+
|
|
17
|
+
if self.name ~= '' then
|
|
18
|
+
table.insert(found, self.name)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
for index = 1, #self.aliases do
|
|
22
|
+
table.insert(found, self.aliases[index])
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
return found
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
handler(): any {
|
|
29
|
+
local command: Command = self
|
|
30
|
+
|
|
31
|
+
if self.core:isServer() then
|
|
32
|
+
return function(player: any, invoked: string, ...)
|
|
33
|
+
command:execute(player, ...)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
return function(invoked: string, ...)
|
|
38
|
+
command:execute(nil, ...)
|
|
39
|
+
end
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
register(): number {
|
|
43
|
+
local registered: number = 0
|
|
44
|
+
local found: string[] = self:names()
|
|
45
|
+
|
|
46
|
+
for index = 1, #found do
|
|
47
|
+
addCommandHandler(found[index], self:handler())
|
|
48
|
+
|
|
49
|
+
registered += 1
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
return registered
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
class Core {
|
|
2
|
+
side: string = 'shared'
|
|
3
|
+
listeners: any = nil
|
|
4
|
+
commands: any = nil
|
|
5
|
+
started: boolean = false
|
|
6
|
+
|
|
7
|
+
constructor(side: string) {
|
|
8
|
+
self.side = side
|
|
9
|
+
self.listeners = {}
|
|
10
|
+
self.commands = {}
|
|
11
|
+
self.started = false
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
isServer(): boolean {
|
|
15
|
+
return self.side == 'server'
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
isClient(): boolean {
|
|
19
|
+
return self.side == 'client'
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
log(message: string): void {
|
|
23
|
+
outputDebugString('[' .. self.side .. '] ' .. message)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
start(): boolean {
|
|
27
|
+
if self.started then
|
|
28
|
+
return false
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
self.started = true
|
|
32
|
+
|
|
33
|
+
local loader: Loader = new Loader(self)
|
|
34
|
+
|
|
35
|
+
self.listeners = loader:loadListeners()
|
|
36
|
+
self.commands = loader:loadCommands()
|
|
37
|
+
|
|
38
|
+
self:log('loaded ' .. #self.listeners .. ' listener(s) and ' .. #self.commands .. ' command(s)')
|
|
39
|
+
|
|
40
|
+
return true
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
stop(): boolean {
|
|
44
|
+
if not self.started then
|
|
45
|
+
return false
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
for index = 1, #self.listeners do
|
|
49
|
+
self.listeners[index]:unregister()
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
self.listeners = {}
|
|
53
|
+
self.commands = {}
|
|
54
|
+
self.started = false
|
|
55
|
+
|
|
56
|
+
return true
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
class Event {
|
|
2
|
+
name: string = ''
|
|
3
|
+
element: any = nil
|
|
4
|
+
handler: any = nil
|
|
5
|
+
attached: boolean = false
|
|
6
|
+
|
|
7
|
+
constructor(name: string, element: any, handler: any) {
|
|
8
|
+
self.name = name
|
|
9
|
+
self.element = element
|
|
10
|
+
self.handler = handler
|
|
11
|
+
self.attached = false
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
attach(): boolean {
|
|
15
|
+
if self.attached then
|
|
16
|
+
return false
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
self.attached = addEventHandler(self.name, self.element, self.handler)
|
|
20
|
+
|
|
21
|
+
return self.attached
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
detach(): boolean {
|
|
25
|
+
if not self.attached then
|
|
26
|
+
return false
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
removeEventHandler(self.name, self.element, self.handler)
|
|
30
|
+
|
|
31
|
+
self.attached = false
|
|
32
|
+
|
|
33
|
+
return true
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
describe(): string {
|
|
37
|
+
return self.name
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
class Listener {
|
|
2
|
+
core: any = nil
|
|
3
|
+
event: string = ''
|
|
4
|
+
element: any = nil
|
|
5
|
+
binding: any = nil
|
|
6
|
+
|
|
7
|
+
constructor(core: any) {
|
|
8
|
+
self.core = core
|
|
9
|
+
self.binding = nil
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
target(): any {
|
|
13
|
+
if self.element == nil then
|
|
14
|
+
return root
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
return self.element
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
handle(...): void {
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
register(): boolean {
|
|
24
|
+
if self.event == '' then
|
|
25
|
+
return false
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
self.binding = new Event(self.event, self:target(), bind(self.handle, self))
|
|
29
|
+
|
|
30
|
+
return self.binding:attach()
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
unregister(): boolean {
|
|
34
|
+
if self.binding == nil then
|
|
35
|
+
return false
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
return self.binding:detach()
|
|
39
|
+
}
|
|
40
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
class Loader {
|
|
2
|
+
core: any = nil
|
|
3
|
+
|
|
4
|
+
constructor(core: any) {
|
|
5
|
+
self.core = core
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
inherits(definition: any, baseName: string): boolean {
|
|
9
|
+
local current: any = definition
|
|
10
|
+
|
|
11
|
+
while current ~= nil do
|
|
12
|
+
local parent: any = rawget(current, '__super')
|
|
13
|
+
|
|
14
|
+
if parent == nil then
|
|
15
|
+
return false
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
if rawget(parent, '__name') == baseName then
|
|
19
|
+
return true
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
current = parent
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
return false
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
subclasses(baseName: string): string[] {
|
|
29
|
+
local found: string[] = {}
|
|
30
|
+
local definitions: table = getClasses()
|
|
31
|
+
|
|
32
|
+
for name, definition in pairs(definitions) do
|
|
33
|
+
if self:inherits(definition, baseName) then
|
|
34
|
+
table.insert(found, name)
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
table.sort(found)
|
|
39
|
+
|
|
40
|
+
return found
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
instantiate(baseName: string): any {
|
|
44
|
+
local created: any = {}
|
|
45
|
+
local names: string[] = self:subclasses(baseName)
|
|
46
|
+
|
|
47
|
+
for index = 1, #names do
|
|
48
|
+
table.insert(created, new(names[index])(self.core))
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
return created
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
loadListeners(): any {
|
|
55
|
+
local listeners: any = self:instantiate('Listener')
|
|
56
|
+
|
|
57
|
+
for index = 1, #listeners do
|
|
58
|
+
listeners[index]:register()
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
return listeners
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
loadCommands(): any {
|
|
65
|
+
local commands: any = self:instantiate('Command')
|
|
66
|
+
|
|
67
|
+
for index = 1, #commands do
|
|
68
|
+
commands[index]:register()
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
return commands
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
class ThreadPool {
|
|
2
|
+
pool: any = nil
|
|
3
|
+
|
|
4
|
+
constructor(style: string, priority: string) {
|
|
5
|
+
self.pool = Threads.new(style, priority)
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
add(task: any): number {
|
|
9
|
+
return self.pool:add(task, {})
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
remove(id: number): boolean {
|
|
13
|
+
return self.pool:remove(id)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
clear(): boolean {
|
|
17
|
+
return self.pool:clear()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
priority(): string {
|
|
21
|
+
return self.pool:getPriority()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
setPriority(priority: string): boolean {
|
|
25
|
+
return self.pool:setPriority(priority)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
class HelloCommand extends Command {
|
|
2
|
+
name: string = 'hello'
|
|
3
|
+
aliases: string[] = { 'hi', 'greet' }
|
|
4
|
+
description: string = 'Greets the calling player with the configured message.'
|
|
5
|
+
|
|
6
|
+
execute(player: any, ...): void {
|
|
7
|
+
outputChatBox(formatPlayerLabel(tostring(Config.greeting)), player)
|
|
8
|
+
}
|
|
9
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
local core: Core = new Core('server')
|
|
2
|
+
|
|
3
|
+
addEventHandler('onResourceStart', resourceRoot, function()
|
|
4
|
+
core:start()
|
|
5
|
+
|
|
6
|
+
outputServerLog(`[${process.env.SERVER_NAME}] started with room for ${process.env.MAX_PLAYERS} players.`)
|
|
7
|
+
end)
|
|
8
|
+
|
|
9
|
+
addEventHandler('onResourceStop', resourceRoot, function()
|
|
10
|
+
core:stop()
|
|
11
|
+
end)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
class Command {
|
|
2
|
+
core: any = nil
|
|
3
|
+
name: string = ''
|
|
4
|
+
aliases: string[] = {}
|
|
5
|
+
description: string = ''
|
|
6
|
+
|
|
7
|
+
constructor(core: any) {
|
|
8
|
+
self.core = core
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
execute(player: any, ...): void {
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
names(): string[] {
|
|
15
|
+
local found: string[] = {}
|
|
16
|
+
|
|
17
|
+
if self.name ~= '' then
|
|
18
|
+
table.insert(found, self.name)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
for index = 1, #self.aliases do
|
|
22
|
+
table.insert(found, self.aliases[index])
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
return found
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
handler(): any {
|
|
29
|
+
local command: Command = self
|
|
30
|
+
|
|
31
|
+
if self.core:isServer() then
|
|
32
|
+
return function(player: any, invoked: string, ...)
|
|
33
|
+
command:execute(player, ...)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
return function(invoked: string, ...)
|
|
38
|
+
command:execute(nil, ...)
|
|
39
|
+
end
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
register(): number {
|
|
43
|
+
local registered: number = 0
|
|
44
|
+
local found: string[] = self:names()
|
|
45
|
+
|
|
46
|
+
for index = 1, #found do
|
|
47
|
+
addCommandHandler(found[index], self:handler())
|
|
48
|
+
|
|
49
|
+
registered += 1
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
return registered
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
class Core {
|
|
2
|
+
side: string = 'shared'
|
|
3
|
+
listeners: any = nil
|
|
4
|
+
commands: any = nil
|
|
5
|
+
started: boolean = false
|
|
6
|
+
|
|
7
|
+
constructor(side: string) {
|
|
8
|
+
self.side = side
|
|
9
|
+
self.listeners = {}
|
|
10
|
+
self.commands = {}
|
|
11
|
+
self.started = false
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
isServer(): boolean {
|
|
15
|
+
return self.side == 'server'
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
isClient(): boolean {
|
|
19
|
+
return self.side == 'client'
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
log(message: string): void {
|
|
23
|
+
outputDebugString('[' .. self.side .. '] ' .. message)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
start(): boolean {
|
|
27
|
+
if self.started then
|
|
28
|
+
return false
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
self.started = true
|
|
32
|
+
|
|
33
|
+
local loader: Loader = new Loader(self)
|
|
34
|
+
|
|
35
|
+
self.listeners = loader:loadListeners()
|
|
36
|
+
self.commands = loader:loadCommands()
|
|
37
|
+
|
|
38
|
+
self:log('loaded ' .. #self.listeners .. ' listener(s) and ' .. #self.commands .. ' command(s)')
|
|
39
|
+
|
|
40
|
+
return true
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
stop(): boolean {
|
|
44
|
+
if not self.started then
|
|
45
|
+
return false
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
for index = 1, #self.listeners do
|
|
49
|
+
self.listeners[index]:unregister()
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
self.listeners = {}
|
|
53
|
+
self.commands = {}
|
|
54
|
+
self.started = false
|
|
55
|
+
|
|
56
|
+
return true
|
|
57
|
+
}
|
|
58
|
+
}
|