From 82fe74e1231c3893cd640af2295c0f16d6cfdcd0 Mon Sep 17 00:00:00 2001 From: xLuxy <67131061+xLuxy@users.noreply.github.com> Date: Mon, 16 Sep 2024 08:57:42 +0200 Subject: [PATCH 01/15] chore(shared): Update Timers and Events to use net time instead --- shared/js/events.js | 12 ++++++------ shared/js/logging.js | 31 ++++++++++++++++++++++--------- shared/js/timers.js | 19 ++++++++++++------- shared/js/utils.js | 6 +++--- 4 files changed, 43 insertions(+), 25 deletions(-) diff --git a/shared/js/events.js b/shared/js/events.js index 7c3adfdbd..1ab4fecef 100644 --- a/shared/js/events.js +++ b/shared/js/events.js @@ -95,10 +95,10 @@ export class Event { const { handler, location, onlyOnce, eventName } = eventHandler; try { - const startTime = Date.now(); + const startTime = alt.getNetTime(); if (isPlayerScriptEvent) handler(ctx.player, ...ctx.args); else handler(...ctx.args); - const duration = Date.now() - startTime; + const duration = alt.getNetTime() - startTime; if (duration > Event.#warningThreshold) { alt.logWarning(`[JS] Event handler in resource '${cppBindings.resourceName}' (${location.fileName}:${location.lineNumber}) for script event '${name}' took ${duration}ms to execute (Threshold: ${Event.#warningThreshold}ms)`); } @@ -196,9 +196,9 @@ export class Event { for (let { handler, location } of handlers) { try { - const startTime = Date.now(); + const startTime = alt.getNetTime(); handler(genericCtx); - const duration = Date.now() - startTime; + const duration = alt.getNetTime() - startTime; if (duration > Event.#warningThreshold) { alt.logWarning(`[JS] Generic event handler in resource '${cppBindings.resourceName}' (${location.fileName}:${location.lineNumber}) for event '${Event.getEventName(eventType, custom)}' took ${duration}ms to execute (Threshold: ${Event.#warningThreshold}ms)`); } @@ -261,9 +261,9 @@ export class Event { const { handler, location, onlyOnce } = eventHandler; try { - const startTime = Date.now(); + const startTime = alt.getNetTime(); handler(ctx); - const duration = Date.now() - startTime; + const duration = alt.getNetTime() - startTime; if (duration > Event.#warningThreshold) alt.logWarning(`[JS] Event handler in resource '${cppBindings.resourceName}' (${location.fileName}:${location.lineNumber}) for event '${Event.getEventName(eventType, custom)}' took ${duration}ms to execute (Threshold: ${Event.#warningThreshold}ms)`); if (onlyOnce) eventHandler.destroy(); diff --git a/shared/js/logging.js b/shared/js/logging.js index ef52dda1b..7f7c95e59 100644 --- a/shared/js/logging.js +++ b/shared/js/logging.js @@ -2814,32 +2814,45 @@ cppBindings.registerExport(cppBindings.BindingExport.LOG_INSPECT, inspectMultipl /** @type {Map} */ const timeLabelMap = new Map(); function time(label) { - if (timeLabelMap.has(label ?? "Timer")) throw new Error(`Label '${label ?? "Timer"}' already running`); - timeLabelMap.set(label ?? "Timer", Date.now()); + if (timeLabelMap.has(label ?? "Timer")) { + throw new Error(`Label '${label ?? "Timer"}' already running`); + } + + timeLabelMap.set(label ?? "Timer", alt.getNetTime()); } function timeLog(label) { - const start = timeLabelMap.get(label ?? "Timer"); - if (start === undefined) throw new Error(`No such label '${label ?? "Timer"}' running`); - const duration = Date.now() - start; + const startTime = timeLabelMap.get(label ?? "Timer"); + if (startTime === undefined) { + throw new Error(`No such label '${label ?? "Timer"}' running`); + } + + const duration = alt.getNetTime() - startTime; alt.log(`[JS] ${label ?? "Timer"}: ${duration}ms`); } function timeEnd(label) { - const start = timeLabelMap.get(label ?? "Timer"); - if (start === undefined) throw new Error(`No such label '${label ?? "Timer"}' running`); - const duration = Date.now() - start; + const startTime = timeLabelMap.get(label ?? "Timer"); + if (startTime === undefined) { + throw new Error(`No such label '${label ?? "Timer"}' running`); + } + + const duration = alt.getNetTime() - startTime; alt.log(`[JS] ${label ?? "Timer"}: ${duration}ms`); timeLabelMap.delete(label ?? "Timer"); } function logDebug(...args) { if (!alt.isDebug) return; + alt.log(...args); } alt.logDebug = logDebug; if (alt.isClient) { - if (!globalThis.console) globalThis.console = {}; + if (!globalThis.console) { + globalThis.console = {}; + } + globalThis.console.log = alt.log; globalThis.console.debug = alt.logDebug; globalThis.console.warn = alt.logWarning; diff --git a/shared/js/timers.js b/shared/js/timers.js index 71036aad7..32e6fb791 100644 --- a/shared/js/timers.js +++ b/shared/js/timers.js @@ -73,7 +73,7 @@ class Timer { this.interval = interval; this.callback = callback.bind(this, ...(Array.isArray(args) ? args : [])); - this.lastTick = Date.now(); + this.lastTick = alt.getNetTime(); this.once = once; this.#_type = type; this.#_id = Timer.#timerIncrementer++; @@ -86,7 +86,7 @@ class Timer { } tick() { - const now = Date.now(); + const now = alt.getNetTime(); if (this.interval === 0 || now - this.lastTick >= this.interval) { try { this.callback(); @@ -96,7 +96,7 @@ class Timer { Event.invoke(alt.Enums.CustomEventType.ERROR, { error: e, location: this.location, stack: e.stack }, true); } - this.lastTick = Date.now(); + this.lastTick = alt.getNetTime(); const duration = this.lastTick - now; if (duration > Timer.#_warningThreshold) { @@ -141,9 +141,11 @@ const timeMap = new Map(); function time(name) { const key = typeof name == "string" ? name : ""; - if (timeMap.has(key)) throw new Error(`Benchmark timer ${key} already exists`); + if (timeMap.has(key)) { + throw new Error(`Benchmark timer ${key} already exists`); + } - timeMap.set(key, Date.now()); + timeMap.set(key, alt.getNetTime()); } /** @@ -153,9 +155,11 @@ function time(name) { function timeEnd(name) { const key = typeof name == "string" ? name : ""; - if (!timeMap.has(key)) throw new Error(`Benchmark timer ${key} not found`); + if (!timeMap.has(key)) { + throw new Error(`Benchmark timer ${key} not found`); + } - const diff = Date.now() - timeMap.get(key); + const diff = alt.getNetTime() - timeMap.get(key); timeMap.delete(key); alt.log(`Timer ${key}: ${diff}ms`); @@ -201,6 +205,7 @@ globalThis.clearInterval = (interval) => { interval.destroy(); } }; + globalThis.clearTimeout = (timeout) => { if (timeout instanceof Timeout) { timeout.destroy(); diff --git a/shared/js/utils.js b/shared/js/utils.js index b55e0093f..babce0c86 100644 --- a/shared/js/utils.js +++ b/shared/js/utils.js @@ -14,17 +14,17 @@ export function waitFor(cb, timeout = 2000) { assertIsType(cb, "function", "Expected a function as first argument"); assertIsType(timeout, "number", "Expected a number or undefined as second argument"); - const checkUntil = Date.now() + timeout; + const checkUntil = alt.getNetTime() + timeout; const sourceLocation = cppBindings.getCurrentSourceLocation(); const source = `resource: ${cppBindings.resourceName} source: ${sourceLocation.fileName}:${sourceLocation.lineNumber}`; return new Promise((resolve, reject) => { alt.Timers.everyTick(function () { - if (Date.now() > checkUntil) { + if (alt.getNetTime() > checkUntil) { this.destroy(); return reject(new Error(`waitFor timed out (limit was ${timeout}ms, ${source})`)); } - + let result; try { result = cb(); From 0aeec1077e9e3bb6f5c71fa03b310fcb548a15f0 Mon Sep 17 00:00:00 2001 From: xLuxy <67131061+xLuxy@users.noreply.github.com> Date: Mon, 16 Sep 2024 11:34:10 +0200 Subject: [PATCH 02/15] fix(shared): Fix RESOURCE_STOP freezing --- shared/src/Event.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/shared/src/Event.cpp b/shared/src/Event.cpp index a7294c17d..dcdea7651 100644 --- a/shared/src/Event.cpp +++ b/shared/src/Event.cpp @@ -27,21 +27,13 @@ void js::Event::SendEvent(const alt::CEvent* ev, IResource* resource) eventHandler->argsCb(ev, eventArgs); - js::Promise promise = CallEventBinding(false, (int)ev->GetType(), eventArgs, resource); + CallEventBinding(false, (int)ev->GetType(), eventArgs, resource); eventArgs.Get()->SetAlignedPointerInInternalField(1, nullptr); - - if (!promise.IsValid()) return; - - if (ev->GetType() == alt::CEvent::Type::RESOURCE_STOP && static_cast(ev)->GetResource() == resource->GetResource()) - { - promise.Await(); - } } void js::Event::SendEvent(EventType type, EventArgs& args, IResource* resource) { - js::Promise promise = CallEventBinding(true, (int)type, args, resource); - if(!promise.IsValid()) return; + CallEventBinding(true, (int)type, args, resource); } // Class From f4a09e3a347e0d13d062143e5cb6b0f84111619f Mon Sep 17 00:00:00 2001 From: xLuxy <67131061+xLuxy@users.noreply.github.com> Date: Mon, 16 Sep 2024 15:48:11 +0200 Subject: [PATCH 03/15] fix(shared): Fix Cannot read properties of null (reading 'type') (#256) --- shared/js/entity.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/shared/js/entity.js b/shared/js/entity.js index f2a353773..e8895deda 100644 --- a/shared/js/entity.js +++ b/shared/js/entity.js @@ -55,10 +55,14 @@ alt.Events.onBaseObjectRemove(({ object }) => { }); export function addEntityToAll(entity) { + if (entity == null || !(entity instanceof alt.BaseObject)) return; + addEntityToAllWithType(entity, entity.type); } export function removeEntityFromAll(entity) { + if (entity == null || !(entity instanceof alt.BaseObject)) return; + entityAllSetDirty = true; entityAllSet.delete(entity); const all = entityAllMap.get(entity.type); From f29df54587bdeea608d9948fa603c46cc69fac8f Mon Sep 17 00:00:00 2001 From: xLuxy <67131061+xLuxy@users.noreply.github.com> Date: Mon, 16 Sep 2024 17:58:14 +0200 Subject: [PATCH 04/15] chore: Refactor CallEventBinding slightly --- shared/src/Event.cpp | 24 +++++++++++++++++------- shared/src/Event.h | 4 +++- shared/src/helpers/JS.h | 6 +----- 3 files changed, 21 insertions(+), 13 deletions(-) diff --git a/shared/src/Event.cpp b/shared/src/Event.cpp index dcdea7651..e0e89d7e4 100644 --- a/shared/src/Event.cpp +++ b/shared/src/Event.cpp @@ -4,15 +4,19 @@ extern js::Class eventContextClass, cancellableEventContextClass; -js::Promise js::Event::CallEventBinding(bool custom, int type, EventArgs& args, IResource* resource) +std::optional js::Event::CallEventBinding(bool custom, int type, EventArgs& args, IResource* resource) { - v8::Isolate* isolate = resource->GetIsolate(); - v8::Local context = resource->GetContext(); js::Function onEvent = resource->GetBindingExport(BindingExport::ON_EVENT); - if(!onEvent.IsValid()) return js::Promise{ v8::Local() }; + if (!onEvent.IsValid()) + return std::nullopt; std::optional> result = onEvent.Call>(custom, type, args.Get()); - return js::Promise{ result.value_or(v8::Local()).As() }; + auto promise = js::Promise{ result.value_or(v8::Local()).As() }; + + if (!promise.Get().IsEmpty()) + return promise; + + return std::nullopt; } void js::Event::SendEvent(const alt::CEvent* ev, IResource* resource) @@ -21,13 +25,19 @@ void js::Event::SendEvent(const alt::CEvent* ev, IResource* resource) if(!eventHandler) return; EventArgs eventArgs; - if(ev->IsCancellable()) eventArgs = cancellableEventContextClass.Create(resource->GetContext(), (void*)ev); + if(ev->IsCancellable()) + eventArgs = cancellableEventContextClass.Create(resource->GetContext(), (void*)ev); else eventArgs = eventContextClass.Create(resource->GetContext(), (void*)ev); eventHandler->argsCb(ev, eventArgs); - CallEventBinding(false, (int)ev->GetType(), eventArgs, resource); + auto promise = CallEventBinding(false, (int)ev->GetType(), eventArgs, resource); + if (promise.has_value() && ev->GetType() == alt::CEvent::Type::RESOURCE_STOP && resource->GetResource() == static_cast(ev)->GetResource()) + { + promise->Await(); + } + eventArgs.Get()->SetAlignedPointerInInternalField(1, nullptr); } diff --git a/shared/src/Event.h b/shared/src/Event.h index a55a50d1d..fc88f65f4 100644 --- a/shared/src/Event.h +++ b/shared/src/Event.h @@ -43,6 +43,7 @@ namespace js static std::unordered_map eventHandlerMap; return eventHandlerMap; } + static Event* GetEventHandler(alt::CEvent::Type type) { auto& eventHandlerMap = GetEventHandlerMap(); @@ -50,7 +51,8 @@ namespace js if(it == eventHandlerMap.end()) return nullptr; return it->second; } - static js::Promise CallEventBinding(bool custom, int type, EventArgs& args, IResource* resource); + + static std::optional CallEventBinding(bool custom, int type, EventArgs& args, IResource* resource); public: Event(alt::CEvent::Type _type, EventArgsCallback _argsCb) : type(_type), argsCb(_argsCb) diff --git a/shared/src/helpers/JS.h b/shared/src/helpers/JS.h index da1679afe..1db725c43 100644 --- a/shared/src/helpers/JS.h +++ b/shared/src/helpers/JS.h @@ -640,15 +640,11 @@ namespace js { v8::Promise::PromiseState state = promise->State(); - switch(state) + switch (state) { case v8::Promise::PromiseState::kPending: internal::RunEventLoop(); break; case v8::Promise::PromiseState::kFulfilled: return true; case v8::Promise::PromiseState::kRejected: return false; - - // NOTE (xLuxy): I have no idea why state can be 3 or what it means - it's undocumented - // state is probably state - 1? - case 3: return false; } std::this_thread::sleep_for(std::chrono::milliseconds(1)); From 8463b3adce8efbaa01f506d3507522320df81d63 Mon Sep 17 00:00:00 2001 From: xLuxy <67131061+xLuxy@users.noreply.github.com> Date: Wed, 18 Sep 2024 09:16:45 +0200 Subject: [PATCH 05/15] fix(client): Fix TextDecoder constructor --- client/src/classes/TextDecoder.cpp | 4 ++-- client/src/classes/TextEncoder.cpp | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/client/src/classes/TextDecoder.cpp b/client/src/classes/TextDecoder.cpp index b941f8907..f7879e163 100644 --- a/client/src/classes/TextDecoder.cpp +++ b/client/src/classes/TextDecoder.cpp @@ -1,6 +1,6 @@ #include "Class.h" -static void Constructor(js::FunctionContext& ctx) +static void TextDecoderConstructor(js::FunctionContext& ctx) { if (!ctx.CheckCtor()) return; if (!ctx.CheckArgCount(0, 2)) return; @@ -35,7 +35,7 @@ static void EncodingGetter(js::PropertyContext& ctx) ctx.Return(ctx.GetThis()->Get(ctx.GetContext(), js::JSValue("__encoding")).ToLocalChecked()); } -extern js::Class textDecoderClass("TextDecoder", Constructor, [](js::ClassTemplate& tpl) +extern js::Class textDecoderClass("TextDecoder", TextDecoderConstructor, [](js::ClassTemplate& tpl) { tpl.Property("encoding", EncodingGetter); }); diff --git a/client/src/classes/TextEncoder.cpp b/client/src/classes/TextEncoder.cpp index 9179ed8a5..1768b11a8 100644 --- a/client/src/classes/TextEncoder.cpp +++ b/client/src/classes/TextEncoder.cpp @@ -1,11 +1,12 @@ #include "Class.h" +static void TextEncoderConstructor(js::FunctionContext&) { } + static void EncodingGetter(js::LazyPropertyContext& ctx) { ctx.Return(std::string("utf-8")); } - static void Encode(js::FunctionContext& ctx) { if (!ctx.CheckArgCount(1)) return; @@ -48,7 +49,7 @@ static void EncodeInto(js::FunctionContext& ctx) ctx.Return(result); } -extern js::Class textEncoderClass("TextEncoder", [](js::ClassTemplate& tpl) +extern js::Class textEncoderClass("TextEncoder", TextEncoderConstructor, [](js::ClassTemplate& tpl) { tpl.LazyProperty("encoding", EncodingGetter); From e2c7f84cd080c7491778fce23612f2d238960d9c Mon Sep 17 00:00:00 2001 From: xLuxy <67131061+xLuxy@users.noreply.github.com> Date: Wed, 18 Sep 2024 09:31:48 +0200 Subject: [PATCH 06/15] fix(server, compat): Fix Player.setDlcClothes args --- server/js/compatibility/classes/player.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/server/js/compatibility/classes/player.js b/server/js/compatibility/classes/player.js index 6c30528b6..24778f1f8 100644 --- a/server/js/compatibility/classes/player.js +++ b/server/js/compatibility/classes/player.js @@ -7,9 +7,8 @@ const { extendClassWithProperties, overrideLazyProperty } = requireBinding("shar const { SharedPlayer } = requireBinding("shared/compatibility/classes/sharedPlayer.js"); -// NOTE(xLuxy): Store the original spawn method to call it later since we can't call it directly using super -// and we need to override it const originalSpawnMethod = alt.Player.prototype.spawn; +const originalSetDlcClothes = alt.Player.prototype.setDlcClothes; class Player { onCreate() { @@ -65,6 +64,10 @@ class Player { originalSpawnMethod.call(this, pos, delay); } + setDlcClothes(dlc, component, drawable, texture, palette = 2) { + return originalSetDlcClothes.call(this, component, drawable, texture, palette, dlc); + } + isEntityInStreamRange(entity) { return this.isEntityInStreamingRange(entity); } From 5966a220e4a15b6ec08b3b3fddafbac91b6dc6b6 Mon Sep 17 00:00:00 2001 From: xLuxy <67131061+xLuxy@users.noreply.github.com> Date: Thu, 19 Sep 2024 12:36:24 +0200 Subject: [PATCH 07/15] fix(shared): Wait for RESOURCE_STOP event callback to complete (async) --- shared/js/events.js | 68 +++++++++++++++++++++++++++++--------- shared/js/events/script.js | 8 +++-- shared/js/utils.js | 6 ++++ shared/src/Event.cpp | 4 +-- types/shared/index.d.ts | 2 ++ types/shared/package.json | 2 +- 6 files changed, 70 insertions(+), 20 deletions(-) diff --git a/shared/js/events.js b/shared/js/events.js index 1ab4fecef..4bf80915d 100644 --- a/shared/js/events.js +++ b/shared/js/events.js @@ -1,5 +1,5 @@ /** @type {typeof import("./utils.js")} */ -const { assert, assertIsType } = requireBinding("shared/utils.js"); +const { assert, assertIsType, isAsyncFunction } = requireBinding("shared/utils.js"); /** @type {typeof import("../../shared/js/helpers/events.js")} */ const { emitRaw } = requireBinding("shared/helpers/events.js"); @@ -88,16 +88,28 @@ export class Event { static #handleScriptEvent(ctx, local) { const name = ctx.eventName; const handlers = local ? Event.#localScriptEventHandlers.get(name) : Event.#remoteScriptEventHandlers.get(name); - if (!handlers) return; + if (!handlers) { + return []; + } + const isPlayerScriptEvent = alt.isServer && !local; + const promises = []; for (let eventHandler of handlers) { const { handler, location, onlyOnce, eventName } = eventHandler; try { const startTime = alt.getNetTime(); - if (isPlayerScriptEvent) handler(ctx.player, ...ctx.args); - else handler(...ctx.args); + + const isAsync = isAsyncFunction(handler); + if (isPlayerScriptEvent) { + if (isAsync) promises.push(handler(ctx.player, ...ctx.args)); + else handler(ctx.player, ...ctx.args); + } else { + if (isAsync) promises.push(handler(...ctx.args)); + else handler(...ctx.args); + } + const duration = alt.getNetTime() - startTime; if (duration > Event.#warningThreshold) { alt.logWarning(`[JS] Event handler in resource '${cppBindings.resourceName}' (${location.fileName}:${location.lineNumber}) for script event '${name}' took ${duration}ms to execute (Threshold: ${Event.#warningThreshold}ms)`); @@ -111,6 +123,8 @@ export class Event { Event.invoke(alt.Enums.CustomEventType.ERROR, { error: e, location, stack: e.stack }, true); } } + + return promises; } static getEventHandlers() { @@ -186,7 +200,7 @@ export class Event { */ static #invokeGeneric(eventType, ctx, custom) { const handlers = Event.#genericHandlers; - if (!handlers.size) return; + if (!handlers.size) return []; const genericCtx = Object.freeze({ ...ctx, @@ -194,10 +208,14 @@ export class Event { customEvent: custom }); + const promises = []; for (let { handler, location } of handlers) { try { const startTime = alt.getNetTime(); - handler(genericCtx); + + if (isAsyncFunction(handler)) promises.push(handler(genericCtx)); + else handler(genericCtx); + const duration = alt.getNetTime() - startTime; if (duration > Event.#warningThreshold) { alt.logWarning(`[JS] Generic event handler in resource '${cppBindings.resourceName}' (${location.fileName}:${location.lineNumber}) for event '${Event.getEventName(eventType, custom)}' took ${duration}ms to execute (Threshold: ${Event.#warningThreshold}ms)`); @@ -209,6 +227,8 @@ export class Event { Event.invoke(alt.Enums.CustomEventType.ERROR, { error: e, location, stack: e.stack }, true); } } + + return promises; } /** @@ -250,23 +270,34 @@ export class Event { * @param {boolean} custom */ static invoke(eventType, ctx, custom) { - Event.#invokeGeneric(eventType, ctx, custom); - if (eventType === alt.Enums.EventType.CLIENT_SCRIPT_EVENT) Event.#handleScriptEvent(ctx, alt.isClient); - else if (eventType === alt.Enums.EventType.SERVER_SCRIPT_EVENT) Event.#handleScriptEvent(ctx, alt.isServer); + let promises = Event.#invokeGeneric(eventType, ctx, custom); + + if (eventType === alt.Enums.EventType.CLIENT_SCRIPT_EVENT) promises = [...Event.#handleScriptEvent(ctx, alt.isClient), ...promises]; + else if (eventType === alt.Enums.EventType.SERVER_SCRIPT_EVENT) promises = [...Event.#handleScriptEvent(ctx, alt.isServer), ...promises]; const map = custom ? Event.#customHandlers : Event.#handlers; const handlers = map.get(eventType); - if (!handlers) return; + + if (!handlers) { + return promises; + } + for (const eventHandler of handlers) { const { handler, location, onlyOnce } = eventHandler; try { const startTime = alt.getNetTime(); - handler(ctx); + if (isAsyncFunction(handler)) promises.push(handler(ctx)); + else handler(ctx); + const duration = alt.getNetTime() - startTime; - if (duration > Event.#warningThreshold) + if (duration > Event.#warningThreshold) { alt.logWarning(`[JS] Event handler in resource '${cppBindings.resourceName}' (${location.fileName}:${location.lineNumber}) for event '${Event.getEventName(eventType, custom)}' took ${duration}ms to execute (Threshold: ${Event.#warningThreshold}ms)`); - if (onlyOnce) eventHandler.destroy(); + } + + if (onlyOnce) { + eventHandler.destroy(); + } } catch (e) { alt.logError(`[JS] Exception caught while invoking event handler`); alt.logError(e); @@ -274,6 +305,8 @@ export class Event { Event.invoke(alt.Enums.CustomEventType.ERROR, { error: e, location, stack: e.stack }, true); } } + + return promises; } } @@ -404,7 +437,12 @@ Object.defineProperties(alt.Events, { alt.Events.setWarningThreshold = Event.setWarningThreshold; alt.Events.setSourceLocationFrameSkipCount = Event.setSourceLocationFrameSkipCount; -function onEvent(custom, eventType, eventData) { - return Event.invoke(eventType, eventData, custom); +async function onEvent(custom, eventType, eventData) { + const promises = Event.invoke(eventType, eventData, custom); + + if (promises.length >= 1) { + return Promise.all(promises); + } } + cppBindings.registerExport(cppBindings.BindingExport.ON_EVENT, onEvent); diff --git a/shared/js/events/script.js b/shared/js/events/script.js index 841118dd2..57817e586 100644 --- a/shared/js/events/script.js +++ b/shared/js/events/script.js @@ -37,7 +37,11 @@ alt.Events.onAnyResourceStart(({ resource }) => { Event.invoke(alt.Enums.CustomEventType.RESOURCE_START, {}, true); }); -alt.Events.onAnyResourceStop(({ resource }) => { +alt.Events.onAnyResourceStop(async ({ resource }) => { if (resource.name !== alt.Resource.current.name) return; - Event.invoke(alt.Enums.CustomEventType.RESOURCE_STOP, {}, true); + + const promises = Event.invoke(alt.Enums.CustomEventType.RESOURCE_STOP, {}, true); + if (promises.length >= 1) { + await Promise.all(promises); + } }); diff --git a/shared/js/utils.js b/shared/js/utils.js index babce0c86..7d5f5a54d 100644 --- a/shared/js/utils.js +++ b/shared/js/utils.js @@ -95,6 +95,10 @@ export function assertVector3(val, message = "Expected Vector3") { return assert(isVector3(val), message); } +export function isAsyncFunction(val) { + return typeof val == "function" && val.constructor.name === "AsyncFunction"; +} + alt.Utils.AssertionError = AssertionError; alt.Utils.assert = assert; alt.Utils.assertIsObject = assertIsObject; @@ -107,6 +111,8 @@ alt.Utils.assertVector3 = assertVector3; alt.Utils.isVector2 = isVector2; alt.Utils.isVector3 = isVector3; +alt.Utils.isAsyncFunction = isAsyncFunction; + export function hash(str) { assertIsType(str, "string", "Expected a string as first argument"); diff --git a/shared/src/Event.cpp b/shared/src/Event.cpp index e0e89d7e4..4700309c7 100644 --- a/shared/src/Event.cpp +++ b/shared/src/Event.cpp @@ -13,7 +13,7 @@ std::optional js::Event::CallEventBinding(bool custom, int type, Ev std::optional> result = onEvent.Call>(custom, type, args.Get()); auto promise = js::Promise{ result.value_or(v8::Local()).As() }; - if (!promise.Get().IsEmpty()) + if (!promise.Get().IsEmpty() && !promise.Get()->HasHandler()) return promise; return std::nullopt; @@ -33,7 +33,7 @@ void js::Event::SendEvent(const alt::CEvent* ev, IResource* resource) eventHandler->argsCb(ev, eventArgs); auto promise = CallEventBinding(false, (int)ev->GetType(), eventArgs, resource); - if (promise.has_value() && ev->GetType() == alt::CEvent::Type::RESOURCE_STOP && resource->GetResource() == static_cast(ev)->GetResource()) + if (promise.has_value() && ev->GetType() == alt::CEvent::Type::RESOURCE_STOP) { promise->Await(); } diff --git a/types/shared/index.d.ts b/types/shared/index.d.ts index 34a90defd..75d696428 100644 --- a/types/shared/index.d.ts +++ b/types/shared/index.d.ts @@ -686,6 +686,8 @@ declare module "@altv/shared" { export function isVector3(val: unknown): boolean; export function assertVector3(val: IVector3, message?: string): void; + export function isAsyncFunction(val: unknown): boolean; + interface ClosestEntityOptions { pos?: IVector3; // default: localPlayer.pos - required for server! range?: number; // default: infinity diff --git a/types/shared/package.json b/types/shared/package.json index 5cbb7ea75..7bb0a7963 100644 --- a/types/shared/package.json +++ b/types/shared/package.json @@ -1,6 +1,6 @@ { "name": "@altv/shared", - "version": "0.0.21", + "version": "0.0.22", "description": "This package contains the type definitions for the alt:V JS module v2 shared types", "types": "index.d.ts", "files": [ From fbb442d1312a010a9d2eb9afb4cb973e47358469 Mon Sep 17 00:00:00 2001 From: xLuxy <67131061+xLuxy@users.noreply.github.com> Date: Thu, 19 Sep 2024 15:32:22 +0200 Subject: [PATCH 08/15] feat: add js-module-v2 client command and add v8 version --- client/src/Main.cpp | 18 ++++++++++++++++++ server/src/Main.cpp | 5 +++-- shared/src/Event.cpp | 1 - shared/src/interfaces/IAltResource.h | 5 +++-- 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/client/src/Main.cpp b/client/src/Main.cpp index e7ed17093..79355b68b 100644 --- a/client/src/Main.cpp +++ b/client/src/Main.cpp @@ -13,6 +13,23 @@ #define JSV2_ENTRY_POINT CreateScriptRuntimeJSv2 #endif +static void ModuleCommand(const std::vector& args) +{ + if (args.empty()) + { + js::Logger::Colored("~y~Usage: ~w~js-module-v2 [options]"); + js::Logger::Colored("~y~Options:"); + js::Logger::Colored(" ~ly~--version ~w~- Version info"); + } + else if (args[0] == "--version") + { + js::Logger::Colored("~g~JS Module v2:"); + js::Logger::Colored("~ly~module:", MODULE_VERSION); + js::Logger::Colored("~ly~cpp-sdk:", ALT_SDK_VERSION); + js::Logger::Colored("~ly~v8:", std::to_string(V8_MAJOR_VERSION) + "." + std::to_string(V8_MINOR_VERSION) + "." + std::to_string(V8_BUILD_NUMBER)); + } +} + ALTV_JSV2_EXPORT alt::IScriptRuntime* JSV2_ENTRY_POINT(alt::ICore* core) { alt::ICore::SetInstance(core); @@ -20,6 +37,7 @@ ALTV_JSV2_EXPORT alt::IScriptRuntime* JSV2_ENTRY_POINT(alt::ICore* core) CJavaScriptRuntime& runtime = CJavaScriptRuntime::Instance(); if(!runtime.Initialize()) return nullptr; + core->SubscribeCommand("js-module-v2", ModuleCommand); core->SubscribeCommand("debughandles", js::DebugHandlesCommand); core->SubscribeCommand("dumpbinding", js::DumpBindingCommand); core->SubscribeCommand("dumpallbindings", js::DumpAllBindingsCommand); diff --git a/server/src/Main.cpp b/server/src/Main.cpp index 35f2de04e..ef8d6d559 100644 --- a/server/src/Main.cpp +++ b/server/src/Main.cpp @@ -10,18 +10,19 @@ static void ModuleCommand(const std::vector& args) { - if(args.size() == 0) + if (args.empty()) { js::Logger::Colored("~y~Usage: ~w~js-module-v2 [options]"); js::Logger::Colored("~y~Options:"); js::Logger::Colored(" ~ly~--version ~w~- Version info"); } - else if(args[0] == "--version") + else if (args[0] == "--version") { js::Logger::Colored("~g~JS Module v2:"); js::Logger::Colored("~ly~module:", MODULE_VERSION); js::Logger::Colored("~ly~cpp-sdk:", ALT_SDK_VERSION); js::Logger::Colored("~ly~nodejs:", std::to_string(NODE_MAJOR_VERSION) + "." + std::to_string(NODE_MINOR_VERSION) + "." + std::to_string(NODE_PATCH_VERSION)); + js::Logger::Colored("~ly~v8:", std::to_string(V8_MAJOR_VERSION) + "." + std::to_string(V8_MINOR_VERSION) + "." + std::to_string(V8_BUILD_NUMBER)); } } diff --git a/shared/src/Event.cpp b/shared/src/Event.cpp index 4700309c7..28c63567d 100644 --- a/shared/src/Event.cpp +++ b/shared/src/Event.cpp @@ -1,6 +1,5 @@ #include "Event.h" #include "interfaces/IResource.h" -#include "magic_enum/include/magic_enum.hpp" extern js::Class eventContextClass, cancellableEventContextClass; diff --git a/shared/src/interfaces/IAltResource.h b/shared/src/interfaces/IAltResource.h index 8c0885a4a..584dcda9a 100644 --- a/shared/src/interfaces/IAltResource.h +++ b/shared/src/interfaces/IAltResource.h @@ -73,9 +73,10 @@ namespace js if(context.IsEmpty()) return; IResource::Scope scope(this); - if (ev->GetType() == alt::CEvent::Type::RESOURCE_STOP) DestroyResourceObject(static_cast(ev)->GetResource()); - Event::SendEvent(ev, this); + + if (ev->GetType() == alt::CEvent::Type::RESOURCE_STOP) + DestroyResourceObject(static_cast(ev)->GetResource()); } void OnTick() override From 74c82a84410b74233f356bc6cd6e7b3676503047 Mon Sep 17 00:00:00 2001 From: xLuxy <67131061+xLuxy@users.noreply.github.com> Date: Fri, 20 Sep 2024 12:37:12 +0200 Subject: [PATCH 09/15] fix!(shared) Make neon property non-dynamic (see #208) --- server/js/compatibility/classes/player.js | 2 +- server/src/classes/Vehicle.cpp | 30 +++++++++++------------ shared/src/classes/SharedVehicle.cpp | 25 +++++++++---------- types/server/index.d.ts | 2 +- types/server/package.json | 2 +- 5 files changed, 28 insertions(+), 33 deletions(-) diff --git a/server/js/compatibility/classes/player.js b/server/js/compatibility/classes/player.js index 24778f1f8..2bc6c89aa 100644 --- a/server/js/compatibility/classes/player.js +++ b/server/js/compatibility/classes/player.js @@ -131,7 +131,7 @@ extendClassWithProperties( alt.Player, { whitelist: { - nonStatic: ["spawn"] + nonStatic: ["spawn", "setDlcClothes"] } }, Player, diff --git a/server/src/classes/Vehicle.cpp b/server/src/classes/Vehicle.cpp index 9b1cc9ce2..a85819f29 100644 --- a/server/src/classes/Vehicle.cpp +++ b/server/src/classes/Vehicle.cpp @@ -1,25 +1,22 @@ #include "Class.h" -static void NeonSetter(js::DynamicPropertySetterContext& ctx) +static void NeonSetter(js::PropertyContext& ctx) { - if(!ctx.CheckParent()) return; - alt::IVehicle* vehicle = ctx.GetParent(); - - bool val; - if(!ctx.GetValue(val)) return; + if (!ctx.CheckThis()) return; + alt::IVehicle* vehicle = ctx.GetThisObject(); bool left, right, front, back; vehicle->GetNeonActive(&left, &right, &front, &back); - std::string prop = ctx.GetProperty(); - if(prop == "left") left = val; - else if(prop == "right") - right = val; - else if(prop == "front") - front = val; - else if(prop == "back") - back = val; - vehicle->SetNeonActive(left, right, front, back); + js::Object prop; + if (!ctx.GetValue(prop, js::Type::OBJECT)) return; + + vehicle->SetNeonActive( + prop.Get("left", left), + prop.Get("right", right), + prop.Get("front", front), + prop.Get("back", back) + ); } static void SetNeonActive(js::FunctionContext& ctx) @@ -116,7 +113,8 @@ extern js::Class vehicleClass("Vehicle", &sharedVehicleClass, nullptr, [](js::Cl { tpl.BindToType(alt::IBaseObject::Type::VEHICLE); - tpl.DynamicProperty("neon", nullptr, &NeonSetter, nullptr, nullptr); + tpl.Property("neon", nullptr, &NeonSetter); + tpl.Method("setNeonActive", &SetNeonActive); tpl.Property("modKit", &ModKitGetter, &ModKitSetter); diff --git a/shared/src/classes/SharedVehicle.cpp b/shared/src/classes/SharedVehicle.cpp index 868a95916..8bee89dd8 100644 --- a/shared/src/classes/SharedVehicle.cpp +++ b/shared/src/classes/SharedVehicle.cpp @@ -1,23 +1,20 @@ #include "Class.h" -static void NeonGetter(js::DynamicPropertyGetterContext& ctx) +static void NeonGetter(js::PropertyContext& ctx) { - if(!ctx.CheckParent()) return; - alt::IVehicle* vehicle = ctx.GetParent(); + if (!ctx.CheckThis()) return; + alt::IVehicle* vehicle = ctx.GetThisObject(); bool left, right, front, back; vehicle->GetNeonActive(&left, &right, &front, &back); - bool val = false; - std::string prop = ctx.GetProperty(); - if(prop == "left") val = left; - else if(prop == "right") - val = right; - else if(prop == "front") - val = front; - else if(prop == "back") - val = back; - ctx.Return(val); + js::Object neonState; + neonState.Set("left", left); + neonState.Set("right", right); + neonState.Set("front", front); + neonState.Set("back", back); + + ctx.Return(neonState); } static void GetNeonActive(js::FunctionContext& ctx) @@ -52,7 +49,7 @@ static void NeonEnumerator(js::DynamicPropertyEnumeratorContext& ctx) extern js::Class entityClass; extern js::Class sharedVehicleClass("SharedVehicle", &entityClass, nullptr, [](js::ClassTemplate& tpl) { - tpl.DynamicProperty("neon", &NeonGetter, nullptr, nullptr, &NeonEnumerator); + tpl.Property("neon", &NeonGetter, nullptr); tpl.Method("getNeonActive", &GetNeonActive); tpl.Property<&alt::IVehicle::GetDriver>("driver"); diff --git a/types/server/index.d.ts b/types/server/index.d.ts index e26b17837..abd6bd9a6 100644 --- a/types/server/index.d.ts +++ b/types/server/index.d.ts @@ -613,7 +613,7 @@ declare module "@altv/server" { } export abstract class Vehicle extends Entity { - readonly neon: altShared.VehicleNeonState; + neon: altShared.VehicleNeonState; readonly driver?: Player; readonly isDestroyed: boolean; readonly modKitsCount: number; diff --git a/types/server/package.json b/types/server/package.json index c6a6c7df7..addbc5ed1 100644 --- a/types/server/package.json +++ b/types/server/package.json @@ -1,6 +1,6 @@ { "name": "@altv/server", - "version": "0.0.46", + "version": "0.0.47", "description": "This package contains the type definitions for the alt:V JS module v2 server types", "types": "index.d.ts", "files": [ From f52687d267db9d65b28c5efdc4833ca1c67404ac Mon Sep 17 00:00:00 2001 From: xLuxy <67131061+xLuxy@users.noreply.github.com> Date: Fri, 20 Sep 2024 13:15:30 +0200 Subject: [PATCH 10/15] fix(shared, compat): Expose all enums --- shared/js/compatibility/enums.js | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 shared/js/compatibility/enums.js diff --git a/shared/js/compatibility/enums.js b/shared/js/compatibility/enums.js new file mode 100644 index 000000000..ccba12749 --- /dev/null +++ b/shared/js/compatibility/enums.js @@ -0,0 +1,8 @@ +/// +/// +/// +// import * as alt from "@altv/shared"; + +for (const enumName in alt.Enums) { + cppBindings.registerCompatibilityExport(enumName, alt.Enums[enumName]); +} From df3923fa57c054cc6cbb6b8907853c8f32a2b1f9 Mon Sep 17 00:00:00 2001 From: xLuxy <67131061+xLuxy@users.noreply.github.com> Date: Fri, 20 Sep 2024 23:32:12 +0200 Subject: [PATCH 11/15] chore(client, typings): Add missing once event typings for resourceStart / resourceStop --- types/client/index.d.ts | 2 ++ types/client/package.json | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/types/client/index.d.ts b/types/client/index.d.ts index 943739166..fb642102b 100644 --- a/types/client/index.d.ts +++ b/types/client/index.d.ts @@ -1855,7 +1855,9 @@ declare module "@altv/client" { // SHARED resource events export function onResourceStart(callback: GenericEventCallback): altShared.Events.EventHandler; + export function onceResourceStart(callback: GenericEventCallback): altShared.Events.EventHandler; export function onResourceStop(callback: GenericEventCallback): altShared.Events.EventHandler; + export function onceResourceStop(callback: GenericEventCallback): altShared.Events.EventHandler; export function onResourceError(callback: GenericEventCallback): altShared.Events.EventHandler; // Custom events diff --git a/types/client/package.json b/types/client/package.json index dd23873d6..158d7e3fa 100644 --- a/types/client/package.json +++ b/types/client/package.json @@ -1,6 +1,6 @@ { "name": "@altv/client", - "version": "0.0.45", + "version": "0.0.46", "description": "This package contains the type definitions for the alt:V JS module v2 client types", "types": "index.d.ts", "files": [ From ec85d9b215f76b8b6fa489359b36a2d3c2134fa7 Mon Sep 17 00:00:00 2001 From: xLuxy <67131061+xLuxy@users.noreply.github.com> Date: Sat, 21 Sep 2024 12:38:57 +0200 Subject: [PATCH 12/15] feat(shared): Add alt.Timers.isValid static method --- shared/js/timers.js | 12 ++++++++++++ types/shared/index.d.ts | 1 + types/shared/package.json | 2 +- 3 files changed, 14 insertions(+), 1 deletion(-) diff --git a/shared/js/timers.js b/shared/js/timers.js index 32e6fb791..9efefc785 100644 --- a/shared/js/timers.js +++ b/shared/js/timers.js @@ -66,6 +66,17 @@ class Timer { return timers.get(id) || null; } + /** + * + * @param {number | Timer} idOrHandle + */ + static isValid(idOrHandle) { + if (!idOrHandle) return false; + + const id = idOrHandle instanceof Timer ? idOrHandle.id : idOrHandle; + return timers.has(id); + } + constructor(type, callback, interval, once, args) { assertIsType(type, "number", "Expected a number as first argument"); assertIsType(callback, "function", "Expected a function as second argument"); @@ -171,6 +182,7 @@ alt.Timers.EveryTick = EveryTick; alt.Timers.NextTick = NextTick; alt.Timers.getByID = Timer.getByID; +alt.Timers.isValid = Timer.isValid; alt.Timers.setInterval = (callback, interval, ...args) => new Interval(callback, interval, ...args); alt.Timers.setTimeout = (callback, timeout, ...args) => new Timeout(callback, timeout, ...args); diff --git a/types/shared/index.d.ts b/types/shared/index.d.ts index 75d696428..cf0b639aa 100644 --- a/types/shared/index.d.ts +++ b/types/shared/index.d.ts @@ -649,6 +649,7 @@ declare module "@altv/shared" { export function timeEnd(name?: string): void; export function getByID(id: number): Timer | null; + export function isValid(idOrHandle?: number | Timer): boolean; } // DO NOT TOUCH THIS - This is only here so client / server can extend Utils namespace using merging diff --git a/types/shared/package.json b/types/shared/package.json index 7bb0a7963..aefe9daaa 100644 --- a/types/shared/package.json +++ b/types/shared/package.json @@ -1,6 +1,6 @@ { "name": "@altv/shared", - "version": "0.0.22", + "version": "0.0.23", "description": "This package contains the type definitions for the alt:V JS module v2 shared types", "types": "index.d.ts", "files": [ From 6ebfa0862d406833a8af9bf7666243421260cee4 Mon Sep 17 00:00:00 2001 From: xLuxy <67131061+xLuxy@users.noreply.github.com> Date: Sat, 21 Sep 2024 13:01:55 +0200 Subject: [PATCH 13/15] chore(shared): Make Timer.once always return a boolean --- shared/js/timers.js | 2 ++ types/shared/index.d.ts | 2 +- types/shared/package.json | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/shared/js/timers.js b/shared/js/timers.js index 9efefc785..47be07887 100644 --- a/shared/js/timers.js +++ b/shared/js/timers.js @@ -38,6 +38,7 @@ class Timer { lastTick; /** @type {boolean} */ once; + /** @type {{ fileName: string, lineNumber: number }} */ location; @@ -81,6 +82,7 @@ class Timer { assertIsType(type, "number", "Expected a number as first argument"); assertIsType(callback, "function", "Expected a function as second argument"); assertIsType(interval, "number", "Expected a number as third argument"); + assertIsType(once, "boolean", "Expected a boolean as fourth argument"); this.interval = interval; this.callback = callback.bind(this, ...(Array.isArray(args) ? args : [])); diff --git a/types/shared/index.d.ts b/types/shared/index.d.ts index cf0b639aa..305677c95 100644 --- a/types/shared/index.d.ts +++ b/types/shared/index.d.ts @@ -3468,7 +3468,7 @@ declare abstract class Timer { public interval: number; public callback: Function; public lastTick: number; - public once?: boolean; + public once: boolean; public location: import("@altv/shared").SourceLocation; public get type(): import("@altv/shared").Enums.TimerType; diff --git a/types/shared/package.json b/types/shared/package.json index aefe9daaa..83a6fa752 100644 --- a/types/shared/package.json +++ b/types/shared/package.json @@ -1,6 +1,6 @@ { "name": "@altv/shared", - "version": "0.0.23", + "version": "0.0.24", "description": "This package contains the type definitions for the alt:V JS module v2 shared types", "types": "index.d.ts", "files": [ From b7955748e41536b91d56fe7b181d957c8a9949dd Mon Sep 17 00:00:00 2001 From: xLuxy <67131061+xLuxy@users.noreply.github.com> Date: Sun, 22 Sep 2024 17:31:14 +0200 Subject: [PATCH 14/15] chore(shared, typings): Add missing factory typings --- types/client/index.d.ts | 3 +++ types/client/package.json | 2 +- types/server/index.d.ts | 3 +++ types/server/package.json | 2 +- 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/types/client/index.d.ts b/types/client/index.d.ts index fb642102b..6c5d40efa 100644 --- a/types/client/index.d.ts +++ b/types/client/index.d.ts @@ -576,6 +576,9 @@ declare module "@altv/client" { static create(): HttpClient; static getByID(id: number): HttpClient | null; + + static setFactory(factory: typeof HttpClient): void; + static getFactory(): T; } export abstract class Object extends Entity { diff --git a/types/client/package.json b/types/client/package.json index 158d7e3fa..fa8aeac31 100644 --- a/types/client/package.json +++ b/types/client/package.json @@ -1,6 +1,6 @@ { "name": "@altv/client", - "version": "0.0.46", + "version": "0.0.47", "description": "This package contains the type definitions for the alt:V JS module v2 client types", "types": "index.d.ts", "files": [ diff --git a/types/server/index.d.ts b/types/server/index.d.ts index abd6bd9a6..b802dd015 100644 --- a/types/server/index.d.ts +++ b/types/server/index.d.ts @@ -1036,6 +1036,9 @@ declare module "@altv/server" { // static readonly all: ReadonlyArray; static getByID(id: number): ConnectionInfo | undefined; + + static setFactory(factory: typeof ConnectionInfo): void; + static getFactory(): T; } export namespace Events { diff --git a/types/server/package.json b/types/server/package.json index addbc5ed1..6a858d8d0 100644 --- a/types/server/package.json +++ b/types/server/package.json @@ -1,6 +1,6 @@ { "name": "@altv/server", - "version": "0.0.47", + "version": "0.0.48", "description": "This package contains the type definitions for the alt:V JS module v2 server types", "types": "index.d.ts", "files": [ From fd1ed73babeb985914efed01c9d83b1950a7f3ba Mon Sep 17 00:00:00 2001 From: xLuxy <67131061+xLuxy@users.noreply.github.com> Date: Sun, 22 Sep 2024 22:13:23 +0200 Subject: [PATCH 15/15] chore(shared): Remove [JS] prefix in favor of core prefixes --- client/src/CJavaScriptResource.cpp | 12 ++++++------ client/src/CJavaScriptRuntime.cpp | 8 ++++---- client/src/helpers/IExceptionHandler.cpp | 14 +++++++------- client/src/helpers/IModuleHandler.cpp | 2 +- client/src/helpers/NativeInvoker.cpp | 6 +++--- server/src/CNodeResource.cpp | 2 +- shared/js/compatibility/utils/classes.js | 10 +++++----- shared/js/events.js | 12 ++++++------ shared/js/logging.js | 4 ++-- shared/js/timers.js | 4 ++-- shared/src/Bindings.cpp | 10 +++++----- shared/src/helpers/JS.cpp | 10 ++++++---- 12 files changed, 48 insertions(+), 46 deletions(-) diff --git a/client/src/CJavaScriptResource.cpp b/client/src/CJavaScriptResource.cpp index a5ceeec56..bf000ed09 100644 --- a/client/src/CJavaScriptResource.cpp +++ b/client/src/CJavaScriptResource.cpp @@ -16,7 +16,7 @@ v8::Local CJavaScriptResource::CompileAndRun(const std::string& path if(maybeMod.IsEmpty()) { - js::Logger::Error("[JS] Failed to compile file", path); + js::Logger::Error("Failed to compile file", path); tryCatch.Check(true, true); return v8::Local(); } @@ -26,11 +26,11 @@ v8::Local CJavaScriptResource::CompileAndRun(const std::string& path if(!InstantiateModule(GetContext(), mod) || tryCatch.HasCaught()) { - js::Logger::Error("[JS] Failed to instantiate file", path); + js::Logger::Error("Failed to instantiate file", path); if(mod->GetStatus() == v8::Module::kErrored) { js::Object exceptionObj = mod->GetException().As(); - js::Logger::Error("[JS]", exceptionObj.Get("message")); + js::Logger::Error(exceptionObj.Get("message")); std::string stack = exceptionObj.Get("stack"); if(!stack.empty()) js::Logger::Error(stack); } @@ -40,11 +40,11 @@ v8::Local CJavaScriptResource::CompileAndRun(const std::string& path v8::MaybeLocal maybeResult = EvaluateModule(GetContext(), mod); if(maybeResult.IsEmpty() || maybeResult.ToLocalChecked().As()->State() == v8::Promise::PromiseState::kRejected) { - js::Logger::Error("[JS] Failed to start file", path); + js::Logger::Error("Failed to start file", path); if(mod->GetStatus() == v8::Module::kErrored) { js::Object exceptionObj = mod->GetException().As(); - js::Logger::Error("[JS]", exceptionObj.Get("message")); + js::Logger::Error(exceptionObj.Get("message")); std::string stack = exceptionObj.Get("stack"); if(!stack.empty()) js::Logger::Error(stack); } @@ -106,7 +106,7 @@ bool CJavaScriptResource::Start() if (IsCompatibilityModeEnabled()) { auto resourceName = resource->GetName(); - js::Logger::Colored << "~y~[JS] Compatibility mode is enabled for resource " << resourceName << js::Logger::Endl; + js::Logger::Colored << "~y~Compatibility mode is enabled for resource " << resourceName << js::Logger::Endl; } return true; diff --git a/client/src/CJavaScriptRuntime.cpp b/client/src/CJavaScriptRuntime.cpp index 5d718cc4e..3b259c59e 100644 --- a/client/src/CJavaScriptRuntime.cpp +++ b/client/src/CJavaScriptRuntime.cpp @@ -4,18 +4,18 @@ void CJavaScriptRuntime::OnFatalError(const char* location, const char* message) { - js::Logger::Error("[JS] V8 fatal error!", location, message); + js::Logger::Error("V8 fatal error!", location, message); } void CJavaScriptRuntime::OnHeapOOM(const char* location, bool isHeap) { if(!isHeap) return; - js::Logger::Error("[JS] V8 heap out of memory!", location); + js::Logger::Error("V8 heap out of memory!", location); } size_t CJavaScriptRuntime::OnNearHeapLimit(void*, size_t current, size_t initial) { - js::Logger::Warn("[JS] The remaining V8 heap space is approaching critical levels. Increasing heap limit..."); + js::Logger::Warn("The remaining V8 heap space is approaching critical levels. Increasing heap limit..."); // Increase the heap limit by 100MB if the heap limit has not exceeded 4GB uint64_t currentLimitMb = (current / 1024) / 1024; @@ -103,7 +103,7 @@ void CJavaScriptRuntime::InitializeImportMetaObject(v8::Local conte void CJavaScriptRuntime::MessageListener(v8::Local message, v8::Local error) { - js::Logger::Warn("[JS] V8 message received!", js::CppValue(message->Get())); + js::Logger::Warn("V8 message received!", js::CppValue(message->Get())); } void CJavaScriptRuntime::SetupIsolateHandlers() diff --git a/client/src/helpers/IExceptionHandler.cpp b/client/src/helpers/IExceptionHandler.cpp index 8a6b683d2..1abd5fe51 100644 --- a/client/src/helpers/IExceptionHandler.cpp +++ b/client/src/helpers/IExceptionHandler.cpp @@ -27,8 +27,8 @@ void IExceptionHandler::OnPromiseRejectAfterResolve(v8::PromiseRejectMessage& me v8::Isolate* isolate = resource->GetIsolate(); std::string rejectionMsg = *v8::String::Utf8Value(isolate, message.GetValue()->ToString(resource->GetContext()).ToLocalChecked()); - js::Logger::Error("[JS] Promise rejected after already being resolved in resource '" + resourceName + "'"); - if(!rejectionMsg.empty()) js::Logger::Error("[JS]", rejectionMsg); + js::Logger::Error("Promise rejected after already being resolved in resource '" + resourceName + "'"); + if(!rejectionMsg.empty()) js::Logger::Error(rejectionMsg); } void IExceptionHandler::OnPromiseResolveAfterResolve(v8::PromiseRejectMessage& message) @@ -38,8 +38,8 @@ void IExceptionHandler::OnPromiseResolveAfterResolve(v8::PromiseRejectMessage& m v8::Isolate* isolate = resource->GetIsolate(); std::string rejectionMsg = *v8::String::Utf8Value(isolate, message.GetValue()->ToString(resource->GetContext()).ToLocalChecked()); - js::Logger::Error("[JS] Promise resolved after already being resolved in resource '" + resourceName + "'"); - if(!rejectionMsg.empty()) js::Logger::Error("[JS]", rejectionMsg); + js::Logger::Error("Promise resolved after already being resolved in resource '" + resourceName + "'"); + if(!rejectionMsg.empty()) js::Logger::Error(rejectionMsg); } void IExceptionHandler::ProcessExceptions() @@ -51,9 +51,9 @@ void IExceptionHandler::ProcessExceptions() for(PromiseRejection& rejection : promiseRejections) { std::string rejectionMsg = *v8::String::Utf8Value(isolate, rejection.value.Get(isolate)->ToString(resource->GetContext()).ToLocalChecked()); - js::Logger::Error("[JS] Unhandled promise rejection in resource '" + resourceName + "' in file '" + rejection.location.file + "' at line " + std::to_string(rejection.location.line)); - if(!rejectionMsg.empty()) js::Logger::Error("[JS]", rejectionMsg); - if(!rejection.stackTrace.IsEmpty()) js::Logger::Error("[JS]", rejection.stackTrace.ToString()); + js::Logger::Error("Unhandled promise rejection in resource '" + resourceName + "' in file '" + rejection.location.file + "' at line " + std::to_string(rejection.location.line)); + if(!rejectionMsg.empty()) js::Logger::Error(rejectionMsg); + if(!rejection.stackTrace.IsEmpty()) js::Logger::Error(rejection.stackTrace.ToString()); } promiseRejections.clear(); } diff --git a/client/src/helpers/IModuleHandler.cpp b/client/src/helpers/IModuleHandler.cpp index 96ffc5c19..b7eac0a8c 100644 --- a/client/src/helpers/IModuleHandler.cpp +++ b/client/src/helpers/IModuleHandler.cpp @@ -235,7 +235,7 @@ v8::MaybeLocal IModuleHandler::CompileBytecode(const std::string& na v8::MaybeLocal module = v8::ScriptCompiler::CompileModule(isolate, &source, v8::ScriptCompiler::kConsumeCodeCache); if(cachedData->rejected) { - js::Logger::Error("[JS] Trying to load invalid bytecode"); + js::Logger::Error("Trying to load invalid bytecode"); return v8::MaybeLocal(); } return module; diff --git a/client/src/helpers/NativeInvoker.cpp b/client/src/helpers/NativeInvoker.cpp index 23d67fba7..0f4b3b962 100644 --- a/client/src/helpers/NativeInvoker.cpp +++ b/client/src/helpers/NativeInvoker.cpp @@ -89,7 +89,7 @@ bool js::NativeInvoker::PushArgs(js::FunctionContext& ctx, alt::INative* native) } default: { - Logger::Warn("[JS] Unknown native argument type", magic_enum::enum_name(nativeArgs[i]), "for native", native->GetName(), "at index", i); + Logger::Warn("Unknown native argument type", magic_enum::enum_name(nativeArgs[i]), "for native", native->GetName(), "at index", i); break; } } @@ -115,7 +115,7 @@ v8::Local js::NativeInvoker::GetPointerReturnValue(alt::INative::Type return resource->CreateVector3({ vector->x, vector->y, vector->z }); } } - // js::Logger::Warn("[JS] Unknown native pointer return type:", magic_enum::enum_name(type), (int)type); + // js::Logger::Warn("Unknown native pointer return type:", magic_enum::enum_name(type), (int)type); return v8::Undefined(resource->GetIsolate()); } @@ -137,7 +137,7 @@ v8::Local js::NativeInvoker::GetReturnValue() case Type::ARG_STRING: return js::JSValue(nativeContext->ResultString()); case Type::ARG_VOID: return v8::Undefined(resource->GetIsolate()); } - js::Logger::Warn("[JS] Unknown native return type:", magic_enum::enum_name(native->GetRetnType()), (int)native->GetRetnType()); + js::Logger::Warn("Unknown native return type:", magic_enum::enum_name(native->GetRetnType()), (int)native->GetRetnType()); return v8::Undefined(resource->GetIsolate()); } diff --git a/server/src/CNodeResource.cpp b/server/src/CNodeResource.cpp index 06293691b..767b614c4 100644 --- a/server/src/CNodeResource.cpp +++ b/server/src/CNodeResource.cpp @@ -84,7 +84,7 @@ bool CNodeResource::Start() if (IsCompatibilityModeEnabled()) { auto resourceName = resource->GetName(); - js::Logger::Colored << "~y~[JS] Compatibility mode is enabled for resource " << resourceName << js::Logger::Endl; + js::Logger::Colored << "~y~Compatibility mode is enabled for resource " << resourceName << js::Logger::Endl; } return true; diff --git a/shared/js/compatibility/utils/classes.js b/shared/js/compatibility/utils/classes.js index f2042c117..97aded690 100644 --- a/shared/js/compatibility/utils/classes.js +++ b/shared/js/compatibility/utils/classes.js @@ -37,7 +37,7 @@ function applyNonStaticProperties(baseClass, cls, options) { ["get", "set", "value"].forEach((key) => { if (key in newDescriptor && (!mergedDescriptor[key] || isWhitelisted)) { if (options.verbose) { - alt.log(`~ly~[JS] ~lr~Merged ${key} for ${prop} from ${prot.constructor.name} to ${baseClass.name}`); + alt.log(`~lr~Merged ${key} for ${prop} from ${prot.constructor.name} to ${baseClass.name}`); } mergedDescriptor[key] = newDescriptor[key]; } @@ -50,7 +50,7 @@ function applyNonStaticProperties(baseClass, cls, options) { if (options.verbose) { const action = baseDescriptor ? "Merged" : "Applied"; - alt.log(`~ly~[JS] ~lb~${action} non-static property ${prop} from ${prot.constructor.name} to ${baseClass.name}`); + alt.log(`~lb~${action} non-static property ${prop} from ${prot.constructor.name} to ${baseClass.name}`); } } } @@ -67,7 +67,7 @@ function applyStaticProperties(baseClass, cls, options) { if (doesPropertyExist && !canBeOverriden) { if (options.verbose) { const reason = !canBeOverriden ? "blacklisted" : "already exists"; - alt.log(`~ly~[JS] ~lb~Skipping static property ${propKey} in ${cls.name}: ${reason}`); + alt.log(`~lb~Skipping static property ${propKey} in ${cls.name}: ${reason}`); } continue; @@ -82,7 +82,7 @@ function applyStaticProperties(baseClass, cls, options) { Object.defineProperty(baseClass, propKey, descriptor); if (options.verbose) { - alt.log(`~ly~[JS] ~lb~Applied static property ${propKey} in ${cls.name} to ${baseClass.name}`); + alt.log(`~lb~Applied static property ${propKey} in ${cls.name} to ${baseClass.name}`); } } } @@ -132,7 +132,7 @@ export function overrideLazyProperty(instance, propertyName, value) { const descriptor = Object.getOwnPropertyDescriptor(instance, propertyName); if (!descriptor) { - alt.log(`~ly~[JS] ~lr~Lazy Property ${propertyName} does not exist in ${instance.constructor.name} to override property`); + alt.log(`~lr~Lazy Property ${propertyName} does not exist in ${instance.constructor.name} to override property`); return; } diff --git a/shared/js/events.js b/shared/js/events.js index 4bf80915d..4a6538721 100644 --- a/shared/js/events.js +++ b/shared/js/events.js @@ -112,12 +112,12 @@ export class Event { const duration = alt.getNetTime() - startTime; if (duration > Event.#warningThreshold) { - alt.logWarning(`[JS] Event handler in resource '${cppBindings.resourceName}' (${location.fileName}:${location.lineNumber}) for script event '${name}' took ${duration}ms to execute (Threshold: ${Event.#warningThreshold}ms)`); + alt.logWarning(`Event handler in resource '${cppBindings.resourceName}' (${location.fileName}:${location.lineNumber}) for script event '${name}' took ${duration}ms to execute (Threshold: ${Event.#warningThreshold}ms)`); } if (onlyOnce) eventHandler.destroy(); } catch (e) { - alt.logError(`[JS] Exception caught while invoking script event '${name}' handler`); + alt.logError(`Exception caught while invoking script event '${name}' handler`); alt.logError(e); Event.invoke(alt.Enums.CustomEventType.ERROR, { error: e, location, stack: e.stack }, true); @@ -218,10 +218,10 @@ export class Event { const duration = alt.getNetTime() - startTime; if (duration > Event.#warningThreshold) { - alt.logWarning(`[JS] Generic event handler in resource '${cppBindings.resourceName}' (${location.fileName}:${location.lineNumber}) for event '${Event.getEventName(eventType, custom)}' took ${duration}ms to execute (Threshold: ${Event.#warningThreshold}ms)`); + alt.logWarning(`Generic event handler in resource '${cppBindings.resourceName}' (${location.fileName}:${location.lineNumber}) for event '${Event.getEventName(eventType, custom)}' took ${duration}ms to execute (Threshold: ${Event.#warningThreshold}ms)`); } } catch (e) { - alt.logError(`[JS] Exception caught while invoking generic event handler`); + alt.logError(`Exception caught while invoking generic event handler`); alt.logError(e); Event.invoke(alt.Enums.CustomEventType.ERROR, { error: e, location, stack: e.stack }, true); @@ -292,14 +292,14 @@ export class Event { const duration = alt.getNetTime() - startTime; if (duration > Event.#warningThreshold) { - alt.logWarning(`[JS] Event handler in resource '${cppBindings.resourceName}' (${location.fileName}:${location.lineNumber}) for event '${Event.getEventName(eventType, custom)}' took ${duration}ms to execute (Threshold: ${Event.#warningThreshold}ms)`); + alt.logWarning(`Event handler in resource '${cppBindings.resourceName}' (${location.fileName}:${location.lineNumber}) for event '${Event.getEventName(eventType, custom)}' took ${duration}ms to execute (Threshold: ${Event.#warningThreshold}ms)`); } if (onlyOnce) { eventHandler.destroy(); } } catch (e) { - alt.logError(`[JS] Exception caught while invoking event handler`); + alt.logError(`Exception caught while invoking event handler`); alt.logError(e); Event.invoke(alt.Enums.CustomEventType.ERROR, { error: e, location, stack: e.stack }, true); diff --git a/shared/js/logging.js b/shared/js/logging.js index 7f7c95e59..c4961f232 100644 --- a/shared/js/logging.js +++ b/shared/js/logging.js @@ -2827,7 +2827,7 @@ function timeLog(label) { } const duration = alt.getNetTime() - startTime; - alt.log(`[JS] ${label ?? "Timer"}: ${duration}ms`); + alt.log(`${label ?? "Timer"}: ${duration}ms`); } function timeEnd(label) { const startTime = timeLabelMap.get(label ?? "Timer"); @@ -2836,7 +2836,7 @@ function timeEnd(label) { } const duration = alt.getNetTime() - startTime; - alt.log(`[JS] ${label ?? "Timer"}: ${duration}ms`); + alt.log(`${label ?? "Timer"}: ${duration}ms`); timeLabelMap.delete(label ?? "Timer"); } diff --git a/shared/js/timers.js b/shared/js/timers.js index 47be07887..bd9a8a0aa 100644 --- a/shared/js/timers.js +++ b/shared/js/timers.js @@ -104,7 +104,7 @@ class Timer { try { this.callback(); } catch (e) { - alt.logError(`[JS] Exception caught while invoking timer callback`); + alt.logError(`Exception caught while invoking timer callback`); alt.logError(e); Event.invoke(alt.Enums.CustomEventType.ERROR, { error: e, location: this.location, stack: e.stack }, true); @@ -113,7 +113,7 @@ class Timer { const duration = this.lastTick - now; if (duration > Timer.#_warningThreshold) { - alt.logWarning(`[JS] Timer callback in resource '${cppBindings.resourceName}' (${this.location.fileName}:${this.location.lineNumber}) took ${duration}ms to execute (Threshold: ${Timer.#_warningThreshold}ms)`); + alt.logWarning(`Timer callback in resource '${cppBindings.resourceName}' (${this.location.fileName}:${this.location.lineNumber}) took ${duration}ms to execute (Threshold: ${Timer.#_warningThreshold}ms)`); } if (this.once) this.destroy(); diff --git a/shared/src/Bindings.cpp b/shared/src/Bindings.cpp index f2ce29641..b414633ab 100644 --- a/shared/src/Bindings.cpp +++ b/shared/src/Bindings.cpp @@ -59,15 +59,15 @@ void js::Binding::CleanupForResource(IResource* resource) void js::Binding::Dump() { - Logger::Warn("[JS] Binding:", GetName()); - Logger::Warn("[JS] Valid:", IsValid()); - Logger::Warn("[JS] Scope:", magic_enum::enum_name(GetScope())); - Logger::Warn("[JS] Source size:", strlen(GetSource())); + Logger::Warn("Binding:", GetName()); + Logger::Warn(" Valid:", IsValid()); + Logger::Warn(" Scope:", magic_enum::enum_name(GetScope())); + Logger::Warn(" Source size:", strlen(GetSource())); Logger::Warn(GetSource()); } void js::Binding::DumpAll() { - Logger::Warn("[JS] Bindings count:", __bindings.size()); + Logger::Warn("Bindings count:", __bindings.size()); for(auto& [name, binding] : __bindings) binding.Dump(); } diff --git a/shared/src/helpers/JS.cpp b/shared/src/helpers/JS.cpp index cedb288a2..446c975aa 100644 --- a/shared/src/helpers/JS.cpp +++ b/shared/src/helpers/JS.cpp @@ -120,13 +120,15 @@ void js::TryCatch::PrintError(bool skipLocation) std::string stack = stackTrace.IsEmpty() ? "" : *v8::String::Utf8Value(isolate, stackTrace.ToLocalChecked()); std::string exceptionStr = *v8::String::Utf8Value(isolate, exception); - if(!skipLocation) Logger::Error("[JS] Exception caught in resource '" + resource->GetName() + "' in file '" + file + "' at line " + lineStr); + if(!skipLocation) Logger::Error("Exception caught in resource '" + resource->GetName() + "' in file '" + file + "' at line " + lineStr); if(!exceptionStr.empty() && stack.empty()) { - Logger::Error("[JS]", exceptionStr); - Logger::Error("[JS] ", sourceLine); + Logger::Error(exceptionStr); + Logger::Error(" ", sourceLine); } - if(!stack.empty()) Logger::Error("[JS]", stack); + + if(!stack.empty()) + Logger::Error(stack); js::Event::EventArgs args; args.Set("error", exception);