Auth System
This commit is contained in:
+169
-12
@@ -2,8 +2,12 @@ import { Rpc } from '@entityseven/rage-fw-rpc';
|
||||
|
||||
const rpc = new Rpc();
|
||||
let browser: BrowserMp | null = null;
|
||||
let cursorVisible = true;
|
||||
let adminLevel = 0;
|
||||
let noclipActive = false;
|
||||
let noclipCamera: CameraMp | null = null;
|
||||
|
||||
// Initialize CEF via standard RAGE MP event to bootstrap the browser for RPC
|
||||
// Initialize CEF via standard RAGE MP event
|
||||
mp.events.add('client:initCef', (cefUrl: string, isDebug: boolean) => {
|
||||
if (isDebug) {
|
||||
mp.gui.chat.push(`[Client] Initializing CEF: ${cefUrl}`);
|
||||
@@ -15,37 +19,190 @@ mp.events.add('client:initCef', (cefUrl: string, isDebug: boolean) => {
|
||||
}
|
||||
|
||||
browser = mp.browsers.new(cefUrl);
|
||||
rpc.browser = browser; // Link immediately
|
||||
rpc.browser = browser;
|
||||
|
||||
mp.gui.chat.push(`[Client] Browser created and linked to RPC`);
|
||||
mp.gui.chat.show(false);
|
||||
mp.gui.cursor.show(true, true);
|
||||
cursorVisible = true;
|
||||
|
||||
mp.players.local.freezePosition(true);
|
||||
});
|
||||
|
||||
// Fallback: auto-link any newly created browser if current is null
|
||||
// Fallback: auto-link browser
|
||||
mp.events.add('browserCreated', (b: BrowserMp) => {
|
||||
if (!rpc.browser) {
|
||||
rpc.browser = b;
|
||||
mp.gui.chat.push(`[Client] RPC Browser auto-linked via browserCreated`);
|
||||
}
|
||||
mp.gui.chat.show(false);
|
||||
});
|
||||
|
||||
// Custom Chat Handlers via RPC
|
||||
rpc.register('chat:toggleInput', (state: boolean) => {
|
||||
// This allows you to freeze other inputs while typing if you build a UI manager later
|
||||
// ─────────────── Keybinds ───────────────────
|
||||
|
||||
// Backtick (`) — toggle cursor
|
||||
mp.keys.bind(0xC0, true, () => {
|
||||
cursorVisible = !cursorVisible;
|
||||
mp.gui.cursor.show(cursorVisible, cursorVisible);
|
||||
});
|
||||
|
||||
// F2 — toggle admin noclip
|
||||
mp.keys.bind(0x71, true, async () => {
|
||||
if (adminLevel <= 0) return;
|
||||
|
||||
try {
|
||||
const result: any = await rpc.callServer('server:admin:noclip', []);
|
||||
if (!result || !result.allowed) return;
|
||||
|
||||
noclipActive = result.active;
|
||||
|
||||
if (noclipActive) {
|
||||
enableNoclip();
|
||||
} else {
|
||||
disableNoclip();
|
||||
}
|
||||
} catch (err) {
|
||||
// silently fail
|
||||
}
|
||||
});
|
||||
|
||||
// ─────────────── Noclip Logic ───────────────
|
||||
|
||||
let isNoClip = false;
|
||||
let noClipPos: Vector3Mp | null = null;
|
||||
|
||||
function enableNoclip() {
|
||||
isNoClip = true;
|
||||
noClipPos = mp.players.local.position;
|
||||
|
||||
mp.players.local.freezePosition(true);
|
||||
mp.players.local.setInvincible(true);
|
||||
mp.players.local.setVisible(false, false);
|
||||
mp.players.local.setCollision(false, false);
|
||||
|
||||
mp.gui.cursor.show(false, false);
|
||||
cursorVisible = false;
|
||||
}
|
||||
|
||||
function disableNoclip() {
|
||||
isNoClip = false;
|
||||
|
||||
if (noClipPos) {
|
||||
mp.players.local.setCoordsNoOffset(noClipPos.x, noClipPos.y, noClipPos.z, false, false, false);
|
||||
noClipPos = null;
|
||||
}
|
||||
|
||||
mp.players.local.freezePosition(false);
|
||||
mp.players.local.setInvincible(false);
|
||||
mp.players.local.setVisible(true, false);
|
||||
mp.players.local.setCollision(true, false);
|
||||
}
|
||||
|
||||
// Math helpers
|
||||
function getCamDirection() {
|
||||
const rot = mp.game.cam.getGameplayCamRot(2);
|
||||
const z = rot.z * (Math.PI / 180.0);
|
||||
const x = rot.x * (Math.PI / 180.0);
|
||||
const num = Math.abs(Math.cos(x));
|
||||
|
||||
return new mp.Vector3(
|
||||
-Math.sin(z) * num,
|
||||
Math.cos(z) * num,
|
||||
Math.sin(x)
|
||||
);
|
||||
}
|
||||
|
||||
mp.events.add('render', () => {
|
||||
if (!isNoClip || !noClipPos) return;
|
||||
|
||||
// Fast movement using Shift
|
||||
let speed = 1.0;
|
||||
if (mp.keys.isDown(0x10)) speed = 3.0; // Shift
|
||||
if (mp.keys.isDown(0x11)) speed = 0.2; // Ctrl
|
||||
|
||||
// We do NOT disable controls — we let the user look around natively
|
||||
// But we override position manually.
|
||||
|
||||
const dir = getCamDirection();
|
||||
|
||||
// W = Forward
|
||||
if (mp.keys.isDown(0x57)) {
|
||||
noClipPos.x += dir.x * speed;
|
||||
noClipPos.y += dir.y * speed;
|
||||
noClipPos.z += dir.z * speed;
|
||||
}
|
||||
// S = Backward
|
||||
if (mp.keys.isDown(0x53)) {
|
||||
noClipPos.x -= dir.x * speed;
|
||||
noClipPos.y -= dir.y * speed;
|
||||
noClipPos.z -= dir.z * speed;
|
||||
}
|
||||
|
||||
// A = Left
|
||||
if (mp.keys.isDown(0x41)) {
|
||||
noClipPos.x += dir.y * speed;
|
||||
noClipPos.y -= dir.x * speed;
|
||||
}
|
||||
// D = Right
|
||||
if (mp.keys.isDown(0x44)) {
|
||||
noClipPos.x -= dir.y * speed;
|
||||
noClipPos.y += dir.x * speed;
|
||||
}
|
||||
// Space = Up
|
||||
if (mp.keys.isDown(0x20)) {
|
||||
noClipPos.z += speed;
|
||||
}
|
||||
|
||||
// We use direct position assignment instead of setCoordsNoOffset
|
||||
// Function calls to natives in a render loop cause massive FPS drops on low-end hardware
|
||||
// because they force physics recalculations. Assignment skips some hooks.
|
||||
mp.players.local.position = noClipPos;
|
||||
});
|
||||
|
||||
// ─────────────── Auth Handlers ──────────────
|
||||
|
||||
rpc.register('auth:login', (email: string, password: string) => {
|
||||
return rpc.callServer('server:auth:login', [email, password]);
|
||||
});
|
||||
|
||||
rpc.register('auth:register', (email: string, password: string, firstName: string, lastName: string) => {
|
||||
return rpc.callServer('server:auth:register', [email, password, firstName, lastName]);
|
||||
});
|
||||
|
||||
rpc.register('client:authSuccess', (rpName: string, level: number) => {
|
||||
adminLevel = level || 0;
|
||||
|
||||
mp.players.local.freezePosition(false);
|
||||
mp.gui.cursor.show(false, false);
|
||||
cursorVisible = false;
|
||||
|
||||
rpc.callBrowser('app:showGame', []).catch(() => {});
|
||||
});
|
||||
|
||||
// Save credentials to RAGE:MP local storage
|
||||
rpc.register('client:saveCredentials', (email: string, password: string) => {
|
||||
mp.storage.data.auth = { email, password };
|
||||
mp.storage.flush();
|
||||
});
|
||||
|
||||
// Load saved credentials from RAGE:MP local storage
|
||||
rpc.register('client:loadCredentials', () => {
|
||||
const auth = mp.storage.data.auth;
|
||||
if (auth && auth.email) {
|
||||
return { email: auth.email, password: auth.password || '' };
|
||||
}
|
||||
return null;
|
||||
});
|
||||
|
||||
// ─────────────── Chat Handlers ──────────────
|
||||
|
||||
rpc.register('chat:toggleInput', (state: boolean) => {});
|
||||
|
||||
rpc.register('chat:sendMessage', (msg: string) => {
|
||||
// Send the message natively to the server via our RPC
|
||||
rpc.callServer('server:chat:receive', [msg]);
|
||||
});
|
||||
|
||||
// Listen for structured chat broadcasts from the server (Player chat)
|
||||
rpc.register('chat:push:custom', (chatData: any) => {
|
||||
rpc.callBrowser('chat:addMessage', [chatData]);
|
||||
});
|
||||
|
||||
// Listen for incoming native string messages from the server (System prints/announcements)
|
||||
mp.events.add('chat:push', (text: string) => {
|
||||
rpc.callBrowser('chat:addMessage', [{ type: 'system', text: text }]);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user