Compare commits
9 Commits
| Author | SHA1 | Date |
|---|---|---|
|
|
07714e6e63 | |
|
|
dd3a7330d3 | |
|
|
224b610aac | |
|
|
8252d42b6a | |
|
|
659ef72d68 | |
|
|
36885c446a | |
|
|
03e495a8ba | |
|
|
9e54158bb6 | |
|
|
c7c97e4ae5 |
|
|
@ -0,0 +1 @@
|
||||||
|
.vscodeignore
|
||||||
|
|
@ -1,11 +0,0 @@
|
||||||
.vscode/**
|
|
||||||
.vscode-test/**
|
|
||||||
src/**
|
|
||||||
.gitignore
|
|
||||||
.yarnrc
|
|
||||||
vsc-extension-quickstart.md
|
|
||||||
**/tsconfig.json
|
|
||||||
**/eslint.config.mjs
|
|
||||||
**/*.map
|
|
||||||
**/*.ts
|
|
||||||
**/.vscode-test.*
|
|
||||||
21
CHANGELOG.md
21
CHANGELOG.md
|
|
@ -17,3 +17,24 @@ I will use this area to keep up with what i did last.
|
||||||
## [Release 1.0.11]
|
## [Release 1.0.11]
|
||||||
|
|
||||||
- Removed Debug Data
|
- Removed Debug Data
|
||||||
|
|
||||||
|
## [Release 1.1.2]
|
||||||
|
|
||||||
|
- Combined the 2 dev tool resources togethter to make one total tool for easier maintaining
|
||||||
|
|
||||||
|
## [Release 1.1.3]
|
||||||
|
|
||||||
|
- Updated snippets for SLF to align with new coding processes
|
||||||
|
- Updated templates for resource builder to build to new coding process
|
||||||
|
|
||||||
|
## [Release 1.1.4]
|
||||||
|
|
||||||
|
- Updated logging functions on all scripts and snippets to allow for the new on the fly log change.
|
||||||
|
|
||||||
|
## [Release 1.1.5]
|
||||||
|
- The Christina update
|
||||||
|
- Added in cleaner snippets for SLF and updated templates to match when creating a new resource.
|
||||||
|
|
||||||
|
## [Release 1.1.6]
|
||||||
|
- Updated all resources generated to have new dependencies on SPH and SDB
|
||||||
|
- Updated to new html code for splashscreens
|
||||||
26
README.md
26
README.md
|
|
@ -8,5 +8,29 @@ A collection of custom Lua snippets for FiveM development.
|
||||||
- Thread templates
|
- Thread templates
|
||||||
- Common FiveM utilities
|
- Common FiveM utilities
|
||||||
|
|
||||||
## Usage
|
## Snippet Usage
|
||||||
Type a snippet prefix and press Ctrl+Space.
|
Type a snippet prefix and press Ctrl+Space.
|
||||||
|
|
||||||
|
## Resource Generator Usage
|
||||||
|
This is an ***INTERNAL USE ONLY*** tool for generating a FiveM Resource using our structure that we have outlined during the GCONFIG update. This will produce you a folder with the correct naming schemes, folder structure, and settings to allow for a plug and play experience. Edit what you need to and remove/add anything you need to the provided files. If you have any updates/request for thing in the generator let Chase know so he can get it in a plugin update and get that uploaded to the repository.
|
||||||
|
|
||||||
|
Right click on your resources folder in your explorer window on the left hand side of your screen and select "Generate FiveM Resource From Template" and follow the prompts on the screen and it will create the following folder structure and fill out the fxmanifest.lua with the info provided.
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
├── RESOURCE CODE
|
||||||
|
│ ├── fxmanifest.lua
|
||||||
|
│ ├── initConfig.json
|
||||||
|
│ ├── SERVER
|
||||||
|
│ │ ├── server.lua
|
||||||
|
│ ├── CLIENT
|
||||||
|
│ │ ├── client.lua
|
||||||
|
│ ├── MENUS
|
||||||
|
│ │ ├── readme.txt
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# Disclaimer
|
||||||
|
Yes you can indeed make a resource folder yourself. Yes this is a fair bit cheating, but this ensure that the files you are starting with are a good foundation to work from and you are less likely to trip and mess up.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,7 @@ exports.activate = activate;
|
||||||
exports.deactivate = deactivate;
|
exports.deactivate = deactivate;
|
||||||
const vscode = __importStar(require("vscode"));
|
const vscode = __importStar(require("vscode"));
|
||||||
const updater_1 = require("./updater");
|
const updater_1 = require("./updater");
|
||||||
|
const resourceGenerator_1 = require("./resourceGenerator");
|
||||||
// ================= LOGGING SETUP =================
|
// ================= LOGGING SETUP =================
|
||||||
exports.updaterOutput = vscode.window.createOutputChannel("Updater Startup");
|
exports.updaterOutput = vscode.window.createOutputChannel("Updater Startup");
|
||||||
function logDebug(...args) {
|
function logDebug(...args) {
|
||||||
|
|
@ -50,12 +51,14 @@ function logDebug(...args) {
|
||||||
exports.updaterOutput.show(true);
|
exports.updaterOutput.show(true);
|
||||||
}
|
}
|
||||||
function activate(context) {
|
function activate(context) {
|
||||||
logDebug("[Extension] Activating extension..."); // test log
|
logDebug("[Extension] Activating extension...");
|
||||||
// Run automatic updater
|
// Run automatic updater
|
||||||
(0, updater_1.runUpdater)(context);
|
(0, updater_1.runUpdater)(context);
|
||||||
// Register manual update check command
|
// Register manual update command
|
||||||
const disposable = vscode.commands.registerCommand("kj4lxc.cstmgames.fivem_snippets.checkUpdates", () => (0, updater_1.manualUpdateCheck)(context));
|
const disposable = vscode.commands.registerCommand("kj4lxc.cstmgames.fivem_devtools.autoUpdate", () => (0, updater_1.manualUpdateCheck)(context));
|
||||||
context.subscriptions.push(disposable);
|
context.subscriptions.push(disposable);
|
||||||
|
// Register resource generator
|
||||||
|
(0, resourceGenerator_1.registerResourceGenerator)(context);
|
||||||
}
|
}
|
||||||
function deactivate() { }
|
function deactivate() { }
|
||||||
//# sourceMappingURL=extension.js.map
|
//# sourceMappingURL=extension.js.map
|
||||||
|
|
@ -1 +1 @@
|
||||||
{"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAMA,4BAOC;AAED,4BAYC;AAED,gCAA+B;AA7B/B,+CAAiC;AACjC,uCAA0D;AAE1D,oDAAoD;AACvC,QAAA,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC,iBAAiB,CAAC,CAAC;AAElF,SAAgB,QAAQ,CAAC,GAAG,IAAW;IACnC,MAAM,OAAO,GAAG,IAAI;SACf,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SAClE,IAAI,CAAC,GAAG,CAAC,CAAC;IACf,qBAAa,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAClC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,oCAAoC;IAC1D,qBAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC;AAED,SAAgB,QAAQ,CAAC,OAAgC;IACrD,QAAQ,CAAC,qCAAqC,CAAC,CAAC,CAAC,WAAW;IAE5D,wBAAwB;IACxB,IAAA,oBAAU,EAAC,OAAO,CAAC,CAAC;IAEpB,uCAAuC;IACvC,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC,eAAe,CAC9C,8CAA8C,EAC9C,GAAG,EAAE,CAAC,IAAA,2BAAiB,EAAC,OAAO,CAAC,CACnC,CAAC;IACF,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AAC3C,CAAC;AAED,SAAgB,UAAU,KAAI,CAAC"}
|
{"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAOA,4BAOC;AAED,4BAeC;AAED,gCAA+B;AAjC/B,+CAAiC;AACjC,uCAA0D;AAC1D,2DAAgE;AAEhE,oDAAoD;AACvC,QAAA,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC,iBAAiB,CAAC,CAAC;AAElF,SAAgB,QAAQ,CAAC,GAAG,IAAW;IACnC,MAAM,OAAO,GAAG,IAAI;SACf,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;SAClE,IAAI,CAAC,GAAG,CAAC,CAAC;IACf,qBAAa,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAClC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,oCAAoC;IAC1D,qBAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC;AAED,SAAgB,QAAQ,CAAC,OAAgC;IACrD,QAAQ,CAAC,qCAAqC,CAAC,CAAC;IAEhD,wBAAwB;IACxB,IAAA,oBAAU,EAAC,OAAO,CAAC,CAAC;IAEpB,iCAAiC;IACjC,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC,eAAe,CAC9C,4CAA4C,EAC5C,GAAG,EAAE,CAAC,IAAA,2BAAiB,EAAC,OAAO,CAAC,CACnC,CAAC;IACF,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAEvC,8BAA8B;IAC9B,IAAA,6CAAyB,EAAC,OAAO,CAAC,CAAC;AACvC,CAAC;AAED,SAAgB,UAAU,KAAI,CAAC"}
|
||||||
|
|
@ -0,0 +1,164 @@
|
||||||
|
"use strict";
|
||||||
|
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||||
|
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||||
|
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||||
|
}
|
||||||
|
Object.defineProperty(o, k2, desc);
|
||||||
|
}) : (function(o, m, k, k2) {
|
||||||
|
if (k2 === undefined) k2 = k;
|
||||||
|
o[k2] = m[k];
|
||||||
|
}));
|
||||||
|
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||||
|
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||||
|
}) : function(o, v) {
|
||||||
|
o["default"] = v;
|
||||||
|
});
|
||||||
|
var __importStar = (this && this.__importStar) || (function () {
|
||||||
|
var ownKeys = function(o) {
|
||||||
|
ownKeys = Object.getOwnPropertyNames || function (o) {
|
||||||
|
var ar = [];
|
||||||
|
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
||||||
|
return ar;
|
||||||
|
};
|
||||||
|
return ownKeys(o);
|
||||||
|
};
|
||||||
|
return function (mod) {
|
||||||
|
if (mod && mod.__esModule) return mod;
|
||||||
|
var result = {};
|
||||||
|
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
||||||
|
__setModuleDefault(result, mod);
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.registerResourceGenerator = registerResourceGenerator;
|
||||||
|
const vscode = __importStar(require("vscode"));
|
||||||
|
const fs_1 = require("fs");
|
||||||
|
const path = __importStar(require("path"));
|
||||||
|
let extensionTemplatePath = "";
|
||||||
|
let includeFeature = false; // ✅ boolean flag
|
||||||
|
const InputData = {
|
||||||
|
resourceCode: {
|
||||||
|
title: "Resource Code",
|
||||||
|
placeholder: "Used for the folder name: GOD, GSR, SELAPI, ...",
|
||||||
|
nextInput: "resourceName",
|
||||||
|
value: ""
|
||||||
|
},
|
||||||
|
resourceName: {
|
||||||
|
title: "Resource name",
|
||||||
|
placeholder: "B_Jobs, Phone, esx_garage, ...",
|
||||||
|
nextInput: "description",
|
||||||
|
value: ""
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
title: "Resource description",
|
||||||
|
placeholder: "This resource is ...",
|
||||||
|
nextInput: "",
|
||||||
|
value: ""
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const startInput = "resourceCode";
|
||||||
|
// ================= ENTRY FUNCTION =================
|
||||||
|
function registerResourceGenerator(context) {
|
||||||
|
extensionTemplatePath = path.join(context.extensionPath, "template");
|
||||||
|
const disposable = vscode.commands.registerCommand("kj4lxc.fivem.generate-resource", (uri) => {
|
||||||
|
loadInputs(uri?.fsPath);
|
||||||
|
});
|
||||||
|
context.subscriptions.push(disposable);
|
||||||
|
}
|
||||||
|
// ================= INPUT FLOW =================
|
||||||
|
function loadInputs(resourcePath) {
|
||||||
|
for (const key in InputData) {
|
||||||
|
const field = InputData[key];
|
||||||
|
field.input = vscode.window.createInputBox();
|
||||||
|
field.input.title = field.title;
|
||||||
|
field.input.placeholder = field.placeholder;
|
||||||
|
field.input.onDidAccept(() => {
|
||||||
|
if (field.input.value.trim().length > 0) {
|
||||||
|
field.value = field.input.value;
|
||||||
|
field.input.hide();
|
||||||
|
if (field.nextInput) {
|
||||||
|
InputData[field.nextInput].input.show();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
askIncludeFeature(resourcePath); // ✅ NEW STEP
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
vscode.window.showErrorMessage(`You need to complete this input (${field.title}).`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (key === startInput) {
|
||||||
|
field.input.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ================= BOOLEAN PROMPT =================
|
||||||
|
async function askIncludeFeature(resourcePath) {
|
||||||
|
const result = await vscode.window.showQuickPick(["Yes", "No"], {
|
||||||
|
placeHolder: "Include UI Elements?"
|
||||||
|
});
|
||||||
|
if (!result) {
|
||||||
|
vscode.window.showWarningMessage("Operation cancelled.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
includeFeature = result === "Yes";
|
||||||
|
startProcessing(resourcePath);
|
||||||
|
}
|
||||||
|
// ================= PROCESSING =================
|
||||||
|
function startProcessing(basePath) {
|
||||||
|
if (!basePath) {
|
||||||
|
vscode.window.showErrorMessage("No folder selected.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const folder = getGeneratedFolder("");
|
||||||
|
const resourcePath = path.join(basePath, InputData.resourceCode.value);
|
||||||
|
(0, fs_1.mkdirSync)(resourcePath);
|
||||||
|
writeFolder(resourcePath, folder);
|
||||||
|
vscode.window.showInformationMessage(`You just created a new FiveM Lua Resource named '${InputData.resourceName.value}'.`);
|
||||||
|
}
|
||||||
|
function Folder(url) {
|
||||||
|
return {
|
||||||
|
url,
|
||||||
|
files: {},
|
||||||
|
folders: {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// ================= TEMPLATE PARSER =================
|
||||||
|
function getGeneratedFolder(url) {
|
||||||
|
const folder = Folder(url);
|
||||||
|
// ✅ SWITCH TEMPLATE BASED ON BOOLEAN
|
||||||
|
const baseTemplatePath = includeFeature
|
||||||
|
? path.join(extensionTemplatePath, "withFeature")
|
||||||
|
: path.join(extensionTemplatePath, "base");
|
||||||
|
const files = (0, fs_1.readdirSync)(path.join(baseTemplatePath, url), {
|
||||||
|
withFileTypes: true
|
||||||
|
});
|
||||||
|
for (const file of files) {
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
folder.folders[file.name] = getGeneratedFolder(path.join(url, file.name));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
let content = (0, fs_1.readFileSync)(path.join(baseTemplatePath, url, file.name), "utf-8");
|
||||||
|
for (const key in InputData) {
|
||||||
|
content = content.replace(new RegExp(`\\$\\{${key}\\}`, "g"), InputData[key].value);
|
||||||
|
}
|
||||||
|
folder.files[file.name] = content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return folder;
|
||||||
|
}
|
||||||
|
// ================= FILE WRITER =================
|
||||||
|
function writeFolder(url, folder) {
|
||||||
|
for (const key in folder.files) {
|
||||||
|
(0, fs_1.writeFileSync)(path.join(url, key), folder.files[key], "utf-8");
|
||||||
|
}
|
||||||
|
for (const key in folder.folders) {
|
||||||
|
const subFolderPath = path.join(url, key);
|
||||||
|
(0, fs_1.mkdirSync)(subFolderPath);
|
||||||
|
writeFolder(subFolderPath, folder.folders[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//# sourceMappingURL=resourceGenerator.js.map
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"resourceGenerator.js","sourceRoot":"","sources":["../src/resourceGenerator.ts"],"names":[],"mappings":"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"}
|
||||||
|
|
@ -46,7 +46,7 @@ const os = __importStar(require("os"));
|
||||||
const path = __importStar(require("path"));
|
const path = __importStar(require("path"));
|
||||||
const node_fetch_1 = __importDefault(require("node-fetch"));
|
const node_fetch_1 = __importDefault(require("node-fetch"));
|
||||||
// ================= LOGGING SETUP =================
|
// ================= LOGGING SETUP =================
|
||||||
exports.updaterOutput = vscode.window.createOutputChannel("Updater");
|
exports.updaterOutput = vscode.window.createOutputChannel("CSTMGames Updater");
|
||||||
function logDebug(...args) {
|
function logDebug(...args) {
|
||||||
const message = args
|
const message = args
|
||||||
.map(a => (typeof a === "object" ? JSON.stringify(a, null, 2) : a))
|
.map(a => (typeof a === "object" ? JSON.stringify(a, null, 2) : a))
|
||||||
|
|
@ -156,29 +156,25 @@ async function installVsix(url) {
|
||||||
const tmpFile = path.join(os.tmpdir(), "update.vsix");
|
const tmpFile = path.join(os.tmpdir(), "update.vsix");
|
||||||
try {
|
try {
|
||||||
logDebug("[Updater] Downloading VSIX from:", url);
|
logDebug("[Updater] Downloading VSIX from:", url);
|
||||||
// Fetch the VSIX
|
|
||||||
const res = await (0, node_fetch_1.default)(url);
|
const res = await (0, node_fetch_1.default)(url);
|
||||||
if (!res.ok)
|
if (!res.ok)
|
||||||
throw new Error(`HTTP ${res.status}`);
|
throw new Error(`HTTP ${res.status}`);
|
||||||
const buffer = Buffer.from(await res.arrayBuffer());
|
const buffer = Buffer.from(await res.arrayBuffer());
|
||||||
// Save to temp file
|
|
||||||
fs.writeFileSync(tmpFile, buffer);
|
fs.writeFileSync(tmpFile, buffer);
|
||||||
logDebug("[Updater] VSIX saved to temp file:", tmpFile);
|
logDebug("[Updater] VSIX saved to temp file:", tmpFile);
|
||||||
// Install extension from local file
|
|
||||||
await vscode.commands.executeCommand("workbench.extensions.installExtension", vscode.Uri.file(tmpFile));
|
await vscode.commands.executeCommand("workbench.extensions.installExtension", vscode.Uri.file(tmpFile));
|
||||||
logDebug("[Updater] Installed VSIX from temp file");
|
logDebug("[Updater] Installed VSIX from temp file");
|
||||||
// Ask user to reload
|
// ✅ Optional short delay (prevents race conditions)
|
||||||
const reload = await vscode.window.showInformationMessage("Extension updated successfully.", "Reload Now");
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
||||||
if (reload === "Reload Now") {
|
vscode.window.showInformationMessage("Extension updated successfully. Reloading...");
|
||||||
await vscode.commands.executeCommand("workbench.action.reloadWindow");
|
// ✅ AUTO reload VS Code (this restarts extensions)
|
||||||
}
|
await vscode.commands.executeCommand("workbench.action.reloadWindow");
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
logDebug("[Updater] Install failed:", err);
|
logDebug("[Updater] Install failed:", err);
|
||||||
vscode.window.showErrorMessage("Failed to install update.");
|
vscode.window.showErrorMessage("Failed to install update.");
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
// Clean up temp file
|
|
||||||
try {
|
try {
|
||||||
if (fs.existsSync(tmpFile)) {
|
if (fs.existsSync(tmpFile)) {
|
||||||
fs.unlinkSync(tmpFile);
|
fs.unlinkSync(tmpFile);
|
||||||
|
|
|
||||||
File diff suppressed because one or more lines are too long
34
package.json
34
package.json
|
|
@ -1,15 +1,19 @@
|
||||||
{
|
{
|
||||||
"name": "cstmgames-fivem-snippets",
|
"name": "cstmgames-fivem-snippets",
|
||||||
"displayName": "CSTMGames FiveM Snippets",
|
"displayName": "CSTMGames FiveM Dev Tools",
|
||||||
"description": "Snippets for FiveM",
|
"description": "Development tools for FiveM",
|
||||||
"version": "1.0.11",
|
"version": "1.1.6",
|
||||||
|
"author": {
|
||||||
|
"name": "Chase Eller",
|
||||||
|
"email": "chase@cstmgames.com",
|
||||||
|
"url": "https://cstmgames.com"
|
||||||
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"vscode": "^1.110.0"
|
"vscode": "^1.110.0"
|
||||||
},
|
},
|
||||||
"main": "./out/extension.js",
|
"main": "./out/extension.js",
|
||||||
"activationEvents": [
|
"activationEvents": [
|
||||||
"onStartupFinished",
|
"onStartupFinished"
|
||||||
"onCommand:cstmgames.fivem_snippets.checkUpdates"
|
|
||||||
],
|
],
|
||||||
"icon": "pridelogo.png",
|
"icon": "pridelogo.png",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
|
@ -29,14 +33,26 @@
|
||||||
],
|
],
|
||||||
"commands": [
|
"commands": [
|
||||||
{
|
{
|
||||||
"command": "kj4lxc.cstmgames.fivem_snippets.checkUpdates",
|
"command": "kj4lxc.cstmgames.fivem_devtools.autoUpdate",
|
||||||
"title": "Check for Snippet Updates"
|
"title": "Check for CSTMDev Tools Updates"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "kj4lxc.fivem.generate-resource",
|
||||||
|
"title": "Generate FiveM Resource"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"menus": {
|
||||||
|
"explorer/context": [
|
||||||
|
{
|
||||||
|
"when": "explorerResourceIsFolder",
|
||||||
|
"command": "kj4lxc.fivem.generate-resource"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
"configuration": {
|
"configuration": {
|
||||||
"title": "Snippets Updater",
|
"title": "CSTMGames FiveM Dev Tools Updater",
|
||||||
"properties": {
|
"properties": {
|
||||||
"cstmgames.fivem_snippets.autoUpdate": {
|
"cstmgames.fivem_devtools.autoUpdate": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": true,
|
"default": true,
|
||||||
"description": "Automatically install updates"
|
"description": "Automatically install updates"
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,29 @@
|
||||||
{
|
{
|
||||||
"Setup SLF Vars": {
|
|
||||||
"prefix": "SLFVARS",
|
|
||||||
"body": [
|
|
||||||
"local CLASS = \"CHANGEME\"--This is the name that the logging framework will use to display your logs in the correct manner",
|
|
||||||
"local LOG_LEVEL = GetResourceMetadata(GetCurrentResourceName(), \"log_level\", 0)",
|
|
||||||
"local RESOURCE_CODE = GetResourceMetadata(GetCurrentResourceName(), \"resource_code\", 0)"
|
|
||||||
],
|
|
||||||
"description": ""
|
|
||||||
},
|
|
||||||
"Log to SLF": {
|
"Log to SLF": {
|
||||||
"prefix": "Log",
|
"prefix": "Log",
|
||||||
"body": "Log(\"${1:Your Log Message Here}\", ${2|4,3,2,1|})$0",
|
"body": "Log(\"${1:Your Log Message Here}\", ${2|4,3,2,1|})$0",
|
||||||
"description": "Sets up basic Log function for use with SLF"
|
"description": "Sets up basic Log function for use with SLF"
|
||||||
},
|
},
|
||||||
"Log to Discord": {
|
"Log to Discord": {
|
||||||
"prefix": "DisLog",
|
"prefix": "DisLogCall",
|
||||||
"body": "DisLog(\"${1:Your Error Text Here}\")$0",
|
"body": "DisLog(\"${1:Your Error Text Here}\")$0",
|
||||||
"description": "SLF Function to log error to Discord."
|
"description": "SLF Function to log error to Discord."
|
||||||
},
|
},
|
||||||
|
"DISLOG FUNCTION": {
|
||||||
|
"prefix": "DISLOG",
|
||||||
|
"body": [
|
||||||
|
"local function DisLog(message)",
|
||||||
|
" local line = debug.getinfo(2, \"l\").currentline",
|
||||||
|
" local name = debug.getinfo(2, \"n\").name",
|
||||||
|
" if name == \"fn\" then",
|
||||||
|
" name = \"Thread\"",
|
||||||
|
" end",
|
||||||
|
" local value = \"{\"..CLASS..\".\"..name..\"(\"..line..\")} \"..message",
|
||||||
|
" exports.SLF:LogServerToDiscord(RESOURCE_CODE, message)",
|
||||||
|
"end"
|
||||||
|
],
|
||||||
|
"description": "DISLOG FUNCTION"
|
||||||
|
},
|
||||||
"Sets up a basic Citizen Thread for CFX": {
|
"Sets up a basic Citizen Thread for CFX": {
|
||||||
"prefix": "thread",
|
"prefix": "thread",
|
||||||
"body": [
|
"body": [
|
||||||
|
|
@ -48,39 +54,77 @@
|
||||||
],
|
],
|
||||||
"description": "Sets up command to be registered"
|
"description": "Sets up command to be registered"
|
||||||
},
|
},
|
||||||
"Server Side SLF Function": {
|
"SLF Functions and Vars for server.": {
|
||||||
"prefix": "slfserver",
|
"prefix": "SLFSERVER",
|
||||||
"body": [
|
"body": [
|
||||||
"function Log(message, logLevel)",
|
"--SLF CONSTANTS",
|
||||||
|
"local CLASS = \"CHANGEME\"--This is the name that the logging framework will use to display your logs in the correct manner",
|
||||||
|
"local LOG_LEVEL = GetResourceMetadata(GetCurrentResourceName(), \"log_level\", 0)",
|
||||||
|
"local RESOURCE_CODE = GetResourceMetadata(GetCurrentResourceName(), \"resource_code\", 0)",
|
||||||
|
"------------------------------------------------------------------------------------------------",
|
||||||
|
"---Used to send logs to the server console",
|
||||||
|
"---@param message any Preformatted message or VARIABLES to be sent to log",
|
||||||
|
"---@param logLevel integer Level of log, 1-Error, 2-Warn, 3-Info, 4-Debug",
|
||||||
|
"local function Log(message, logLevel)",
|
||||||
" local line = debug.getinfo(2, \"l\").currentline",
|
" local line = debug.getinfo(2, \"l\").currentline",
|
||||||
" local name = debug.getinfo(2, \"n\").name",
|
" local name = debug.getinfo(2, \"n\").name",
|
||||||
" if name == \"fn\" then",
|
" if name == \"fn\" then",
|
||||||
" name = \"Thread\"",
|
" name = \"Thread\"",
|
||||||
" end",
|
" end",
|
||||||
" local value = \"{\"..CLASS..\".\"..name..\"(\"..line..\")} \"..message",
|
" local value = \"{\"..CLASS..\".\"..name..\"(\"..line..\")} \"..message",
|
||||||
" if tonumber(LOG_LEVEL) >= logLevel then",
|
" if logLevel then",
|
||||||
" exports.SLF:LogToServer(RESOURCE_CODE, logLevel, value)",
|
" if tonumber(LOG_LEVEL) >= logLevel then",
|
||||||
|
" exports.SLF:LogToServer(RESOURCE_CODE, logLevel, value)",
|
||||||
|
" end",
|
||||||
|
" else",
|
||||||
|
" exports.SLF:LogToServer(RESOURCE_CODE, 4, value)",
|
||||||
|
" Log(\"Warning line was logged without a level value... Logged it as debug as that is the safest route.\", 1)",
|
||||||
" end",
|
" end",
|
||||||
"end"
|
"end",
|
||||||
|
"",
|
||||||
|
"RegisterNetEvent(RESOURCE_CODE..\":UpdateLogLevel\")",
|
||||||
|
"AddEventHandler(RESOURCE_CODE..\":UpdateLogLevel\", function(num)",
|
||||||
|
" LOG_LEVEL = num",
|
||||||
|
"end)",
|
||||||
|
"-----------------------------------------------------------------------------------------------"
|
||||||
],
|
],
|
||||||
"description": "Server Side SLF Function"
|
"description": "SLF Functions and Vars for server."
|
||||||
},
|
},
|
||||||
"Client Side SLF Function": {
|
"SLF Functions and Vars for client.": {
|
||||||
"prefix": "slfclient",
|
"prefix": "SLFCLIENT",
|
||||||
"body": [
|
"body": [
|
||||||
"function Log(message, logLevel)",
|
"--SLF CONSTANTS",
|
||||||
|
"local CLASS = \"CHANGEME\"--This is the name that the logging framework will use to display your logs in the correct manner",
|
||||||
|
"local LOG_LEVEL = GetResourceMetadata(GetCurrentResourceName(), \"log_level\", 0)",
|
||||||
|
"local RESOURCE_CODE = GetResourceMetadata(GetCurrentResourceName(), \"resource_code\", 0)",
|
||||||
|
"-----------------------------------------------------------------------------------------------",
|
||||||
|
"---Used to send logs to the client console",
|
||||||
|
"---@param message any Preformatted message or VARIABLES to be sent to log",
|
||||||
|
"---@param logLevel integer Level of log, 1-Error, 2-Warn, 3-Info, 4-Debug",
|
||||||
|
"local function Log(message, logLevel)",
|
||||||
" local line = debug.getinfo(2, \"l\").currentline",
|
" local line = debug.getinfo(2, \"l\").currentline",
|
||||||
" local name = debug.getinfo(2, \"n\").name",
|
" local name = debug.getinfo(2, \"n\").name",
|
||||||
" if name == \"fn\" then",
|
" if name == \"fn\" then",
|
||||||
" name = \"Thread\"",
|
" name = \"Thread\"",
|
||||||
" end",
|
" end",
|
||||||
" local value = \"{\"..CLASS..\".\"..name..\"(\"..line..\")} \"..message",
|
" local value = \"{\"..CLASS..\".\"..name..\"(\"..line..\")} \"..message",
|
||||||
" if tonumber(LOG_LEVEL) >= logLevel then",
|
" if logLevel then",
|
||||||
" exports.SLF:LogToClient(RESOURCE_CODE, logLevel, value)",
|
" if tonumber(LOG_LEVEL) >= logLevel then",
|
||||||
|
" exports.SLF:LogToClient(RESOURCE_CODE, logLevel, value)",
|
||||||
|
" end",
|
||||||
|
" else",
|
||||||
|
" exports.SLF:LogToClient(RESOURCE_CODE, 4, value)",
|
||||||
|
" Log(\"Warning line was logged without a level value... Logged it as debug as that is the safest route.\", 1)",
|
||||||
" end",
|
" end",
|
||||||
"end"
|
"end",
|
||||||
|
"",
|
||||||
|
"RegisterNetEvent(RESOURCE_CODE..\":UpdateLogLevel\")",
|
||||||
|
"AddEventHandler(RESOURCE_CODE..\":UpdateLogLevel\", function(num)",
|
||||||
|
" LOG_LEVEL = num",
|
||||||
|
"end)",
|
||||||
|
"-----------------------------------------------------------------------------------------------"
|
||||||
],
|
],
|
||||||
"description": "Client Side SLF Function"
|
"description": "SLF Functions and Vars for client."
|
||||||
},
|
},
|
||||||
"Sets up TriggerClientEvent": {
|
"Sets up TriggerClientEvent": {
|
||||||
"prefix": "tce",
|
"prefix": "tce",
|
||||||
|
|
@ -174,5 +218,35 @@
|
||||||
"end)"
|
"end)"
|
||||||
],
|
],
|
||||||
"description": "Thread Net Register"
|
"description": "Thread Net Register"
|
||||||
|
},
|
||||||
|
"Coding Regions": {
|
||||||
|
"prefix": "regions",
|
||||||
|
"body": [
|
||||||
|
"--CONSTANTS--",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"--VARIABLES--",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"--FUNCTIONS--",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"--THREADS--",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"--NET EVENTS--",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"--COMMANDS--",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
""
|
||||||
|
],
|
||||||
|
"description": "Coding Regions"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import * as vscode from "vscode";
|
import * as vscode from "vscode";
|
||||||
import { runUpdater, manualUpdateCheck } from "./updater";
|
import { runUpdater, manualUpdateCheck } from "./updater";
|
||||||
|
import { registerResourceGenerator } from "./resourceGenerator";
|
||||||
|
|
||||||
// ================= LOGGING SETUP =================
|
// ================= LOGGING SETUP =================
|
||||||
export const updaterOutput = vscode.window.createOutputChannel("Updater Startup");
|
export const updaterOutput = vscode.window.createOutputChannel("Updater Startup");
|
||||||
|
|
@ -14,17 +15,20 @@ export function logDebug(...args: any[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function activate(context: vscode.ExtensionContext) {
|
export function activate(context: vscode.ExtensionContext) {
|
||||||
logDebug("[Extension] Activating extension..."); // test log
|
logDebug("[Extension] Activating extension...");
|
||||||
|
|
||||||
// Run automatic updater
|
// Run automatic updater
|
||||||
runUpdater(context);
|
runUpdater(context);
|
||||||
|
|
||||||
// Register manual update check command
|
// Register manual update command
|
||||||
const disposable = vscode.commands.registerCommand(
|
const disposable = vscode.commands.registerCommand(
|
||||||
"kj4lxc.cstmgames.fivem_snippets.checkUpdates",
|
"kj4lxc.cstmgames.fivem_devtools.autoUpdate",
|
||||||
() => manualUpdateCheck(context)
|
() => manualUpdateCheck(context)
|
||||||
);
|
);
|
||||||
context.subscriptions.push(disposable);
|
context.subscriptions.push(disposable);
|
||||||
|
|
||||||
|
// Register resource generator
|
||||||
|
registerResourceGenerator(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deactivate() {}
|
export function deactivate() {}
|
||||||
|
|
@ -0,0 +1,189 @@
|
||||||
|
import * as vscode from "vscode";
|
||||||
|
import { readFileSync, readdirSync, mkdirSync, writeFileSync } from "fs";
|
||||||
|
import * as path from "path";
|
||||||
|
|
||||||
|
let extensionTemplatePath = "";
|
||||||
|
let includeFeature = false; // ✅ boolean flag
|
||||||
|
|
||||||
|
// ================= INPUT STRUCTURE =================
|
||||||
|
interface InputField {
|
||||||
|
title: string;
|
||||||
|
placeholder: string;
|
||||||
|
nextInput: string;
|
||||||
|
value: string;
|
||||||
|
input?: vscode.InputBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
const InputData: Record<string, InputField> = {
|
||||||
|
resourceCode: {
|
||||||
|
title: "Resource Code",
|
||||||
|
placeholder: "Used for the folder name: GOD, GSR, SELAPI, ...",
|
||||||
|
nextInput: "resourceName",
|
||||||
|
value: ""
|
||||||
|
},
|
||||||
|
resourceName: {
|
||||||
|
title: "Resource name",
|
||||||
|
placeholder: "B_Jobs, Phone, esx_garage, ...",
|
||||||
|
nextInput: "description",
|
||||||
|
value: ""
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
title: "Resource description",
|
||||||
|
placeholder: "This resource is ...",
|
||||||
|
nextInput: "",
|
||||||
|
value: ""
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const startInput = "resourceCode";
|
||||||
|
|
||||||
|
// ================= ENTRY FUNCTION =================
|
||||||
|
export function registerResourceGenerator(context: vscode.ExtensionContext) {
|
||||||
|
extensionTemplatePath = path.join(context.extensionPath, "template");
|
||||||
|
|
||||||
|
const disposable = vscode.commands.registerCommand(
|
||||||
|
"kj4lxc.fivem.generate-resource",
|
||||||
|
(uri: vscode.Uri) => {
|
||||||
|
loadInputs(uri?.fsPath);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
context.subscriptions.push(disposable);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================= INPUT FLOW =================
|
||||||
|
function loadInputs(resourcePath?: string) {
|
||||||
|
for (const key in InputData) {
|
||||||
|
const field = InputData[key];
|
||||||
|
|
||||||
|
field.input = vscode.window.createInputBox();
|
||||||
|
field.input.title = field.title;
|
||||||
|
field.input.placeholder = field.placeholder;
|
||||||
|
|
||||||
|
field.input.onDidAccept(() => {
|
||||||
|
if (field.input!.value.trim().length > 0) {
|
||||||
|
field.value = field.input!.value;
|
||||||
|
field.input!.hide();
|
||||||
|
|
||||||
|
if (field.nextInput) {
|
||||||
|
InputData[field.nextInput].input!.show();
|
||||||
|
} else {
|
||||||
|
askIncludeFeature(resourcePath); // ✅ NEW STEP
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
vscode.window.showErrorMessage(
|
||||||
|
`You need to complete this input (${field.title}).`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (key === startInput) {
|
||||||
|
field.input.show();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================= BOOLEAN PROMPT =================
|
||||||
|
async function askIncludeFeature(resourcePath?: string) {
|
||||||
|
const result = await vscode.window.showQuickPick(
|
||||||
|
["Yes", "No"],
|
||||||
|
{
|
||||||
|
placeHolder: "Include UI Elements?"
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!result) {
|
||||||
|
vscode.window.showWarningMessage("Operation cancelled.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
includeFeature = result === "Yes";
|
||||||
|
|
||||||
|
startProcessing(resourcePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================= PROCESSING =================
|
||||||
|
function startProcessing(basePath?: string) {
|
||||||
|
if (!basePath) {
|
||||||
|
vscode.window.showErrorMessage("No folder selected.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const folder = getGeneratedFolder("");
|
||||||
|
|
||||||
|
const resourcePath = path.join(basePath, InputData.resourceCode.value);
|
||||||
|
|
||||||
|
mkdirSync(resourcePath);
|
||||||
|
writeFolder(resourcePath, folder);
|
||||||
|
|
||||||
|
vscode.window.showInformationMessage(
|
||||||
|
`You just created a new FiveM Lua Resource named '${InputData.resourceName.value}'.`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================= FOLDER STRUCT =================
|
||||||
|
interface FolderType {
|
||||||
|
url: string;
|
||||||
|
files: Record<string, string>;
|
||||||
|
folders: Record<string, FolderType>;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Folder(url: string): FolderType {
|
||||||
|
return {
|
||||||
|
url,
|
||||||
|
files: {},
|
||||||
|
folders: {}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================= TEMPLATE PARSER =================
|
||||||
|
function getGeneratedFolder(url: string): FolderType {
|
||||||
|
const folder = Folder(url);
|
||||||
|
|
||||||
|
// ✅ SWITCH TEMPLATE BASED ON BOOLEAN
|
||||||
|
const baseTemplatePath = includeFeature
|
||||||
|
? path.join(extensionTemplatePath, "withFeature")
|
||||||
|
: path.join(extensionTemplatePath, "base");
|
||||||
|
|
||||||
|
const files = readdirSync(path.join(baseTemplatePath, url), {
|
||||||
|
withFileTypes: true
|
||||||
|
});
|
||||||
|
|
||||||
|
for (const file of files) {
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
folder.folders[file.name] = getGeneratedFolder(
|
||||||
|
path.join(url, file.name)
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
let content = readFileSync(
|
||||||
|
path.join(baseTemplatePath, url, file.name),
|
||||||
|
"utf-8"
|
||||||
|
);
|
||||||
|
|
||||||
|
for (const key in InputData) {
|
||||||
|
content = content.replace(
|
||||||
|
new RegExp(`\\$\\{${key}\\}`, "g"),
|
||||||
|
InputData[key].value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
folder.files[file.name] = content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return folder;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ================= FILE WRITER =================
|
||||||
|
function writeFolder(url: string, folder: FolderType) {
|
||||||
|
for (const key in folder.files) {
|
||||||
|
writeFileSync(path.join(url, key), folder.files[key], "utf-8");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const key in folder.folders) {
|
||||||
|
const subFolderPath = path.join(url, key);
|
||||||
|
mkdirSync(subFolderPath);
|
||||||
|
|
||||||
|
writeFolder(subFolderPath, folder.folders[key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -7,7 +7,7 @@ import fetch from "node-fetch";
|
||||||
|
|
||||||
|
|
||||||
// ================= LOGGING SETUP =================
|
// ================= LOGGING SETUP =================
|
||||||
export const updaterOutput = vscode.window.createOutputChannel("Updater");
|
export const updaterOutput = vscode.window.createOutputChannel("CSTMGames Updater");
|
||||||
|
|
||||||
export function logDebug(...args: any[]) {
|
export function logDebug(...args: any[]) {
|
||||||
const message = args
|
const message = args
|
||||||
|
|
@ -152,38 +152,35 @@ async function installVsix(url: string) {
|
||||||
try {
|
try {
|
||||||
logDebug("[Updater] Downloading VSIX from:", url);
|
logDebug("[Updater] Downloading VSIX from:", url);
|
||||||
|
|
||||||
// Fetch the VSIX
|
|
||||||
const res = await fetch(url);
|
const res = await fetch(url);
|
||||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||||
|
|
||||||
const buffer = Buffer.from(await res.arrayBuffer());
|
const buffer = Buffer.from(await res.arrayBuffer());
|
||||||
|
|
||||||
// Save to temp file
|
|
||||||
fs.writeFileSync(tmpFile, buffer);
|
fs.writeFileSync(tmpFile, buffer);
|
||||||
logDebug("[Updater] VSIX saved to temp file:", tmpFile);
|
logDebug("[Updater] VSIX saved to temp file:", tmpFile);
|
||||||
|
|
||||||
// Install extension from local file
|
|
||||||
await vscode.commands.executeCommand(
|
await vscode.commands.executeCommand(
|
||||||
"workbench.extensions.installExtension",
|
"workbench.extensions.installExtension",
|
||||||
vscode.Uri.file(tmpFile)
|
vscode.Uri.file(tmpFile)
|
||||||
);
|
);
|
||||||
|
|
||||||
logDebug("[Updater] Installed VSIX from temp file");
|
logDebug("[Updater] Installed VSIX from temp file");
|
||||||
|
|
||||||
// Ask user to reload
|
// ✅ Optional short delay (prevents race conditions)
|
||||||
const reload = await vscode.window.showInformationMessage(
|
await new Promise(resolve => setTimeout(resolve, 1500));
|
||||||
"Extension updated successfully.",
|
|
||||||
"Reload Now"
|
vscode.window.showInformationMessage(
|
||||||
|
"Extension updated successfully. Reloading..."
|
||||||
);
|
);
|
||||||
|
|
||||||
if (reload === "Reload Now") {
|
// ✅ AUTO reload VS Code (this restarts extensions)
|
||||||
await vscode.commands.executeCommand("workbench.action.reloadWindow");
|
await vscode.commands.executeCommand("workbench.action.reloadWindow");
|
||||||
}
|
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logDebug("[Updater] Install failed:", err);
|
logDebug("[Updater] Install failed:", err);
|
||||||
vscode.window.showErrorMessage("Failed to install update.");
|
vscode.window.showErrorMessage("Failed to install update.");
|
||||||
} finally {
|
} finally {
|
||||||
// Clean up temp file
|
|
||||||
try {
|
try {
|
||||||
if (fs.existsSync(tmpFile)) {
|
if (fs.existsSync(tmpFile)) {
|
||||||
fs.unlinkSync(tmpFile);
|
fs.unlinkSync(tmpFile);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
If you need to create a menu please add it here in this folder then declare it properly in the fxmanifest.
|
||||||
|
|
||||||
|
|
||||||
|
add "menuv" to your dependencies
|
||||||
|
|
||||||
|
add '@menuv/menuv.lua' and 'menu/*.lua' to your client_scripts declaration.
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
--SLF CONSTANTS
|
||||||
|
local CLASS = "CHANGEME"--This is the name that the logging framework will use to display your logs in the correct manner
|
||||||
|
local LOG_LEVEL = GetResourceMetadata(GetCurrentResourceName(), "log_level", 0)
|
||||||
|
local RESOURCE_CODE = GetResourceMetadata(GetCurrentResourceName(), "resource_code", 0)
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
---Used to send logs to the client console
|
||||||
|
---@param message any Preformatted message or VARIABLES to be sent to log
|
||||||
|
---@param logLevel integer Level of log, 1-Error, 2-Warn, 3-Info, 4-Debug
|
||||||
|
local function Log(message, logLevel)
|
||||||
|
local line = debug.getinfo(2, "l").currentline
|
||||||
|
local name = debug.getinfo(2, "n").name
|
||||||
|
if name == "fn" then
|
||||||
|
name = "Thread"
|
||||||
|
end
|
||||||
|
local value = "{"..CLASS.."."..name.."("..line..")} "..message
|
||||||
|
if logLevel then
|
||||||
|
if tonumber(LOG_LEVEL) >= logLevel then
|
||||||
|
exports.SLF:LogToClient(RESOURCE_CODE, logLevel, value)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
exports.SLF:LogToClient(RESOURCE_CODE, 4, value)
|
||||||
|
Log("Warning line was logged without a level value... Logged it as debug as that is the safest route.", 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
RegisterNetEvent(RESOURCE_CODE..":UpdateLogLevel")
|
||||||
|
AddEventHandler(RESOURCE_CODE..":UpdateLogLevel", function(num)
|
||||||
|
LOG_LEVEL = num
|
||||||
|
end)
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
--CONSTANTS--
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--VARIABLES--
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--FUNCTIONS--
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--THREADS--
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--NET EVENTS--
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--COMMANDS--
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
fx_version 'adamant'
|
||||||
|
game 'gta5'
|
||||||
|
name '${resourceName}'
|
||||||
|
description '${description}'
|
||||||
|
author 'CSTMChristina & KJ4LXC'
|
||||||
|
version '0.0.1'
|
||||||
|
--this is a working script
|
||||||
|
resource_code '${resourceCode}'
|
||||||
|
log_level '4'
|
||||||
|
bucket_prefix '9'
|
||||||
|
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
'SLF',
|
||||||
|
'SCF',
|
||||||
|
'SDB',
|
||||||
|
'SPH'
|
||||||
|
}
|
||||||
|
|
||||||
|
files {
|
||||||
|
'client/config/*.json'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
-- shared_scripts {
|
||||||
|
-- 'shared/*.lua'
|
||||||
|
-- }
|
||||||
|
|
||||||
|
client_scripts {
|
||||||
|
'@menuv/menuv.lua',
|
||||||
|
'menus/*.lua',
|
||||||
|
'client/*.lua'
|
||||||
|
}
|
||||||
|
|
||||||
|
server_scripts {
|
||||||
|
'server/*.lua'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
--SLF CONSTANTS
|
||||||
|
local CLASS = "CHANGEME"--This is the name that the logging framework will use to display your logs in the correct manner
|
||||||
|
local LOG_LEVEL = GetResourceMetadata(GetCurrentResourceName(), "log_level", 0)
|
||||||
|
local RESOURCE_CODE = GetResourceMetadata(GetCurrentResourceName(), "resource_code", 0)
|
||||||
|
------------------------------------------------------------------------------------------------
|
||||||
|
---Used to send logs to the server console
|
||||||
|
---@param message any Preformatted message or VARIABLES to be sent to log
|
||||||
|
---@param logLevel integer Level of log, 1-Error, 2-Warn, 3-Info, 4-Debug
|
||||||
|
local function Log(message, logLevel)
|
||||||
|
local line = debug.getinfo(2, "l").currentline
|
||||||
|
local name = debug.getinfo(2, "n").name
|
||||||
|
if name == "fn" then
|
||||||
|
name = "Thread"
|
||||||
|
end
|
||||||
|
local value = "{"..CLASS.."."..name.."("..line..")} "..message
|
||||||
|
if logLevel then
|
||||||
|
if tonumber(LOG_LEVEL) >= logLevel then
|
||||||
|
exports.SLF:LogToServer(RESOURCE_CODE, logLevel, value)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
exports.SLF:LogToServer(RESOURCE_CODE, 4, value)
|
||||||
|
Log("Warning line was logged without a level value... Logged it as debug as that is the safest route.", 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
RegisterNetEvent(RESOURCE_CODE..":UpdateLogLevel")
|
||||||
|
AddEventHandler(RESOURCE_CODE..":UpdateLogLevel", function(num)
|
||||||
|
LOG_LEVEL = num
|
||||||
|
end)
|
||||||
|
------------------------------------------------------------------------------------------------
|
||||||
|
--CONSTANTS--
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--VARIABLES--
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--FUNCTIONS--
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--THREADS--
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--NET EVENTS--
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--COMMANDS--
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
If you need to create a menu please add it here in this folder then declare it properly in the fxmanifest.
|
||||||
|
|
||||||
|
|
||||||
|
add "menuv" to your dependencies
|
||||||
|
|
||||||
|
add '@menuv/menuv.lua' and 'menu/*.lua' to your client_scripts declaration.
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
--SLF CONSTANTS
|
||||||
|
local CLASS = "CHANGEME"--This is the name that the logging framework will use to display your logs in the correct manner
|
||||||
|
local LOG_LEVEL = GetResourceMetadata(GetCurrentResourceName(), "log_level", 0)
|
||||||
|
local RESOURCE_CODE = GetResourceMetadata(GetCurrentResourceName(), "resource_code", 0)
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
---Used to send logs to the client console
|
||||||
|
---@param message any Preformatted message or VARIABLES to be sent to log
|
||||||
|
---@param logLevel integer Level of log, 1-Error, 2-Warn, 3-Info, 4-Debug
|
||||||
|
local function Log(message, logLevel)
|
||||||
|
local line = debug.getinfo(2, "l").currentline
|
||||||
|
local name = debug.getinfo(2, "n").name
|
||||||
|
if name == "fn" then
|
||||||
|
name = "Thread"
|
||||||
|
end
|
||||||
|
local value = "{"..CLASS.."."..name.."("..line..")} "..message
|
||||||
|
if logLevel then
|
||||||
|
if tonumber(LOG_LEVEL) >= logLevel then
|
||||||
|
exports.SLF:LogToClient(RESOURCE_CODE, logLevel, value)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
exports.SLF:LogToClient(RESOURCE_CODE, 4, value)
|
||||||
|
Log("Warning line was logged without a level value... Logged it as debug as that is the safest route.", 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
RegisterNetEvent(RESOURCE_CODE..":UpdateLogLevel")
|
||||||
|
AddEventHandler(RESOURCE_CODE..":UpdateLogLevel", function(num)
|
||||||
|
LOG_LEVEL = num
|
||||||
|
end)
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
--CONSTANTS--
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--VARIABLES--
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--FUNCTIONS--
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--THREADS--
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--NET EVENTS--
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--COMMANDS--
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,57 @@
|
||||||
|
body {
|
||||||
|
font-size: 20px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.unselectable {
|
||||||
|
-webkit-touch-callout: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-khtml-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
-o-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loader {
|
||||||
|
border: 16px solid #6d6d6dc4; /* Light grey */
|
||||||
|
border-top: 16px solid #4f2580; /* purple */
|
||||||
|
border-radius: 50%;
|
||||||
|
width: 120px;
|
||||||
|
height: 120px;
|
||||||
|
animation: spin 2s linear infinite;
|
||||||
|
right: 1%;
|
||||||
|
bottom: 1%;
|
||||||
|
position: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% { transform: rotate(0deg); }
|
||||||
|
100% { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-in-image {
|
||||||
|
animation: fadeIn 1.5S;
|
||||||
|
-webkit-animation: fadeIn 1.5S;
|
||||||
|
-moz-animation: fadeIn 1.5S;
|
||||||
|
-o-animation: fadeIn 1.5S;
|
||||||
|
-ms-animation: fadeIn 1.5S;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeIn {
|
||||||
|
0% { opacity: 0; }
|
||||||
|
100% { opacity: 1; }
|
||||||
|
}
|
||||||
|
|
||||||
|
.fade-out-image {
|
||||||
|
animation: fadeOut 1.5S;
|
||||||
|
-webkit-animation: fadeOut 1.5S;
|
||||||
|
-moz-animation: fadeOut 1.5S;
|
||||||
|
-o-animation: fadeOut 1.5S;
|
||||||
|
-ms-animation: fadeOut 1.5S;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes fadeOut {
|
||||||
|
0% { opacity: 1; }
|
||||||
|
100% { opacity: 0; }
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,41 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" href="reset.css" type="text/css">
|
||||||
|
<link rel="stylesheet" href="loadsplash.css" type="text/css">
|
||||||
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Fjalla+One&family=Inconsolata:wght@300&display=swap" rel="stylesheet">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Fjalla+One&family=Inconsolata:wght@300&family=Roboto+Condensed&display=swap" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="https://www.w3schools.com/w3css/4/w3.css">
|
||||||
|
<script src="nui://game/ui/jquery.js" type="text/javascript"></script>
|
||||||
|
<script src="nui://game/ui/jquery.js" type="text/javascript"></script>
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/howler/2.1.1/howler.min.js" type="text/javascript"></script>
|
||||||
|
<script>
|
||||||
|
var audioPlayer = null;
|
||||||
|
// Listen for NUI Messages.
|
||||||
|
window.addEventListener('message', function(event) {
|
||||||
|
// Check for playSound transaction
|
||||||
|
if (event.data.transactionType == "playSound") {
|
||||||
|
|
||||||
|
if (audioPlayer != null) {
|
||||||
|
audioPlayer.pause();
|
||||||
|
}
|
||||||
|
|
||||||
|
audioPlayer = new Howl({src: ["./sounds/" + event.data.transactionFile + ".ogg"]});
|
||||||
|
audioPlayer.volume(event.data.transactionVolume);
|
||||||
|
audioPlayer.play();
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body id="splashScreen" class="unselectable w3-display-container">
|
||||||
|
<div class="w3-animate-opacity">
|
||||||
|
<script src="./loadsplash.js" type="text/javascript"></script>
|
||||||
|
<div id="loader" class="loader"></div>
|
||||||
|
<div class="fade-in-image">
|
||||||
|
<img id="bgIMG" src="https://images.cstm.games/imgstor/splashscreens/defaultsplash.png" alt="" style="width:100%;height:100%;">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
$(function () {
|
||||||
|
function showSplash(bool) {
|
||||||
|
if (bool) {
|
||||||
|
$("#splashScreen").show();
|
||||||
|
} else {
|
||||||
|
$("#splashScreen").hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function showLoadingSplash(bool) {
|
||||||
|
if (bool) {
|
||||||
|
$("#splashScreen").show();
|
||||||
|
$("#loader").show();
|
||||||
|
} else {
|
||||||
|
$("#splashScreen").hide();
|
||||||
|
$("#loader").hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('message', function(event) {
|
||||||
|
var item = event.data;
|
||||||
|
|
||||||
|
// Show or hide the splash screen without loading spinner
|
||||||
|
if (item.type === "showSplash") {
|
||||||
|
if (item.status == true) {
|
||||||
|
showSplash(true)
|
||||||
|
} else {
|
||||||
|
showSplash(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Show or hide the loading splash screen
|
||||||
|
if (item.type === "showLoadingSplash") {
|
||||||
|
if (item.status == true) {
|
||||||
|
showLoadingSplash(true)
|
||||||
|
} else {
|
||||||
|
showLoadingSplash(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.type === "setIMG") {
|
||||||
|
document.getElementById("bgIMG").src = item.value;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
showLoadingSplash(false)
|
||||||
|
})
|
||||||
|
|
@ -0,0 +1,48 @@
|
||||||
|
/* http://meyerweb.com/eric/tools/css/reset/
|
||||||
|
v2.0 | 20110126
|
||||||
|
License: none (public domain)
|
||||||
|
*/
|
||||||
|
|
||||||
|
html, body, div, span, applet, object, iframe,
|
||||||
|
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
|
||||||
|
a, abbr, acronym, address, big, cite, code,
|
||||||
|
del, dfn, em, img, ins, kbd, q, s, samp,
|
||||||
|
small, strike, strong, sub, sup, tt, var,
|
||||||
|
b, u, i, center,
|
||||||
|
dl, dt, dd, ol, ul, li,
|
||||||
|
fieldset, form, label, legend,
|
||||||
|
table, caption, tbody, tfoot, thead, tr, th, td,
|
||||||
|
article, aside, canvas, details, embed,
|
||||||
|
figure, figcaption, footer, header, hgroup,
|
||||||
|
menu, nav, output, ruby, section, summary,
|
||||||
|
time, mark, audio, video {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
font-size: 100%;
|
||||||
|
font: inherit;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
/* HTML5 display-role reset for older browsers */
|
||||||
|
article, aside, details, figcaption, figure,
|
||||||
|
footer, header, hgroup, menu, nav, section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
body {
|
||||||
|
line-height: 1;
|
||||||
|
}
|
||||||
|
ol, ul {
|
||||||
|
list-style: none;
|
||||||
|
}
|
||||||
|
blockquote, q {
|
||||||
|
quotes: none;
|
||||||
|
}
|
||||||
|
blockquote:before, blockquote:after,
|
||||||
|
q:before, q:after {
|
||||||
|
content: '';
|
||||||
|
content: none;
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
border-collapse: collapse;
|
||||||
|
border-spacing: 0;
|
||||||
|
}
|
||||||
Binary file not shown.
|
|
@ -0,0 +1,97 @@
|
||||||
|
--SLF CONSTANTS
|
||||||
|
local CLASS = "GFMS_NUI"--This is the name that the logging framework will use to display your logs in the correct manner
|
||||||
|
local LOG_LEVEL = GetResourceMetadata(GetCurrentResourceName(), "log_level", 0)
|
||||||
|
local RESOURCE_CODE = GetResourceMetadata(GetCurrentResourceName(), "resource_code", 0)
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
---Used to send logs to the client console
|
||||||
|
---@param message any Preformatted message or VARIABLES to be sent to log
|
||||||
|
---@param logLevel integer Level of log, 1-Error, 2-Warn, 3-Info, 4-Debug
|
||||||
|
local function Log(message, logLevel)
|
||||||
|
local line = debug.getinfo(2, "l").currentline
|
||||||
|
local name = debug.getinfo(2, "n").name
|
||||||
|
if name == "fn" then
|
||||||
|
name = "Thread"
|
||||||
|
end
|
||||||
|
local value = "{"..CLASS.."."..name.."("..line..")} "..message
|
||||||
|
if logLevel then
|
||||||
|
if tonumber(LOG_LEVEL) >= logLevel then
|
||||||
|
exports.SLF:LogToClient(RESOURCE_CODE, logLevel, value)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
exports.SLF:LogToClient(RESOURCE_CODE, 4, value)
|
||||||
|
Log("Warning line was logged without a level value... Logged it as debug as that is the safest route.", 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
RegisterNetEvent(RESOURCE_CODE..":UpdateLogLevel")
|
||||||
|
AddEventHandler(RESOURCE_CODE..":UpdateLogLevel", function(num)
|
||||||
|
LOG_LEVEL = num
|
||||||
|
end)
|
||||||
|
-----------------------------------------------------------------------------------------------
|
||||||
|
--CONSTANTS--
|
||||||
|
|
||||||
|
--VARIABLES--
|
||||||
|
GFMS_SPLASH_IMG = GetResourceMetadata(GetCurrentResourceName(), "SPLASH_IMG", 0)
|
||||||
|
|
||||||
|
--FUNCTIONS--
|
||||||
|
local function ChangeImage(image)
|
||||||
|
print("Setting Up LoadSplash")
|
||||||
|
SendNUIMessage({
|
||||||
|
type = "setIMG",
|
||||||
|
value = image
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function DisplaySplash(bool)
|
||||||
|
SendNUIMessage({
|
||||||
|
type = "showSplash",
|
||||||
|
status = bool
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function DisplayLoadSplash(bool)
|
||||||
|
SendNUIMessage({
|
||||||
|
type = "showLoadingSplash",
|
||||||
|
status = bool
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--THREADS--
|
||||||
|
Citizen.CreateThread(function()
|
||||||
|
ChangeImage(GFMS_SPLASH_IMG)
|
||||||
|
end)
|
||||||
|
|
||||||
|
--NET EVENTS--
|
||||||
|
RegisterNetEvent(RESOURCE_CODE..':ShowStaticSplash')
|
||||||
|
AddEventHandler(RESOURCE_CODE..':ShowStaticSplash', function(bool)
|
||||||
|
Log("Displaying or Hiding Static Splash Screen", 4)
|
||||||
|
DisplaySplash(bool)
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNetEvent(RESOURCE_CODE..':ShowLoadingSplash')
|
||||||
|
AddEventHandler(RESOURCE_CODE..':ShowLoadingSplash', function(bool)
|
||||||
|
Log("Displaying or Hiding Loading Splash Screen", 4)
|
||||||
|
DisplayLoadSplash(bool)
|
||||||
|
end)
|
||||||
|
|
||||||
|
RegisterNetEvent(RESOURCE_CODE..":ChangeImage")
|
||||||
|
AddEventHandler(RESOURCE_CODE..":ChangeImage", function(image)
|
||||||
|
Log("Changing Splash Image", 4)
|
||||||
|
ChangeImage(image)
|
||||||
|
end)
|
||||||
|
|
||||||
|
|
||||||
|
--COMMANDS--
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--Setup the splash image on script load
|
||||||
|
|
||||||
|
|
||||||
|
-- Show and hide the splash without spinner
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
fx_version 'adamant'
|
||||||
|
game 'gta5'
|
||||||
|
name '${resourceName}'
|
||||||
|
description '${description}'
|
||||||
|
author 'CSTMChristina & KJ4LXC'
|
||||||
|
version '0.0.1'
|
||||||
|
--this is a working script
|
||||||
|
resource_code '${resourceCode}'
|
||||||
|
log_level '4'
|
||||||
|
bucket_prefix '9'
|
||||||
|
SPLASH_IMG 'https://images.cstm.games/imgstor/splashscreens/defaultsplash.png'
|
||||||
|
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
'SLF',
|
||||||
|
'SCF',
|
||||||
|
'SDB',
|
||||||
|
'SPH'
|
||||||
|
}
|
||||||
|
|
||||||
|
files {
|
||||||
|
'client/html/index.html',
|
||||||
|
'client/html/sounds/*.ogg',
|
||||||
|
'client/config/*.json',
|
||||||
|
'client/html/loadsplash.html',
|
||||||
|
'client/html/loadsplash.js',
|
||||||
|
'client/html/loadsplash.css',
|
||||||
|
'client/html/reset.css'
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_page 'client/html/loadsplash.html'
|
||||||
|
|
||||||
|
-- shared_scripts {
|
||||||
|
-- 'shared/*.lua'
|
||||||
|
-- }
|
||||||
|
|
||||||
|
client_scripts {
|
||||||
|
'@menuv/menuv.lua',
|
||||||
|
'menus/*.lua',
|
||||||
|
'client/*.lua'
|
||||||
|
}
|
||||||
|
|
||||||
|
server_scripts {
|
||||||
|
'server/*.lua'
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
--SLF CONSTANTS
|
||||||
|
local CLASS = "CHANGEME"--This is the name that the logging framework will use to display your logs in the correct manner
|
||||||
|
local LOG_LEVEL = GetResourceMetadata(GetCurrentResourceName(), "log_level", 0)
|
||||||
|
local RESOURCE_CODE = GetResourceMetadata(GetCurrentResourceName(), "resource_code", 0)
|
||||||
|
------------------------------------------------------------------------------------------------
|
||||||
|
---Used to send logs to the server console
|
||||||
|
---@param message any Preformatted message or VARIABLES to be sent to log
|
||||||
|
---@param logLevel integer Level of log, 1-Error, 2-Warn, 3-Info, 4-Debug
|
||||||
|
local function Log(message, logLevel)
|
||||||
|
local line = debug.getinfo(2, "l").currentline
|
||||||
|
local name = debug.getinfo(2, "n").name
|
||||||
|
if name == "fn" then
|
||||||
|
name = "Thread"
|
||||||
|
end
|
||||||
|
local value = "{"..CLASS.."."..name.."("..line..")} "..message
|
||||||
|
if logLevel then
|
||||||
|
if tonumber(LOG_LEVEL) >= logLevel then
|
||||||
|
exports.SLF:LogToServer(RESOURCE_CODE, logLevel, value)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
exports.SLF:LogToServer(RESOURCE_CODE, 4, value)
|
||||||
|
Log("Warning line was logged without a level value... Logged it as debug as that is the safest route.", 1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
RegisterNetEvent(RESOURCE_CODE..":UpdateLogLevel")
|
||||||
|
AddEventHandler(RESOURCE_CODE..":UpdateLogLevel", function(num)
|
||||||
|
LOG_LEVEL = num
|
||||||
|
end)
|
||||||
|
------------------------------------------------------------------------------------------------
|
||||||
|
--CONSTANTS--
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--VARIABLES--
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--FUNCTIONS--
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--THREADS--
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--NET EVENTS--
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
--COMMANDS--
|
||||||
|
|
||||||
|
|
||||||
Loading…
Reference in New Issue