The addHints
function modifies Quake 3 map files by adding boundary or hint information, either based on the map's name or a provided pattern, likely for purposes like skybox placement or collision detection.
npm run import -- "draw hints in map"
var path = require('path')
var importer = require('../Core')
var {getBounds} = importer.import("add skybox to map")
var MAPS_HINTS = {
'base1-a': [
[-648, -209],
[-648, 235],
[-400, 235],
[-400, 514],
[300, 514],
[300, 1922],
[9999, 1922],
[9999, -9999],
[-648, -9999],
[-648, -209]
],
'base1-b': [
[-648, -209],
[-648, 235],
[-400, 235],
[-400, 514],
[300, 514],
[300, 1922],
[-1300, 2174],
[-1300, 648],
[-648, -209],
],
'base1-c': [
[-1300, 1000],
[-1300, 2174],
[-9999, 9999],
[-9999, 1000],
[-1300, 1000],
],
'base2-a': [
[-1212, 1242],
[340, 1242],
[340, 1030],
[1324, 1030],
[1324, 3109],
[-1212, 3109],
[-1212, 1242]
],
'base2-b': [
[-1212, 1242],
[340, 1242],
[340, 1030],
[1324, 1030],
[1324, -1711],
[736, -1711],
[736, -1251],
[-1212, -1251],
[-1212, 1242]
],
'base2-c': [
[1324, 1030],
[1324, -1711],
[736, -1711],
[736, -1251],
[-1212, -1251],
[-1212, -2815],
[1324, -2815],
[1324, 1030],
]
}
function addHints(fileName, hints) {
var file
if(typeof fileName === 'string' && fs.existsSync(fileName)) {
file = fs.readFileSync(fileName).toString('utf-8')
if(!hints) {
hints = path.basename(fileName).replace(/[-_]converted|\.map$/ig, '')
}
} else {
file = fileName
}
if(!Array.isArray(hints)) {
var exp = new RegExp(hints, 'ig')
hints = Object.keys(MAPS_HINTS).reduce((arr, k) => {
if(k.match(exp)) {
arr.push(MAPS_HINTS[k])
}
return arr
}, [])
}
var brushes = importer.regexToArray(/\{[^\{}]*?\}\s*/ig, file)
/*
brushes.forEach(b => {
if(b.includes('/areaportal')) {
file = file.replace(b, '')
return false
}
return true
})
*/
var vs = getBounds(file)
var newBrush = ``
for(var h = 0; h < hints.length; h++) {
for(var i = 0; i < hints[h].length - 1; i++) {
var minX = Math.min(hints[h][i][0], hints[h][i+1][0]),
maxX = Math.max(hints[h][i][0], hints[h][i+1][0]),
minY = Math.min(hints[h][i][1], hints[h][i+1][1]),
maxY = Math.max(hints[h][i][1], hints[h][i+1][1])
var p1 = [minX, minY, vs[0][2]]
var p2 = [maxX+2, maxY+2, vs[1][2]]
newBrush += `
{ // brush 0
( ${p1[0]} ${p1[1]} ${p2[2]} ) ( ${p1[0]} ${p1[1]} ${p1[2]} ) ( ${p1[0]} ${p2[1]} ${p1[2]} ) common/hint 0 0 0 1 1 0 0 0
( ${p2[0]} ${p2[1]} ${p2[2]} ) ( ${p2[0]} ${p2[1]} ${p1[2]} ) ( ${p2[0]} ${p1[1]} ${p1[2]} ) common/hint 0 0 0 1 1 0 0 0
( ${p2[0]} ${p1[1]} ${p2[2]} ) ( ${p2[0]} ${p1[1]} ${p1[2]} ) ( ${p1[0]} ${p1[1]} ${p1[2]} ) common/hint 0 0 0 1 1 0 0 0
( ${p1[0]} ${p2[1]} ${p2[2]} ) ( ${p1[0]} ${p2[1]} ${p1[2]} ) ( ${p2[0]} ${p2[1]} ${p1[2]} ) common/hint 0 0 0 1 1 0 0 0
( ${p1[0]} ${p2[1]} ${p1[2]} ) ( ${p1[0]} ${p1[1]} ${p1[2]} ) ( ${p2[0]} ${p1[1]} ${p1[2]} ) common/hint 0 0 0 1 1 0 0 0
( ${p1[0]} ${p1[1]} ${p2[2]} ) ( ${p1[0]} ${p2[1]} ${p2[2]} ) ( ${p2[0]} ${p2[1]} ${p2[2]} ) common/hint 0 0 0 1 1 0 0 0
}
`
}
}
var exp = (/\{*\s*\/\/\s*brush\s*0\s*\{*/ig)
var match = exp.exec(file)
var pos = exp.lastIndex
file = file.substr(0, pos - match[0].length) + newBrush + file.substr(pos - match[0].length)
if(typeof fileName === 'string' && fs.existsSync(fileName)) {
console.log(`writing ${fileName}`)
fs.writeFileSync(fileName, file)
} else {
return file
}
}
module.exports = addHints
module.exports.addHints = addHints
module.exports.MAPS_HINTS = MAPS_HINTS
const fs = require('fs');
const path = require('path');
const importer = require('../Core');
const { getBounds } = importer.import('add skybox to map');
// Define map hints in a more readable format
const MAPS_HINTS = {
'base1-a': [
[-648, -209],
[-648, 235],
[-400, 235],
[-400, 514],
[300, 514],
[300, 1922],
[9999, 1922],
[9999, -9999],
[-648, -9999],
[-648, -209]
],
'base1-b': [
[-648, -209],
[-648, 235],
[-400, 235],
[-400, 514],
[300, 514],
[300, 1922],
[-1300, 2174],
[-1300, 648],
[-648, -209],
],
'base1-c': [
[-1300, 1000],
[-1300, 2174],
[-9999, 9999],
[-9999, 1000],
[-1300, 1000],
],
'base2-a': [
[-1212, 1242],
[340, 1242],
[340, 1030],
[1324, 1030],
[1324, 3109],
[-1212, 3109],
[-1212, 1242]
],
'base2-b': [
[-1212, 1242],
[340, 1242],
[340, 1030],
[1324, 1030],
[1324, -1711],
[736, -1711],
[736, -1251],
[-1212, -1251],
[-1212, 1242]
],
'base2-c': [
[1324, 1030],
[1324, -1711],
[736, -1711],
[736, -1251],
[-1212, -1251],
[-1212, -2815],
[1324, -2815],
[1324, 1030],
]
};
/**
* Add hints to a map file based on the provided map hints.
*
* @param {string} fileName The path to the map file or the file contents as a string.
* @param {string|Array<any>} hints A string or array of map hints to add.
* @returns {string} The updated map file contents.
*/
function addHints(fileName, hints) {
// Read the file contents if a file path is provided
let file;
if (typeof fileName ==='string' && fs.existsSync(fileName)) {
file = fs.readFileSync(fileName, 'utf-8');
// Extract the map hint name from the file name
const hintName = path.basename(fileName).replace(/[-_]converted|\.map$/ig, '');
// If no hints are provided, use the hint name as a regex to extract the map hint
if (!hints) {
hints = Object.keys(MAPS_HINTS).reduce((arr, k) => {
if (k.match(new RegExp(hintName, 'ig'))) {
arr.push(MAPS_HINTS[k]);
}
return arr;
}, []);
}
} else {
file = fileName;
}
// If the hints are a string, convert it to an array of map hints
if (!Array.isArray(hints)) {
const exp = new RegExp(hints, 'ig');
hints = Object.keys(MAPS_HINTS).reduce((arr, k) => {
if (k.match(exp)) {
arr.push(MAPS_HINTS[k]);
}
return arr;
}, []);
}
// Extract the brushes from the file contents
const brushes = importer.regexToArray(/\{[^\{}]*?\}\s*/ig, file);
// Remove any areaportal brushes
// TODO: Optimize this loop
// brushes.forEach((b) => {
// if (b.includes('/areaportal')) {
// file = file.replace(b, '');
// return false;
// }
// return true;
// });
// Get the bounds of the map
const vs = getBounds(file);
// Initialize the new brush contents
let newBrush = '';
// Iterate over each map hint and add a brush for each segment
hints.forEach((hint) => {
for (let i = 0; i < hint.length - 1; i++) {
const minX = Math.min(hint[i][0], hint[i + 1][0]);
const maxX = Math.max(hint[i][0], hint[i + 1][0]);
const minY = Math.min(hint[i][1], hint[i + 1][1]);
const maxY = Math.max(hint[i][1], hint[i + 1][1]);
const p1 = [minX, minY, vs[0][2]];
const p2 = [maxX + 2, maxY + 2, vs[1][2]];
// Add the brush contents for the current segment
newBrush += `
{ // brush 0
( ${p1[0]} ${p1[1]} ${p2[2]} ) ( ${p1[0]} ${p1[1]} ${p1[2]} ) ( ${p1[0]} ${p2[1]} ${p1[2]} ) common/hint 0 0 0 1 1 0 0 0
( ${p2[0]} ${p2[1]} ${p2[2]} ) ( ${p2[0]} ${p2[1]} ${p1[2]} ) ( ${p2[0]} ${p1[1]} ${p1[2]} ) common/hint 0 0 0 1 1 0 0 0
( ${p2[0]} ${p1[1]} ${p2[2]} ) ( ${p2[0]} ${p1[1]} ${p1[2]} ) ( ${p1[0]} ${p1[1]} ${p1[2]} ) common/hint 0 0 0 1 1 0 0 0
( ${p1[0]} ${p2[1]} ${p2[2]} ) ( ${p1[0]} ${p2[1]} ${p1[2]} ) ( ${p2[0]} ${p2[1]} ${p1[2]} ) common/hint 0 0 0 1 1 0 0 0
( ${p1[0]} ${p2[1]} ${p1[2]} ) ( ${p1[0]} ${p1[1]} ${p1[2]} ) ( ${p2[0]} ${p1[1]} ${p1[2]} ) common/hint 0 0 0 1 1 0 0 0
( ${p1[0]} ${p1[1]} ${p2[2]} ) ( ${p1[0]} ${p2[1]} ${p2[2]} ) ( ${p2[0]} ${p2[1]} ${p2[2]} ) common/hint 0 0 0 1 1 0 0 0
}
`;
}
});
// Insert the new brush contents into the file
const exp = /\{*\s*\/\/\s*brush\s*0\s*\{*/ig;
const match = exp.exec(file);
const pos = exp.lastIndex;
file = file.substr(0, pos - match[0].length) + newBrush + file.substr(pos - match[0].length);
// Write the updated file contents to the original file if necessary
if (typeof fileName ==='string' && fs.existsSync(fileName)) {
console.log(`writing ${fileName}`);
fs.writeFileSync(fileName, file);
} else {
return file;
}
}
module.exports = addHints;
module.exports.addHints = addHints;
module.exports.MAPS_HINTS = MAPS_HINTS;
This code snippet defines a function addHints
that adds hints to a Quake 3 map file based on its name or a provided pattern.
Here's a breakdown:
Initialization:
path
: Node.js module for working with file paths.importer
: A custom module likely containing utility functions for working with Quake 3 map files.getBounds
: A function imported from the add skybox to map
module (likely used for skybox-related calculations).MAPS_HINTS
: An object mapping map names (keys) to arrays of coordinates (values). These coordinates likely define the boundaries of the map for skybox placement.addHints
Function:
fileName
(the map file path) and hints
(an optional array of coordinates or a pattern to match map names).file
variable if fileName
is a valid string and the file exists.hints
is not provided, it tries to extract the map name from the fileName
and uses the corresponding coordinates from MAPS_HINTS
.hints
is not an array, it uses a regular expression to match the provided pattern against map names in MAPS_HINTS
and builds an array of coordinates accordingly.file
using a regular expression.hints
coordinates to the brush definition (the code snippet is incomplete).Purpose: