Formats KV : fMasse=1600,0, fMasse 1600,0, ou <fMass value="1600.0"/>.
Sortir
Utiliser Copier la sortie ou Télécharger XML.
Remarques: Les estimations sont indicatives. Testez en jeu. Les valeurs sont conservées localement (localStorage).
Transmission intégrale/propulsion : fDriveBiasFront → 0 = propulsion, 1 = traction avant, 0,5 = traction intégrale.
Confidentialité: 100% côté client. Aucune donnée ne quitte la page.
`;
}
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();
})();
Luc
Je m'appelle Luke, je suis un joueur et j'adore écrire sur FiveM, GTA et le jeu de rôle. Je dirige une communauté de jeu de rôle et j'ai environ 10 ans d'expérience dans l'administration de serveurs.