Lunar Client

Lunar Client with draggable title bars, crosshair editor, selectable stats (OS, CPU, FPS, Ping), autosave, glow, etc.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey, Greasemonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्क्रिप्ट व्यवस्थापक एक्स्टेंशन इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्क्रिप्ट व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्टाईल व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

// ==UserScript==
// @name         Lunar Client
// @namespace    https://deadshot.io/
// @version      1.0
// @description  Lunar Client with draggable title bars, crosshair editor, selectable stats (OS, CPU, FPS, Ping), autosave, glow, etc.
// @author       Aguy123
// @match        *://*/*
// @grant        none
// @run-at       document-idle
// ==/UserScript==

(function(){
'use strict';
if(window.lunarClientLoaded) return;
window.lunarClientLoaded = true;

const d=document, L=localStorage;

// --- Default state ---
const defaultState = {
  style:'Circle', overlay:'Dot', size:60, glow:10, color:'#00eaff',
  enabled:true, editorX:null, editorY:null, uiX:null, uiY:null
};
let state = JSON.parse(L.getItem('lc_state')) || defaultState;
function saveState(){ L.setItem('lc_state', JSON.stringify(state)); }

// --- Canvas for Crosshair ---
const canvas=d.createElement('canvas');
canvas.style=`position:fixed;top:0;left:0;width:100%;height:100%;pointer-events:none;z-index:2147483646;`;
d.body.appendChild(canvas);
const ctx=canvas.getContext('2d');
function resizeCanvas(){canvas.width=innerWidth;canvas.height=innerHeight;}
addEventListener('resize',resizeCanvas);resizeCanvas();

// --- Primary UI ---
const ui=d.createElement('div');
ui.style=`
  position:fixed;top:${state.uiY ?? 10}px;left:${state.uiX ?? 10}px;
  background:rgba(10,10,15,0.95);color:#00eaff;font-family:sans-serif;
  border-radius:10px;padding:6px;min-width:160px;max-width:160px;z-index:2147483647;position:relative;
`;
ui.innerHTML=`
  <div id="uiTitle" style="text-align:center;cursor:grab;margin-bottom:5px;font-weight:bold;">Lunar Client</div>
  <button id="btnEditor" style="width:100%;margin-bottom:3px;padding:4px;font-size:13px;">Crosshair Editor</button>
  <button id="btnStats" style="width:100%;margin-bottom:3px;padding:4px;font-size:13px;">Show Stats</button>
  <button id="btnStatsSettings" style="width:100%;margin-bottom:3px;padding:4px;font-size:13px;">Stats Settings</button>
  <button id="btnHide" style="width:100%;padding:4px;font-size:13px;">Hide UI</button>
`;
d.body.appendChild(ui);

// --- Crosshair Editor ---
const editor=d.createElement('div');
editor.style=`
  position:fixed;top:${state.editorY ?? 10}px;left:${state.editorX ?? (innerWidth-240)}px;
  background:rgba(20,20,30,0.95);color:#00eaff;font-family:sans-serif;
  border-radius:10px;padding:10px;min-width:220px;z-index:2147483647;
  cursor:default;display:none;
`;
editor.innerHTML=`
  <div id="editorTitle" style="text-align:center;cursor:grab;margin-bottom:6px;font-weight:bold;">Crosshair Editor</div>
  <div><label>Enabled:</label> <input type="checkbox" id="chToggle"></div>
  <div><label>Style:</label>
    <select id="chStyle">
      <option>None</option><option>Square</option><option>Circle</option>
      <option>Triangle</option><option>Pentagon</option><option>Four Corners</option>
    </select>
  </div>
  <div><label>Overlay:</label>
    <select id="chOverlay">
      <option>Dot</option><option>Plus</option><option>Cross</option><option>None</option>
    </select>
  </div>
  <div><label>Size: <span id="sizeVal">${state.size}</span></label><input type="range" id="chSize" min="5" max="200" style="width:100%;"></div>
  <div><label>Glow: <span id="glowVal">${state.glow}</span></label><input type="range" id="chGlow" min="0" max="50" style="width:100%;"></div>
  <div><label>Color:</label> <input type="color" id="chColor"></div>
  <button id="btnReset" style="width:100%;padding:5px;margin-top:5px;">Reset</button>
`;
d.body.appendChild(editor);

// --- Stats Panel ---
const stats=d.createElement('div');
stats.style=`
  position:fixed;right:10px;top:10px;background:rgba(0,0,0,0.6);color:#00eaff;
  padding:4px 6px;border-radius:6px;font-family:monospace;font-size:14px;
  z-index:2147483647;display:none;white-space:pre;
`;
stats.innerText='Stats:\n';
d.body.appendChild(stats);

// --- Show UI Button ---
const showBtn=d.createElement('button');
showBtn.textContent='Show UI';
showBtn.style=`
  position:fixed;top:10px;left:10px;background:rgba(20,20,30,0.9);
  color:#00eaff;border:none;border-radius:6px;padding:4px 8px;
  font-family:sans-serif;z-index:2147483647;display:none;
`;
d.body.appendChild(showBtn);

// --- Stats Settings Panel ---
const statsSettings=d.createElement('div');
statsSettings.style=`
  position:fixed;top:50px;left:10px;background:rgba(20,20,30,0.95);color:#00eaff;
  border-radius:10px;padding:10px;min-width:200px;z-index:2147483647;display:none;
`;
statsSettings.innerHTML=`
  <h4 style="text-align:center;margin:0 0 10px;">Stats Settings</h4>
  <div><input type="checkbox" id="selOS"> OS</div>
  <div><input type="checkbox" id="selCPU"> CPU</div>
  <div><input type="checkbox" id="selFPS"> FPS</div>
  <div><input type="checkbox" id="selPing"> Ping</div>
`;
d.body.appendChild(statsSettings);

// --- Draggable by title bars ---
function makeTitleDraggable(titleEl, targetEl, saveX, saveY){
 let drag=false, offX=0, offY=0;
 const start=e=>{
   const p=e.touches?e.touches[0]:e;
   drag=true; offX=p.clientX-targetEl.offsetLeft; offY=p.clientY-targetEl.offsetTop;
   titleEl.style.cursor='grabbing';
 };
 const move=e=>{
   if(!drag) return;
   const p=e.touches?e.touches[0]:e;
   let x=p.clientX-offX, y=p.clientY-offY;
   targetEl.style.left=x+'px'; targetEl.style.top=y+'px';
   saveX(x); saveY(y);
 };
 const stop=()=>{if(drag){drag=false;titleEl.style.cursor='grab'; saveState();}};
 titleEl.addEventListener('mousedown',start); titleEl.addEventListener('touchstart',start);
 addEventListener('mousemove',move); addEventListener('touchmove',move);
 addEventListener('mouseup',stop); addEventListener('touchend',stop);
}
makeTitleDraggable(d.getElementById('uiTitle'), ui, x=>state.uiX=x, y=>state.uiY=y);
makeTitleDraggable(d.getElementById('editorTitle'), editor, x=>state.editorX=x, y=>state.editorY=y);

// --- Button actions ---
d.getElementById('btnEditor').onclick=()=>editor.style.display=editor.style.display==='none'?'block':'none';
d.getElementById('btnStats').onclick=()=>stats.style.display=stats.style.display==='none'?'block':'none';
d.getElementById('btnStatsSettings').onclick=()=>statsSettings.style.display=statsSettings.style.display==='none'?'block':'none';
d.getElementById('btnHide').onclick=()=>{
 ui.style.display='none'; editor.style.display='none'; statsSettings.style.display='none';
 showBtn.style.display='block'; stats.style.display='block';
};
showBtn.onclick=()=>{ui.style.display='block'; showBtn.style.display='none';};

// --- Crosshair Inputs ---
const chToggle=d.getElementById('chToggle'),chStyle=d.getElementById('chStyle'),
chOverlay=d.getElementById('chOverlay'),chSize=d.getElementById('chSize'),
chGlow=d.getElementById('chGlow'),chColor=d.getElementById('chColor'),
sizeVal=d.getElementById('sizeVal'),glowVal=d.getElementById('glowVal'),
btnReset=d.getElementById('btnReset');

chToggle.checked=state.enabled;chStyle.value=state.style;chOverlay.value=state.overlay;
chSize.value=state.size;chGlow.value=state.glow;chColor.value=state.color;

function update(fn){fn();saveState();drawCrosshair();}
chToggle.onchange=()=>update(()=>state.enabled=chToggle.checked);
chStyle.onchange=()=>update(()=>state.style=chStyle.value);
chOverlay.onchange=()=>update(()=>state.overlay=chOverlay.value);
chSize.oninput=()=>update(()=>{state.size=+chSize.value;sizeVal.textContent=state.size;});
chGlow.oninput=()=>update(()=>{state.glow=+chGlow.value;glowVal.textContent=state.glow;});
chColor.oninput=()=>update(()=>state.color=chColor.value);
btnReset.onclick=()=>{state={...defaultState,editorX:editor.offsetLeft,editorY:editor.offsetTop,uiX:ui.offsetLeft,uiY:ui.offsetTop};saveState();location.reload();};

// --- Draw Crosshair ---
function drawCrosshair(){
 ctx.clearRect(0,0,canvas.width,canvas.height);
 if(!state.enabled)return;
 ctx.save();
 ctx.translate(canvas.width/2,canvas.height/2);
 ctx.strokeStyle=ctx.fillStyle=state.color;
 ctx.lineWidth=Math.max(1,Math.min(3,state.size/50));
 if(state.glow>0){ctx.shadowColor=state.color;ctx.shadowBlur=state.glow;}
 const s=state.size, cLen=Math.min(15,s/4);
 switch(state.style){
  case'Square':ctx.strokeRect(-s/2,-s/2,s,s);break;
  case'Circle':ctx.beginPath();ctx.arc(0,0,s/2,0,2*Math.PI);ctx.stroke();break;
  case'Triangle':ctx.beginPath();ctx.moveTo(0,-s/2);ctx.lineTo(s*Math.sqrt(3)/4,s/4);ctx.lineTo(-s*Math.sqrt(3)/4,s/4);ctx.closePath();ctx.stroke();break;
  case'Pentagon':ctx.beginPath();for(let i=0;i<5;i++){let a=i*2*Math.PI/5-Math.PI/2;let x=Math.cos(a)*s/2,y=Math.sin(a)*s/2;i?ctx.lineTo(x,y):ctx.moveTo(x,y);}ctx.closePath();ctx.stroke();break;
  case'Four Corners':
    ctx.beginPath();
    [[-1,-1],[1,-1],[-1,1],[1,1]].forEach(([x,y])=>{
      let sx=s/2*x,sy=s/2*y;
      ctx.moveTo(sx,sy);ctx.lineTo(sx-cLen*x,sy);
      ctx.moveTo(sx,sy);ctx.lineTo(sx,sy-cLen*y);
    });
    ctx.stroke();break;
 }
 ctx.shadowBlur=0;ctx.lineWidth=2;
 const oLen=Math.min(s/2,12);
 switch(state.overlay){
  case'Dot':ctx.beginPath();ctx.arc(0,0,2,0,2*Math.PI);ctx.fill();break;
  case'Plus':ctx.beginPath();ctx.moveTo(-oLen,0);ctx.lineTo(oLen,0);ctx.moveTo(0,-oLen);ctx.lineTo(0,oLen);ctx.stroke();break;
  case'Cross':ctx.beginPath();ctx.moveTo(-oLen,-oLen);ctx.lineTo(oLen,oLen);ctx.moveTo(oLen,-oLen);ctx.lineTo(-oLen,oLen);ctx.stroke();break;
 }
 ctx.restore();
}
requestAnimationFrame(function loop(){drawCrosshair();requestAnimationFrame(loop);});

// --- Stats / FPS / Ping ---
let frames=[], currentFPS=0, currentPing=0, lastPing=0;

// --- Stats selection (no Server) ---
let selectedStats = JSON.parse(L.getItem('lc_selectedStats')) || {OS:true, CPU:true, FPS:true, Ping:true};
for(const key in selectedStats){
    const cb=d.getElementById('sel'+key);
    if(cb) cb.checked=selectedStats[key];
    if(cb) cb.onchange=()=>{selectedStats[key]=cb.checked; L.setItem('lc_selectedStats',JSON.stringify(selectedStats));};
}

// --- Update Stats ---
function updateStats(){
    let lines=[];
    if(selectedStats.OS) lines.push(`OS: ${navigator.platform}`);
    if(selectedStats.CPU) lines.push(`CPU: ${navigator.hardwareConcurrency||'Unknown'} cores`);
    if(selectedStats.FPS) lines.push(`FPS: ${currentFPS}`);
    if(selectedStats.Ping) lines.push(`Ping: ${currentPing} ms`);
    stats.innerText = 'Stats:\n'+lines.join('\n');
}

// --- Stats Loop ---
(async function statsLoop(){
 const now=performance.now();frames.push(now);
 if(frames.length>60)frames.shift();
 currentFPS=Math.round((frames.length-1)/(frames[frames.length-1]-frames[0])*1000);

 if(now-lastPing>2000){
   lastPing=now;
   const start=now;
   try{await fetch('https://www.google.com/generate_204',{mode:'no-cors',cache:'no-store'}); currentPing=Math.round(performance.now()-start);}catch{currentPing='∞';}
 }
 updateStats();
 requestAnimationFrame(statsLoop);
})();
})();