Quaternius weapons, input fixes, sound & path fixes
- Added 6 Quaternius weapon models (Pistol, Revolver, Rifle, Shotgun, P90, SniperRifle) - Created weapon resource files with balanced stats - Wired Pistol + Rifle into player.tscn replacing Kenney blasters - Fixed WASD input (matched input map action names) - Fixed Escape key toggles mouse capture - Added Audio autoload singleton - Fixed broken sound asset paths across all scripts - Fixed all scene ext_resource text paths (nested under assets/kenney-fps/) - Fixed all .import source_file paths - Deleted stale .import files (will be regenerated by editor on open)
This commit is contained in:
Vendored
+124
@@ -0,0 +1,124 @@
|
||||
import { readFileSync, writeFileSync } from 'fs';
|
||||
/**
|
||||
* Matches an empty `[autoload]` section (the header followed by only blank
|
||||
* lines, up to the next section header or end-of-file). Used by cleanup paths
|
||||
* to drop the section after the last entry is removed.
|
||||
*/
|
||||
export const EMPTY_AUTOLOAD_SECTION_REGEX = /\[autoload\]\s*(?=\n\[|\n*$)/g;
|
||||
/**
|
||||
* Mirrors the parser's `\w+` assumption (parseAutoloads / removeAutoloadEntry).
|
||||
* Enforced on write paths to prevent a name with newlines or INI section
|
||||
* delimiters from corrupting project.godot.
|
||||
*/
|
||||
export const VALID_AUTOLOAD_NAME_REGEX = /^\w+$/;
|
||||
function assertValidName(name) {
|
||||
if (!VALID_AUTOLOAD_NAME_REGEX.test(name)) {
|
||||
throw new Error(`Invalid autoload name '${name}': must contain only word characters (letters, digits, underscore)`);
|
||||
}
|
||||
}
|
||||
export function normalizeAutoloadPath(p) {
|
||||
return p.startsWith('res://') ? p : `res://${p}`;
|
||||
}
|
||||
export function parseAutoloads(projectFilePath, existingContent) {
|
||||
const content = existingContent ?? readFileSync(projectFilePath, 'utf8');
|
||||
const autoloads = [];
|
||||
let inAutoloadSection = false;
|
||||
for (const line of content.split('\n')) {
|
||||
const trimmed = line.trim();
|
||||
if (trimmed.startsWith('[')) {
|
||||
inAutoloadSection = trimmed === '[autoload]';
|
||||
continue;
|
||||
}
|
||||
if (!inAutoloadSection || trimmed === '' || trimmed.startsWith(';') || trimmed.startsWith('#'))
|
||||
continue;
|
||||
// The surrounding `"?` are intentional: Godot always writes quotes, but
|
||||
// hand-edited project.godot files sometimes omit them. Tolerating both
|
||||
// shapes means a missing quote pair doesn't silently drop the entry.
|
||||
const match = trimmed.match(/^(\w+)="?(\*?)([^"]*?)"?$/);
|
||||
if (match) {
|
||||
autoloads.push({ name: match[1], singleton: match[2] === '*', path: match[3] });
|
||||
}
|
||||
}
|
||||
return autoloads;
|
||||
}
|
||||
export function addAutoloadEntry(projectFilePath, name, path, singleton, existingContent) {
|
||||
assertValidName(name);
|
||||
const content = existingContent ?? readFileSync(projectFilePath, 'utf8');
|
||||
const lines = content.split('\n');
|
||||
const entry = `${name}="${singleton ? '*' : ''}${normalizeAutoloadPath(path)}"`;
|
||||
const sectionIdx = lines.findIndex((l) => l.trim() === '[autoload]');
|
||||
if (sectionIdx === -1) {
|
||||
writeFileSync(projectFilePath, content.trimEnd() + '\n\n[autoload]\n' + entry + '\n', 'utf8');
|
||||
return;
|
||||
}
|
||||
let insertIdx = sectionIdx + 1;
|
||||
while (insertIdx < lines.length && !lines[insertIdx].trim().startsWith('[')) {
|
||||
insertIdx++;
|
||||
}
|
||||
lines.splice(insertIdx, 0, entry);
|
||||
writeFileSync(projectFilePath, lines.join('\n'), 'utf8');
|
||||
}
|
||||
/**
|
||||
* Remove the named autoload entry. Also drops the `[autoload]` section header
|
||||
* if the removed entry was the last one in it. Returns true when the file was
|
||||
* mutated.
|
||||
*/
|
||||
export function removeAutoloadEntry(projectFilePath, name) {
|
||||
const content = readFileSync(projectFilePath, 'utf8');
|
||||
const lines = content.split('\n');
|
||||
let inAutoloadSection = false;
|
||||
let removed = false;
|
||||
const filtered = lines.filter((line) => {
|
||||
const trimmed = line.trim();
|
||||
if (trimmed.startsWith('[')) {
|
||||
inAutoloadSection = trimmed === '[autoload]';
|
||||
return true;
|
||||
}
|
||||
if (inAutoloadSection) {
|
||||
const match = trimmed.match(/^(\w+)=/);
|
||||
if (match && match[1] === name) {
|
||||
removed = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
if (!removed)
|
||||
return false;
|
||||
let newContent = filtered.join('\n');
|
||||
newContent = newContent.replace(EMPTY_AUTOLOAD_SECTION_REGEX, '');
|
||||
newContent = newContent.trimEnd() + '\n';
|
||||
writeFileSync(projectFilePath, newContent, 'utf8');
|
||||
return true;
|
||||
}
|
||||
export function updateAutoloadEntry(projectFilePath, name, newPath, singleton) {
|
||||
assertValidName(name);
|
||||
const content = readFileSync(projectFilePath, 'utf8');
|
||||
const lines = content.split('\n');
|
||||
let inAutoloadSection = false;
|
||||
let updated = false;
|
||||
const newLines = lines.map((line) => {
|
||||
const trimmed = line.trim();
|
||||
if (trimmed.startsWith('[')) {
|
||||
inAutoloadSection = trimmed === '[autoload]';
|
||||
return line;
|
||||
}
|
||||
if (inAutoloadSection) {
|
||||
// The surrounding `"?` are intentional: Godot always writes quotes, but
|
||||
// hand-edited project.godot files sometimes omit them. Tolerating both
|
||||
// shapes means a missing quote pair doesn't silently drop the entry.
|
||||
const match = trimmed.match(/^(\w+)="?(\*?)([^"]*?)"?$/);
|
||||
if (match && match[1] === name) {
|
||||
const effectiveSingleton = singleton !== undefined ? singleton : match[2] === '*';
|
||||
const effectivePath = newPath !== undefined ? normalizeAutoloadPath(newPath) : match[3];
|
||||
updated = true;
|
||||
return `${name}="${effectiveSingleton ? '*' : ''}${effectivePath}"`;
|
||||
}
|
||||
}
|
||||
return line;
|
||||
});
|
||||
if (updated)
|
||||
writeFileSync(projectFilePath, newLines.join('\n'), 'utf8');
|
||||
return updated;
|
||||
}
|
||||
//# sourceMappingURL=autoload-ini.js.map
|
||||
Reference in New Issue
Block a user