Compare commits

..

9 Commits

Author SHA1 Message Date
Chase Eller 07714e6e63
Update 1.1.6
Build & Release VS Code Extension / release (push) Successful in 23s Details
2026-04-11 19:29:48 -04:00
Chase Eller dd3a7330d3
Updating for new snipets
Build & Release VS Code Extension / release (push) Successful in 20s Details
2026-03-25 18:58:21 -04:00
Chase Eller 224b610aac
SLF Updates
Build & Release VS Code Extension / release (push) Successful in 20s Details
2026-03-25 17:41:35 -04:00
Chase Eller 8252d42b6a
Coding Update
Build & Release VS Code Extension / release (push) Successful in 18s Details
- Updated snippets for SLF to align with new coding processes
- Updated templates for resource builder to build to new coding process
2026-03-24 21:55:24 -04:00
Chase Eller 659ef72d68
cleanup of old code
Build & Release VS Code Extension / release (push) Successful in 23s Details
2026-03-24 21:18:29 -04:00
Chase Eller 36885c446a
stupid fix
Build & Release VS Code Extension / release (push) Failing after 18s Details
2026-03-24 21:14:57 -04:00
Chase Eller 03e495a8ba
Delete .vscodeignore 2026-03-24 21:14:26 -04:00
Chase Eller 9e54158bb6
Create .gitignore 2026-03-24 21:13:02 -04:00
Chase Eller c7c97e4ae5
Dev Update
Build & Release VS Code Extension / release (push) Failing after 18s Details
2026-03-24 21:03:43 -04:00
31 changed files with 1155 additions and 78 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
.vscodeignore

View File

@ -1,11 +0,0 @@
.vscode/**
.vscode-test/**
src/**
.gitignore
.yarnrc
vsc-extension-quickstart.md
**/tsconfig.json
**/eslint.config.mjs
**/*.map
**/*.ts
**/.vscode-test.*

View File

@ -17,3 +17,24 @@ I will use this area to keep up with what i did last.
## [Release 1.0.11]
- 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

View File

@ -8,5 +8,29 @@ A collection of custom Lua snippets for FiveM development.
- Thread templates
- Common FiveM utilities
## Usage
## Snippet Usage
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.

View File

@ -39,6 +39,7 @@ exports.activate = activate;
exports.deactivate = deactivate;
const vscode = __importStar(require("vscode"));
const updater_1 = require("./updater");
const resourceGenerator_1 = require("./resourceGenerator");
// ================= LOGGING SETUP =================
exports.updaterOutput = vscode.window.createOutputChannel("Updater Startup");
function logDebug(...args) {
@ -50,12 +51,14 @@ function logDebug(...args) {
exports.updaterOutput.show(true);
}
function activate(context) {
logDebug("[Extension] Activating extension..."); // test log
logDebug("[Extension] Activating extension...");
// Run automatic updater
(0, updater_1.runUpdater)(context);
// Register manual update check command
const disposable = vscode.commands.registerCommand("kj4lxc.cstmgames.fivem_snippets.checkUpdates", () => (0, updater_1.manualUpdateCheck)(context));
// Register manual update command
const disposable = vscode.commands.registerCommand("kj4lxc.cstmgames.fivem_devtools.autoUpdate", () => (0, updater_1.manualUpdateCheck)(context));
context.subscriptions.push(disposable);
// Register resource generator
(0, resourceGenerator_1.registerResourceGenerator)(context);
}
function deactivate() { }
//# sourceMappingURL=extension.js.map

View File

@ -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"}

164
out/resourceGenerator.js Normal file
View File

@ -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

View File

@ -0,0 +1 @@
{"version":3,"file":"resourceGenerator.js","sourceRoot":"","sources":["../src/resourceGenerator.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAwCA,8DAWC;AAnDD,+CAAiC;AACjC,2BAAyE;AACzE,2CAA6B;AAE7B,IAAI,qBAAqB,GAAG,EAAE,CAAC;AAC/B,IAAI,cAAc,GAAG,KAAK,CAAC,CAAC,iBAAiB;AAW7C,MAAM,SAAS,GAA+B;IAC1C,YAAY,EAAE;QACV,KAAK,EAAE,eAAe;QACtB,WAAW,EAAE,iDAAiD;QAC9D,SAAS,EAAE,cAAc;QACzB,KAAK,EAAE,EAAE;KACZ;IACD,YAAY,EAAE;QACV,KAAK,EAAE,eAAe;QACtB,WAAW,EAAE,gCAAgC;QAC7C,SAAS,EAAE,aAAa;QACxB,KAAK,EAAE,EAAE;KACZ;IACD,WAAW,EAAE;QACT,KAAK,EAAE,sBAAsB;QAC7B,WAAW,EAAE,sBAAsB;QACnC,SAAS,EAAE,EAAE;QACb,KAAK,EAAE,EAAE;KACZ;CACJ,CAAC;AAEF,MAAM,UAAU,GAAG,cAAc,CAAC;AAElC,qDAAqD;AACrD,SAAgB,yBAAyB,CAAC,OAAgC;IACtE,qBAAqB,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;IAErE,MAAM,UAAU,GAAG,MAAM,CAAC,QAAQ,CAAC,eAAe,CAC9C,gCAAgC,EAChC,CAAC,GAAe,EAAE,EAAE;QAChB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IAC5B,CAAC,CACJ,CAAC;IAEF,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AAC3C,CAAC;AAED,iDAAiD;AACjD,SAAS,UAAU,CAAC,YAAqB;IACrC,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC;QAE7B,KAAK,CAAC,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QAC7C,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;QAChC,KAAK,CAAC,KAAK,CAAC,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;QAE5C,KAAK,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,EAAE;YACzB,IAAI,KAAK,CAAC,KAAM,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACvC,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC,KAAM,CAAC,KAAK,CAAC;gBACjC,KAAK,CAAC,KAAM,CAAC,IAAI,EAAE,CAAC;gBAEpB,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;oBAClB,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,KAAM,CAAC,IAAI,EAAE,CAAC;gBAC7C,CAAC;qBAAM,CAAC;oBACJ,iBAAiB,CAAC,YAAY,CAAC,CAAC,CAAC,aAAa;gBAClD,CAAC;YACL,CAAC;iBAAM,CAAC;gBACJ,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAC1B,oCAAoC,KAAK,CAAC,KAAK,IAAI,CACtD,CAAC;YACN,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,IAAI,GAAG,KAAK,UAAU,EAAE,CAAC;YACrB,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QACvB,CAAC;IACL,CAAC;AACL,CAAC;AAED,qDAAqD;AACrD,KAAK,UAAU,iBAAiB,CAAC,YAAqB;IAClD,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,aAAa,CAC5C,CAAC,KAAK,EAAE,IAAI,CAAC,EACb;QACI,WAAW,EAAE,sBAAsB;KACtC,CACJ,CAAC;IAEF,IAAI,CAAC,MAAM,EAAE,CAAC;QACV,MAAM,CAAC,MAAM,CAAC,kBAAkB,CAAC,sBAAsB,CAAC,CAAC;QACzD,OAAO;IACX,CAAC;IAED,cAAc,GAAG,MAAM,KAAK,KAAK,CAAC;IAElC,eAAe,CAAC,YAAY,CAAC,CAAC;AAClC,CAAC;AAED,iDAAiD;AACjD,SAAS,eAAe,CAAC,QAAiB;IACtC,IAAI,CAAC,QAAQ,EAAE,CAAC;QACZ,MAAM,CAAC,MAAM,CAAC,gBAAgB,CAAC,qBAAqB,CAAC,CAAC;QACtD,OAAO;IACX,CAAC;IAED,MAAM,MAAM,GAAG,kBAAkB,CAAC,EAAE,CAAC,CAAC;IAEtC,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAEvE,IAAA,cAAS,EAAC,YAAY,CAAC,CAAC;IACxB,WAAW,CAAC,YAAY,EAAE,MAAM,CAAC,CAAC;IAElC,MAAM,CAAC,MAAM,CAAC,sBAAsB,CAChC,oDAAoD,SAAS,CAAC,YAAY,CAAC,KAAK,IAAI,CACvF,CAAC;AACN,CAAC;AASD,SAAS,MAAM,CAAC,GAAW;IACvB,OAAO;QACH,GAAG;QACH,KAAK,EAAE,EAAE;QACT,OAAO,EAAE,EAAE;KACd,CAAC;AACN,CAAC;AAED,sDAAsD;AACtD,SAAS,kBAAkB,CAAC,GAAW;IACnC,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IAE3B,qCAAqC;IACrC,MAAM,gBAAgB,GAAG,cAAc;QACnC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,qBAAqB,EAAE,aAAa,CAAC;QACjD,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAC;IAE/C,MAAM,KAAK,GAAG,IAAA,gBAAW,EAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,GAAG,CAAC,EAAE;QACxD,aAAa,EAAE,IAAI;KACtB,CAAC,CAAC;IAEH,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACrB,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,kBAAkB,CAC1C,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,CAC5B,CAAC;QACN,CAAC;aAAM,CAAC;YACJ,IAAI,OAAO,GAAG,IAAA,iBAAY,EACtB,IAAI,CAAC,IAAI,CAAC,gBAAgB,EAAE,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,EAC3C,OAAO,CACV,CAAC;YAEF,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;gBAC1B,OAAO,GAAG,OAAO,CAAC,OAAO,CACrB,IAAI,MAAM,CAAC,SAAS,GAAG,KAAK,EAAE,GAAG,CAAC,EAClC,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,CACvB,CAAC;YACN,CAAC;YAED,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC;QACtC,CAAC;IACL,CAAC;IAED,OAAO,MAAM,CAAC;AAClB,CAAC;AAED,kDAAkD;AAClD,SAAS,WAAW,CAAC,GAAW,EAAE,MAAkB;IAChD,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAC7B,IAAA,kBAAa,EAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,CAAC;IACnE,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QAC/B,MAAM,aAAa,GAAG,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAC1C,IAAA,cAAS,EAAC,aAAa,CAAC,CAAC;QAEzB,WAAW,CAAC,aAAa,EAAE,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IACpD,CAAC;AACL,CAAC"}

View File

@ -46,7 +46,7 @@ const os = __importStar(require("os"));
const path = __importStar(require("path"));
const node_fetch_1 = __importDefault(require("node-fetch"));
// ================= LOGGING SETUP =================
exports.updaterOutput = vscode.window.createOutputChannel("Updater");
exports.updaterOutput = vscode.window.createOutputChannel("CSTMGames Updater");
function logDebug(...args) {
const message = args
.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");
try {
logDebug("[Updater] Downloading VSIX from:", url);
// Fetch the VSIX
const res = await (0, node_fetch_1.default)(url);
if (!res.ok)
throw new Error(`HTTP ${res.status}`);
const buffer = Buffer.from(await res.arrayBuffer());
// Save to temp file
fs.writeFileSync(tmpFile, buffer);
logDebug("[Updater] VSIX saved to temp file:", tmpFile);
// Install extension from local file
await vscode.commands.executeCommand("workbench.extensions.installExtension", vscode.Uri.file(tmpFile));
logDebug("[Updater] Installed VSIX from temp file");
// Ask user to reload
const reload = await vscode.window.showInformationMessage("Extension updated successfully.", "Reload Now");
if (reload === "Reload Now") {
await vscode.commands.executeCommand("workbench.action.reloadWindow");
}
// ✅ Optional short delay (prevents race conditions)
await new Promise(resolve => setTimeout(resolve, 1500));
vscode.window.showInformationMessage("Extension updated successfully. Reloading...");
// ✅ AUTO reload VS Code (this restarts extensions)
await vscode.commands.executeCommand("workbench.action.reloadWindow");
}
catch (err) {
logDebug("[Updater] Install failed:", err);
vscode.window.showErrorMessage("Failed to install update.");
}
finally {
// Clean up temp file
try {
if (fs.existsSync(tmpFile)) {
fs.unlinkSync(tmpFile);

File diff suppressed because one or more lines are too long

View File

@ -1,15 +1,19 @@
{
"name": "cstmgames-fivem-snippets",
"displayName": "CSTMGames FiveM Snippets",
"description": "Snippets for FiveM",
"version": "1.0.11",
"displayName": "CSTMGames FiveM Dev Tools",
"description": "Development tools for FiveM",
"version": "1.1.6",
"author": {
"name": "Chase Eller",
"email": "chase@cstmgames.com",
"url": "https://cstmgames.com"
},
"engines": {
"vscode": "^1.110.0"
},
"main": "./out/extension.js",
"activationEvents": [
"onStartupFinished",
"onCommand:cstmgames.fivem_snippets.checkUpdates"
"onStartupFinished"
],
"icon": "pridelogo.png",
"repository": {
@ -29,14 +33,26 @@
],
"commands": [
{
"command": "kj4lxc.cstmgames.fivem_snippets.checkUpdates",
"title": "Check for Snippet Updates"
"command": "kj4lxc.cstmgames.fivem_devtools.autoUpdate",
"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": {
"title": "Snippets Updater",
"title": "CSTMGames FiveM Dev Tools Updater",
"properties": {
"cstmgames.fivem_snippets.autoUpdate": {
"cstmgames.fivem_devtools.autoUpdate": {
"type": "boolean",
"default": true,
"description": "Automatically install updates"

View File

@ -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": {
"prefix": "Log",
"body": "Log(\"${1:Your Log Message Here}\", ${2|4,3,2,1|})$0",
"description": "Sets up basic Log function for use with SLF"
},
"Log to Discord": {
"prefix": "DisLog",
"prefix": "DisLogCall",
"body": "DisLog(\"${1:Your Error Text Here}\")$0",
"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": {
"prefix": "thread",
"body": [
@ -48,39 +54,77 @@
],
"description": "Sets up command to be registered"
},
"Server Side SLF Function": {
"prefix": "slfserver",
"SLF Functions and Vars for server.": {
"prefix": "SLFSERVER",
"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 name = debug.getinfo(2, \"n\").name",
" if name == \"fn\" then",
" name = \"Thread\"",
" end",
" local value = \"{\"..CLASS..\".\"..name..\"(\"..line..\")} \"..message",
" if tonumber(LOG_LEVEL) >= logLevel then",
" exports.SLF:LogToServer(RESOURCE_CODE, logLevel, value)",
" 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"
"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": {
"prefix": "slfclient",
"SLF Functions and Vars for client.": {
"prefix": "SLFCLIENT",
"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 name = debug.getinfo(2, \"n\").name",
" if name == \"fn\" then",
" name = \"Thread\"",
" end",
" local value = \"{\"..CLASS..\".\"..name..\"(\"..line..\")} \"..message",
" if tonumber(LOG_LEVEL) >= logLevel then",
" exports.SLF:LogToClient(RESOURCE_CODE, logLevel, value)",
" 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"
"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": {
"prefix": "tce",
@ -174,5 +218,35 @@
"end)"
],
"description": "Thread Net Register"
},
"Coding Regions": {
"prefix": "regions",
"body": [
"--CONSTANTS--",
"",
"",
"",
"--VARIABLES--",
"",
"",
"",
"--FUNCTIONS--",
"",
"",
"",
"--THREADS--",
"",
"",
"",
"--NET EVENTS--",
"",
"",
"",
"--COMMANDS--",
"",
"",
""
],
"description": "Coding Regions"
}
}

View File

@ -1,5 +1,6 @@
import * as vscode from "vscode";
import { runUpdater, manualUpdateCheck } from "./updater";
import { registerResourceGenerator } from "./resourceGenerator";
// ================= LOGGING SETUP =================
export const updaterOutput = vscode.window.createOutputChannel("Updater Startup");
@ -14,17 +15,20 @@ export function logDebug(...args: any[]) {
}
export function activate(context: vscode.ExtensionContext) {
logDebug("[Extension] Activating extension..."); // test log
logDebug("[Extension] Activating extension...");
// Run automatic updater
runUpdater(context);
// Register manual update check command
// Register manual update command
const disposable = vscode.commands.registerCommand(
"kj4lxc.cstmgames.fivem_snippets.checkUpdates",
"kj4lxc.cstmgames.fivem_devtools.autoUpdate",
() => manualUpdateCheck(context)
);
context.subscriptions.push(disposable);
// Register resource generator
registerResourceGenerator(context);
}
export function deactivate() {}

189
src/resourceGenerator.ts Normal file
View File

@ -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]);
}
}

View File

@ -7,7 +7,7 @@ import fetch from "node-fetch";
// ================= LOGGING SETUP =================
export const updaterOutput = vscode.window.createOutputChannel("Updater");
export const updaterOutput = vscode.window.createOutputChannel("CSTMGames Updater");
export function logDebug(...args: any[]) {
const message = args
@ -152,38 +152,35 @@ async function installVsix(url: string) {
try {
logDebug("[Updater] Downloading VSIX from:", url);
// Fetch the VSIX
const res = await fetch(url);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
const buffer = Buffer.from(await res.arrayBuffer());
// Save to temp file
fs.writeFileSync(tmpFile, buffer);
logDebug("[Updater] VSIX saved to temp file:", tmpFile);
// Install extension from local file
await vscode.commands.executeCommand(
"workbench.extensions.installExtension",
vscode.Uri.file(tmpFile)
);
logDebug("[Updater] Installed VSIX from temp file");
// Ask user to reload
const reload = await vscode.window.showInformationMessage(
"Extension updated successfully.",
"Reload Now"
// ✅ Optional short delay (prevents race conditions)
await new Promise(resolve => setTimeout(resolve, 1500));
vscode.window.showInformationMessage(
"Extension updated successfully. Reloading..."
);
if (reload === "Reload Now") {
await vscode.commands.executeCommand("workbench.action.reloadWindow");
}
// ✅ AUTO reload VS Code (this restarts extensions)
await vscode.commands.executeCommand("workbench.action.reloadWindow");
} catch (err) {
logDebug("[Updater] Install failed:", err);
vscode.window.showErrorMessage("Failed to install update.");
} finally {
// Clean up temp file
try {
if (fs.existsSync(tmpFile)) {
fs.unlinkSync(tmpFile);

View File

@ -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.

View File

@ -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--

View File

@ -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'
}

View File

@ -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--

View File

View File

@ -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.

View File

@ -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--

View File

@ -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; }
}

View File

@ -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>

View File

@ -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)
})

View File

@ -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.

View File

@ -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

View File

@ -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'
}

View File

@ -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--

View File