diff --git a/YabosRageMPCore.sql b/YabosRageMPCore.sql
new file mode 100644
index 0000000..4f21bb4
--- /dev/null
+++ b/YabosRageMPCore.sql
@@ -0,0 +1,68 @@
+-- phpMyAdmin SQL Dump
+-- version 5.2.2
+-- https://www.phpmyadmin.net/
+--
+-- Host: dns.burnednodes.ge
+-- Generation Time: Apr 01, 2026 at 03:48 AM
+-- Server version: 10.6.22-MariaDB-0ubuntu0.22.04.1
+-- PHP Version: 8.4.18
+
+SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
+START TRANSACTION;
+SET time_zone = "+00:00";
+
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8mb4 */;
+
+--
+-- Database: `YabosRageMPCore`
+--
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `users`
+--
+
+CREATE TABLE `users` (
+ `id` int(11) NOT NULL,
+ `email` varchar(255) NOT NULL,
+ `password` varchar(255) NOT NULL,
+ `created_at` timestamp NOT NULL DEFAULT current_timestamp(),
+ `name` varchar(24) NOT NULL DEFAULT '',
+ `lastname` varchar(24) NOT NULL DEFAULT '',
+ `hardwareid` varchar(128) DEFAULT '',
+ `ip` varchar(64) DEFAULT '',
+ `adminLvl` int(11) DEFAULT 0,
+ `social` varchar(128) DEFAULT '',
+ `socialid` varchar(128) DEFAULT ''
+) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
+
+--
+-- Indexes for dumped tables
+--
+
+--
+-- Indexes for table `users`
+--
+ALTER TABLE `users`
+ ADD PRIMARY KEY (`id`),
+ ADD UNIQUE KEY `email` (`email`);
+
+--
+-- AUTO_INCREMENT for dumped tables
+--
+
+--
+-- AUTO_INCREMENT for table `users`
+--
+ALTER TABLE `users`
+ MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=4;
+COMMIT;
+
+/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
+/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
+/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
diff --git a/develop_cef/src/App.vue b/develop_cef/src/App.vue
index 8152d81..4f945ba 100644
--- a/develop_cef/src/App.vue
+++ b/develop_cef/src/App.vue
@@ -1,13 +1,29 @@
-
+
+
diff --git a/develop_client/src/index.ts b/develop_client/src/index.ts
index 705c458..14575f5 100644
--- a/develop_client/src/index.ts
+++ b/develop_client/src/index.ts
@@ -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 }]);
});