Skip to content

Commit

Permalink
Merge branch 'dev' into rc
Browse files Browse the repository at this point in the history
  • Loading branch information
C0kkie committed Jul 29, 2024
2 parents cf28e26 + 6a728f8 commit 426e67e
Show file tree
Hide file tree
Showing 11 changed files with 302 additions and 4 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Generated
*.gen
shared/JSBindings.h
shared/JSEnums.h

node_modules/
3 changes: 3 additions & 0 deletions client/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ include(FetchContent)
include(cmake/DepsDownload.cmake)
set(BINDINGS_SCOPE "CLIENT")
include(../shared/cmake/GenerateBindings.cmake)
include(../shared/cmake/GenerateEnums.cmake)

project(altv-client-js)

Expand Down Expand Up @@ -112,6 +113,7 @@ if(DYNAMIC_BUILD EQUAL 1)
)

add_dependencies(${PROJECT_NAME} ${SDK_PROJECT_NAME} js-bindings)
add_dependencies(${PROJECT_NAME} ${SDK_PROJECT_NAME} js-enums)
else()
## STATIC
add_library(
Expand All @@ -130,6 +132,7 @@ else()
)

add_dependencies(${PROJECT_NAME}-static js-bindings)
add_dependencies(${PROJECT_NAME}-static js-enums)
endif()

if(ALTV_JS_DEINIT_CPPSDK)
Expand Down
2 changes: 2 additions & 0 deletions server/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ include(../shared/deps/cpp-sdk/CMakeLists.txt)
include(cmake/DepsDownload.cmake)
set(BINDINGS_SCOPE "SERVER")
include(../shared/cmake/GenerateBindings.cmake)
include(../shared/cmake/GenerateEnums.cmake)

project(js-module)

Expand Down Expand Up @@ -145,6 +146,7 @@ add_library(
)

add_dependencies(${PROJECT_NAME} alt-sdk js-bindings)
add_dependencies(${PROJECT_NAME} alt-sdk js-enums)

if(MSVC AND WIN32)
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /DEBUG")
Expand Down
14 changes: 12 additions & 2 deletions server/src/CNodeResourceImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ bool CNodeResourceImpl::Start()
std::vector<std::string> args{ resource->GetName() };
std::vector<std::string> execArgs{ };

env = node::CreateEnvironment(nodeData, _context, args, execArgs, flags, threadId, std::move(inspector));
env = node::CreateEnvironment(nodeData, _context, args, execArgs, flags, threadId, std::move(inspector));
node::LoadEnvironment(env, bootstrap_code);

// Not sure it's needed anymore
Expand Down Expand Up @@ -171,7 +171,17 @@ void CNodeResourceImpl::OnEvent(const alt::CEvent* e)
auto ev = static_cast<const alt::CPlayerDisconnectEvent*>(e);
auto player = ev->GetTarget();

remoteRPCHandlers.erase(player);
if (remoteRPCHandlers[player].size() > 0)
{
for (const auto rpcHandler : remoteRPCHandlers[player])
{
const auto promise = rpcHandler.PromiseResolver.Get(GetIsolate());
if (promise->IsPromise())
promise->Reject(GetContext(), V8Helpers::JSValue("Player disconnected"));
}

remoteRPCHandlers.erase(player);
}

