feat: WS sends selected_game_id on connect, gear indicator auto-adapts to game mapping (Forza/AC/iRacing)

This commit is contained in:
2026-07-25 16:29:00 +08:00
parent 636801b6a3
commit 7959d911e6
3 changed files with 68 additions and 19 deletions
+60 -17
View File
@@ -46,6 +46,60 @@ html,body{width:100%;height:100%;overflow:hidden;background:#000;
</div></div></div>
<script>
const M={aspect_ratio:"1:1",render_mode:"contain",gear_style:"auto"};
let GAME_ID='';
// Forza: 0=R, 1-8=1-8 (no neutral in UDP)
// AC/F1: -1=R, 0=N, 1-8=1-8
// iRacing: 0=N, 1=R, 2=1st... (offset +2)
function gearLabel(g){
if(!g&&g!==0)return'-';
const style=M.gear_style||'auto';
const isForza=GAME_ID&&(GAME_ID.includes('forza'));
const isIRacing=GAME_ID&&GAME_ID.includes('iracing');
if(style==='forza'||isForza){
if(g===0)return'R';
if(g>=1&&g<=8)return String(g);
return String(g);
}
if(style==='ac'||(!isForza&&!isIRacing)){
if(g===-1)return'R';
if(g===0)return'N';
if(g>=1&&g<=8)return String(g);
return String(g);
}
if(isIRacing){
if(g===0)return'N';
if(g===1)return'R';
if(g>=2&&g<=9)return String(g-1);
return String(g);
}
// fallback
if(g===0)return'N';
if(g>0)return String(g);
return String(g);
}
function gearBarIndex(g){
if(!g&&g!==0)return-1;
const isForza=GAME_ID&&GAME_ID.includes('forza');
const isIRacing=GAME_ID&&GAME_ID.includes('iracing');
if(isForza){
if(g===0)return 0; // R at index 0
if(g>=1&&g<=8)return g+1; // 1->2
}
if(isIRacing){
if(g===0)return 1; // N at index 1
if(g===1)return 0; // R at index 0
if(g>=2&&g<=9)return g; // 2->2(index for '1')
}
// AC/F1/default
if(g===-1)return 0; // R
if(g===0)return 1; // N
if(g>=1&&g<=8)return g+1; // 1->2
return -1;
}
(function(){
const box=document.getElementById('box'),gearTxt=document.getElementById('gear-txt'),
gearEl=document.getElementById('gear-el'),barRow=document.getElementById('bar-row');
@@ -91,21 +145,8 @@ const M={aspect_ratio:"1:1",render_mode:"contain",gear_style:"auto"};
function updateGear(g){
if(g===lastGear)return;lastGear=g;
// Determine mapping based on actual gear value
let label,activeIndex;
if(g<0){// AC style: negative is reverse
label='R';activeIndex=0;
}else if(g===0){
// ambiguous: could be R (Forza) or N (AC)
// Show R by default for Forza, but check gear_style
label='R';activeIndex=0;
}else{
// Forward gear: g is 1-based in Forza, but some games might use 0-based
label=String(g);
if(g>=1&&g<=8)activeIndex=g+1; // gear 1 -> index 2
else activeIndex=-1;
}
const label=gearLabel(g);
const activeIndex=gearBarIndex(g);
gearTxt.textContent=label;
gearEl.className='gear-circle active';
@@ -131,8 +172,10 @@ const M={aspect_ratio:"1:1",render_mode:"contain",gear_style:"auto"};
}
function connect(){
ws=new WebSocket(wsUrl);ws.onopen=()=>{if(rt){clearTimeout(rt);rt=null}};
ws.onmessage=(e)=>{try{const m=JSON.parse(e.data);if(m.type==='telemetry')updateGear(m.data.gear||0)}catch(e){}};
ws=new WebSocket(wsUrl);ws.onopen=()=>{if(rt){clearTimeout(rt);rt=null}};
ws.onmessage=(e)=>{try{const m=JSON.parse(e.data);
if(m.type==='connected'){GAME_ID=m.selected_game_id||'';console.log('[Gear] game:',GAME_ID)}
if(m.type==='telemetry')updateGear(m.data.gear||0)}catch(e){}};
ws.onclose=()=>{rt=setTimeout(connect,2000)};
}