Formatos KV: fMassa=1600,0, fMassa 1600,0, ou <fMass value="1600.0"/>.
Saída
Usar Copiar saída ou Baixar XML.
Notas: As estimativas são indicativas. Teste no jogo. Os valores persistem localmente (localStorage).
Tração integral/tração traseira: fDriveBiasFront → 0 = RWD, 1 = FWD, 0,5 = AWD.
Privacidade: 100% do lado do cliente. Nenhum dado sai da página.
`;
}
function toXML(){
const x=(k,v)=>` `;
const body = Object.keys(FIELDS).map(k=>x(k,state[k]??”)).join(‘\n’);
const header = ”; /* avoid ‘<?xml' */
return `${header}
${body}
`;
}
function toKV(){
return Object.keys(FIELDS).map(k=>{
const v = state[k]??”; return `${k}=${typeof v===’number’?Number(v).toFixed(6):v}`;
}).join(‘\n’);
}
function parseXML(text){
try{
const doc = new DOMParser().parseFromString(text,’application/xml’);
if(doc.querySelector(‘parsererror’)) return null;
const next = {…state};
Object.keys(FIELDS).forEach(k=>{
const el = doc.querySelector(k); if(!el) return;
let val = el.getAttribute(‘value’); if(val==null) val = el.textContent;
if(val==null) return;
const meta = FIELDS[k];
if(meta.type===’text’) next[k] = String(val).trim();
else { const n = Number(val); if(!isNaN(n)) next[k]=n; }
});
return next;
}catch(e){ return null; }
}
function parseKV(text){
const next = {…state};
const lines = text.split(/\r?\n/).map(s=>s.trim()).filter(Boolean);
for(const line of lines){
let m = line.match(/^\s*([a-zA-Z0-9_]+)\s*=\s*(“?)([^”]+)\2\s*$/)
|| line.match(/^\s*([a-zA-Z0-9_]+)\s+([^\s]+)\s*$/)
|| line.match(/^\s*]*\bvalue\s*=\s*”(.*?)”[^>]*\/?>\s*$/);
if(!m) continue;
const key = m[1], val = m[3] ?? m[2];
if(!(key in FIELDS)) continue;
const meta = FIELDS[key];
if(meta.type===’text’) next[key]=String(val).trim();
else { const n = Number(val); if(!isNaN(n)) next[key]=n; }
}
return next;
}
function setState(next){
state = {…state, …next};
save(); renderFields(); renderMetrics();
}
function download(filename,content){
const blob = new Blob([content],{type:’application/xml;charset=utf-8′});
const url = URL.createObjectURL(blob);
const a = document.createElement(‘a’); a.href=url; a.download=filename; a.click();
setTimeout(()=>URL.revokeObjectURL(url),5000);
}
document.getElementById(‘fhe-root’).addEventListener(‘click’, (e)=>{
const btn = e.target.closest(‘.fhe-btn’); if(!btn) return;
const a = btn.getAttribute(‘data-action’);
if(a===’reset’){ setState({…DEFAULTS}); document.getElementById(‘fhe-output’).value=”; document.getElementById(‘fhe-import’).value=”; }
if(a===’save’){ save(); btn.textContent=’Saved’; setTimeout(()=>btn.textContent=’Save’,900); }
if(a===’load-example’){
setState({
HandlingName:’GODMODEX’,
fMass:1450,fInitialDragCoeff:6.4,fPercentSubmerged:85,fDriveBiasFront:0.05,nInitialDriveGears:7,
fInitialDriveForce:0.40,fDriveInertia:1.15,fClutchChangeRateScaleUpShift:3.2,fClutchChangeRateScaleDownShift:2.6,
fInitialDriveMaxFlatVel:165,fBrakeForce:1.10,fHandBrakeForce:0.9,fSteeringLock:38.0,fTractionCurveMax:2.45,
fTractionCurveMin:2.20,fSuspensionForce:2.7,fSuspensionCompDamp:1.5,fSuspensionReboundDamp:1.8,
fRollCentreHeightFront:0.32,fRollCentreHeightRear:0.32
});
}
if(a===’export-xml’){ document.getElementById(‘fhe-output’).value = toXML(); document.getElementById(‘fhe-output’).scrollIntoView({behavior:’smooth’,block:’center’}); }
if(a===’export-kv’){ document.getElementById(‘fhe-output’).value = toKV(); document.getElementById(‘fhe-output’).scrollIntoView({behavior:’smooth’,block:’center’}); }
if(a===’copy-output’){
const ta = document.getElementById(‘fhe-output’);
if(!ta.value) ta.value = toXML();
ta.select(); document.execCommand(‘copy’);
btn.textContent=’Copied’; setTimeout(()=>btn.textContent=’Copy Output’,900);
}
if(a===’download-xml’){ const xml = toXML(); const name = (state.HandlingName||’handling’) + ‘.xml’; download(name, xml); }
});
document.querySelector(‘#fhe-root [data-action=”import-xml”]’).addEventListener(‘click’, ()=>{
const txt = document.getElementById(‘fhe-import’).value.trim(); if(!txt){ alert(‘Paste XML into the Import box.’); return; }
const next = parseXML(txt); if(!next){ alert(‘Could not parse XML.’); return; }
setState(next);
});
document.querySelector(‘#fhe-root [data-action=”import-kv”]’).addEventListener(‘click’, ()=>{
const txt = document.getElementById(‘fhe-import’).value.trim(); if(!txt){ alert(‘Paste KV lines into the Import box.’); return; }
const next = parseKV(txt); setState(next);
});
renderFields();
renderMetrics();
})();
Lucas
Eu sou Luke, sou um gamer e adoro escrever sobre FiveM, GTA e roleplay. Eu administro uma comunidade de roleplay e tenho cerca de 10 anos de experiência em administração de servidores.