for (auto it = awaitableRPCHandlers.rbegin(); it != awaitableRPCHandlers.rend(); ++it)
{
Expand Down
2 changes: 1 addition & 1 deletion shared/V8ResourceImpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ class V8ResourceImpl : public alt::IResource::Impl
template<class T>
v8::Local<v8::Value> GetBaseObjectOrNull(const T*& handle)
{
return GetBaseObjectOrNull(handle.Get());
return GetBaseObjectOrNull(handle->Get());
}

v8::Local<v8::Value> CreateVector3(alt::Vector3f vec);
Expand Down
52 changes: 52 additions & 0 deletions shared/bindings/BindingsMain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "../V8Helpers.h"
#include "../V8ResourceImpl.h"
#include "../V8Module.h"
#include "JSEnums.h"

static void HashCb(const v8::FunctionCallbackInfo<v8::Value>& info)
{
Expand Down Expand Up @@ -465,6 +466,55 @@ static void GetNetTime(const v8::FunctionCallbackInfo<v8::Value>& info)
V8_RETURN_UINT(netTime);
}

// Enums module doesn't need to import any modules
static v8::MaybeLocal<v8::Module> HandleEnumsModuleImport(v8::Local<v8::Context> context, v8::Local<v8::String> specifier, v8::Local<v8::FixedArray>, v8::Local<v8::Module> referrer) {
v8::MaybeLocal<v8::Module> maybeModule;
Log::Error << "Enums module must not import anything" << Log::Endl;
return maybeModule;
}

static void AddEnumsToSharedModuleExports(v8::Isolate* isolate, v8::Local<v8::Context> ctx, v8::Local<v8::Object> exports) {
v8::Local<v8::String> sourceCode = V8Helpers::JSValue(JSEnums::GetBindingsCode());

v8::ScriptOrigin scriptOrigin(isolate, V8Helpers::JSValue("js-enums"), 0, 0, false, -1, v8::Local<v8::Value>(), false, false, true, v8::Local<v8::PrimitiveArray>());

v8::ScriptCompiler::Source source{ sourceCode, scriptOrigin };
auto maybeModule = v8::ScriptCompiler::CompileModule(isolate, &source);
if (maybeModule.IsEmpty()) {
Log::Error << "Failed to compile js-enums module" << Log::Endl;
return;
}

auto mod = maybeModule.ToLocalChecked();
v8::Maybe<bool> result = mod->InstantiateModule(ctx, HandleEnumsModuleImport);
if(result.IsNothing() || result.ToChecked() == false)
{
Log::Error << "Failed to instantiate js-enums module" << Log::Endl;
return;
}

auto returnValue = mod->Evaluate(ctx);
if(returnValue.IsEmpty())
{
Log::Error << "Failed to evaluate js-enums module" << Log::Endl;
return;
}

auto enumsNamespace = mod->GetModuleNamespace();
auto enums = enumsNamespace.As<v8::Object>();
v8::Local<v8::Array> keys;
enums->GetOwnPropertyNames(ctx).ToLocal(&keys);

for(uint32_t i = 0; i < keys->Length(); ++i)
{
v8::Local<v8::Value> key;
keys->Get(ctx, i).ToLocal(&key);
v8::Local<v8::Value> value;
enums->Get(ctx, key).ToLocal(&value);
exports->Set(ctx, key, value);
}
}

extern V8Class v8BaseObject, v8WorldObject, v8Entity, v8File, v8RGBA, v8Vector2, v8Vector3, v8Quaternion, v8Blip, v8AreaBlip, v8RadiusBlip, v8PointBlip, v8Resource, v8Utils;

extern V8Module
Expand Down Expand Up @@ -531,6 +581,8 @@ extern V8Module
V8_OBJECT_SET_INT(exports, "defaultDimension", alt::DEFAULT_DIMENSION);
V8_OBJECT_SET_INT(exports, "globalDimension", alt::GLOBAL_DIMENSION);

AddEnumsToSharedModuleExports(isolate, ctx, exports);

#ifdef ALT_CLIENT_API
V8_OBJECT_SET_BOOLEAN(exports, "isClient", true);
V8_OBJECT_SET_BOOLEAN(exports, "isServer", false);
Expand Down
16 changes: 16 additions & 0 deletions shared/cmake/GenerateEnums.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Generates the header files for the JavaScript enums transpiled from altv-types
if(NOT BINDINGS_SCOPE)
set(BINDINGS_SCOPE "SHARED")
endif()

if (CMAKE_HOST_WIN32)
add_custom_target(js-enums
call generate-enums.bat ${BINDINGS_SCOPE}
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
)
else()
add_custom_target(js-enums
bash generate-enums.sh ${BINDINGS_SCOPE}
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
)
endif()
1 change: 1 addition & 0 deletions shared/cmake/generate-enums.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node ../../tools/enums-transpiler.js ..
1 change: 1 addition & 0 deletions shared/cmake/generate-enums.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
node ../../tools/enums-transpiler.js ..
2 changes: 1 addition & 1 deletion shared/helpers/Bindings.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ namespace V8Helpers
v8::Isolate* isolate, v8::Local<v8::Context> ctx, v8::Local<v8::Object> target, const char* name, v8::FunctionCallback slowCb, FastFunc&& fastCb, const char* className = "")
{
V8FastFunction* func = V8FastFunction::GetOrCreate(name, className, slowCb, fastCb);
target->Set(ctx, v8::String::NewFromUtf8(isolate, name), func->GetTemplate(isolate)->GetFunction(ctx).ToLocalChecked());
target->Set(ctx, v8::String::NewFromUtf8(isolate, name).ToLocalChecked(), func->GetTemplate(isolate)->GetFunction(ctx).ToLocalChecked());
}
#endif
} // namespace V8Helpers
212 changes: 212 additions & 0 deletions tools/enums-transpiler.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
// clang-format off
const fs = require("fs").promises;
const assert = require("assert");
const pathUtil = require("path");

const ENUM_START = "enum ";
const transpiledEnumNames = new Set();

function transpileTSEnums(tsCode) {
let jsCode = "";
let pos = 0;

while (true) {
const startIndex = tsCode.indexOf(ENUM_START, pos);
if (startIndex === -1) {
// console.log("startIndex -1");
break;
}

const enumNameStartIndex = startIndex + ENUM_START.length;

let bodyStartIndex = tsCode.indexOf("{", enumNameStartIndex);
assert.notEqual(bodyStartIndex, -1);

const bodyEndIndex = tsCode.indexOf("}", bodyStartIndex);
assert.notEqual(bodyEndIndex, -1);
pos = bodyEndIndex;

const body = tsCode
.slice(bodyStartIndex + 1, bodyEndIndex)
.replaceAll(/\/\*(.|\n)*\*\//gm, "")
.replaceAll(/\/\/(.|\n)*$/gm, "");

const enumName = tsCode
.slice(enumNameStartIndex, bodyStartIndex)
.trim();
if (transpiledEnumNames.has(enumName)) {
throw new Error(`Detected enum duplicate: ${enumName}`);
}
transpiledEnumNames.add(enumName);

const members = body.split(/(?!"),(?!")/).map((each) => each.trim());

// console.log({ members } /* "body:\n\n", body, "\n\n" */);

if (members.at(-1)?.length === 0) {
// console.log("removing trailing comma space");
members.pop();
}

const jsMembers = [];

members.reduce((acc, memberContent) => {
// console.log({
// acc,
// memberContent,
// });

let memberName;
let memberValue;

const explicitMember = memberContent.match(/^(.+).*=(.*)$/);
if (explicitMember) {
// console.log({ explicitMember });

[, memberName, memberValue] = explicitMember;
memberName = memberName.trim();
memberValue = memberValue.trim();
if (!(memberValue.includes('"') || memberValue.includes("'"))) {
assert.ok(
!isNaN(+memberValue),
`raw member value: ${memberValue}`
);
memberValue = +memberValue;
}
} else {
memberName = memberContent;
assert.ok(
typeof acc === "number" && !isNaN(acc),
`acc: ${acc} memberName: ${memberName}`
);
memberValue = acc + 1;
}

// console.log({
// memberContent,
// memberName,
// memberValue,
// });

jsMembers.push([memberName.trim(), memberValue]);

return memberValue;
}, -1);

// console.log({
// enumName,
// members,
// });

const jsBody = jsMembers
.map(([name, value]) => {
name = name
.replaceAll('"', "")
.replaceAll("'", "")
.replaceAll("\\", "\\\\");
if (typeof value === "number") {
return (
` '${name}': ${value},\n` + ` '${value}': '${name}'`
);
} else {
return ` '${name}': ${value},\n` + ` ${value}: '${name}'`;
}
})
.join(",\n");

jsCode += `export const ${enumName} = {\n${jsBody}\n}\n`;
}

return jsCode;
}

const modules = [
"https://raw.githubusercontent.com/altmp/altv-types/master/shared/index.d.ts",
"https://raw.githubusercontent.com/altmp/altv-types/master/server/index.d.ts",
"https://raw.githubusercontent.com/altmp/altv-types/master/client/index.d.ts",
];

(async () => {
// Base path should point to the main directory of the repo
if (process.argv.length < 3) {
showError("Missing 'basePath' argument");
showUsage();
process.exit(1);
}
const basePath = process.argv[2];

// for debug purposes
const outputJsCode = process.argv[3] ?? null;

let jsCode = "";
for (const m of modules) {
const content = await (await fetch(m)).text();
jsCode += transpileTSEnums(content);
}

if (outputJsCode) {
await fs.writeFile(
pathUtil.resolve(__dirname, basePath, outputJsCode),
jsCode
);
showLog(
`Wrote enums transpilation result as JS code to file: ${outputJsCode}`
);
}

// Result bindings output path
const outputPath = "shared/JSEnums.h";

// Full output file
const resultTemplate = `// !!! THIS FILE WAS AUTOMATICALLY GENERATED (ON {Date}), DO NOT EDIT MANUALLY !!!
#pragma once
#include <string>
namespace JSEnums {
static std::string GetBindingsCode()
{
static constexpr char code[] = { {BindingsCode},'\\0' };
return code;
}
}
`;

// Convert the whole file content to a char code array
const content = jsCode.split("").map((char) => char.charCodeAt(0));
const outputStr = resultTemplate
.replace("{BindingsCode}", content.toString())
.replace("{Date}", `${getDate()} ${getTime()}`);
await fs.writeFile(
pathUtil.resolve(__dirname, basePath, outputPath),
outputStr
);
showLog(`Wrote enums transpilation result to file: ${outputPath}`);
})();

function getDate() {
const date = new Date();
const day = date.getDate(),
month = date.getMonth() + 1,
year = date.getFullYear();
return `${day < 10 ? `0${day}` : day}/${
month < 10 ? `0${month}` : month
}/${year}`;
}

function getTime() {
const date = new Date();
const hours = date.getHours(),
minutes = date.getMinutes(),
seconds = date.getSeconds();
return `${hours < 10 ? `0${hours}` : hours}:${
minutes < 10 ? `0${minutes}` : minutes
}:${seconds < 10 ? `0${seconds}` : seconds}`;
}

function showLog(...args) {
console.log(`[${getTime()}]`, ...args);
}

function showError(...args) {
console.error(`[${getTime()}]`, ...args);
}

0 comments on commit 426e67e

Please sign in to comment.