Skip to content
23 changes: 9 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,36 +1,30 @@
# rebar-adminpanel

> [!IMPORTANT]
> It's required that you go to your Rebar directory
> and set up some things first before using the rebar-adminpanel plugin
> Please read all installation steps to prevent unwanted behaviour

## Installation
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/S6S3171498)

1. Go to your Rebar `main` server's directory and then to `./webview/src/index.css`
2. Add following code at the end of `index.css`
## Installation

```css
.neon-button {
@apply w-full rounded-lg border-2 border-transparent px-4 py-3 text-left text-sm text-gray-200 hover:animate-pulse hover:border-red-500 hover:bg-opacity-75 hover:shadow-md;
}
```
1. Go to your Rebar `main` server's directory.

3. Now clone this repository in to your Rebar `main` directory using git commands.
2. Now clone this repository in to your Rebar `main` directory using git commands.

```bash
cd path/to/your/rebar-altv/
git clone https://github.com/programmernb-ctrl/rebar-adminpanel.git src/plugins/rebar-adminpanel
```

4. Should your character don't have the admin group you'll need to customize the config in `./shared/config.ts`
3. If your character doesn't already have the admin group, you'll need to customize the config in `./shared/config.ts`

```typescript
export const adminpanelConfig = {
adminMode: true, // true to see webview even if you don't got the admin group. mostly required to setup the plugin
};
```

5. Start the server once by using one of the below commands. The plugin will load __automatically.__
4. Start the server once by using one of the below commands. The plugin will load __automatically.__

```
pnpm start
Expand All @@ -57,7 +51,8 @@ cd path/to/your/rebar-altv/src/plugins/rebar-adminpanel
git pull
```

- If you forked this repo and wanna update it, simply search for `merge from upstream` on [Google](https://www.google.com)
- If you forked this repo and want to update it, simply search for `merge from upstream` on [Google](https://www.google.
com)

## Dependencies

Expand Down
154 changes: 121 additions & 33 deletions server/index.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,47 @@
import * as alt from 'alt-server';
import { useRebar } from '@Server/index.js';
import { adminpanelConfig } from '@Plugins/rebar-adminpanel/shared/config.js';
import { adminPanelEvents } from '@Plugins/rebar-adminpanel/shared/events.js';
import { adminpanelEvents } from '@Plugins/rebar-adminpanel/shared/events.js';

const Rebar = useRebar();
const keyBinding = Rebar.useKeybinder();
const getter = Rebar.get.usePlayersGetter();
const Keybinder = Rebar.useKeybinder();
const worldGetter = Rebar.get.useWorldGetter();

const syncedBinder = Rebar.systems.useStreamSyncedBinder();
syncedBinder.syncCharacterKey('cash');
syncedBinder.syncCharacterKey('bank');

if (adminpanelConfig.Settings.debug) {
alt.log('[rebar-adminpanel] Debug Mode is activated for the plugin.')
alt.logWarning(
'[rebar-adminpanel] Debug Mode is still activated. Consider disable it to prevent unwanted' + ' behaviour',
);
}

let keybinding = undefined;
async function showView(player: alt.Player) {
keybinding = keyBinding.on(adminpanelEvents.bindings.F4, () => {
adminpanelShow(player);
});
}

/**
* Checks if the player is a member of the 'admin' group, if true continue with showing the webview
* @param player to show the webview to | alt.Player
*/
async function adminpanelShow(player: alt.Player) {
// useWebview(player).show('Adminpanel', 'page', true);
if (!player?.valid) {
return;
}

const character = Rebar.document.character.useCharacter(player);
const isMember = character.groups.memberOf('admin');
// const hasPermission = Rebar.permissions.usePermissions(player).hasPermission('adminpanel');

if (isMember || adminpanelConfig.Settings.adminMode) {
const view = Rebar.player.useWebview(player);
Rebar.player.useWorld(player).disableControls();
Rebar.player.useAudio(player).playFrontendSound('Click_Special', 'WEB_NAVIGATION_SOUNDS_PHONE');
view.show('Adminpanel', 'page');
} else {
return;
Expand All @@ -28,21 +51,37 @@ async function adminpanelShow(player: alt.Player) {
async function adminpanelHide(player: alt.Player) {
const view = Rebar.player.useWebview(player);
view.hide('Adminpanel');
Rebar.player.useAudio(player).playFrontendSound('Click_Fail', 'WEB_NAVIGATION_SOUNDS_PHONE');
Rebar.player.useWorld(player).enableControls();
}

async function makeAdmin(player: alt.Player) {
const rPlayer = Rebar.usePlayer(player);
async function adminpanelHideUser(player: alt.Player) {
const view = Rebar.player.useWebview(player);

rPlayer.character.groups.add('admin');
rPlayer.account.permissions.grant('admin');
view.hide('Users');
Rebar.player.useAudio(player).playFrontendSound('Click_Fail', 'WEB_NAVIGATION_SOUNDS_PHONE');
Rebar.player.useWorld(player).enableControls();
}

async function getAdmin(player: alt.Player) {
const character = Rebar.document.character.useCharacter(player);
const hasGroup = character.groups.memberOf('admin');

if (!hasGroup) {
alt.log('[rebar-adminpanel] The admin group is now being added to your character!');
await character.groups.add('admin');
} else {
alt.logWarning('[rebar-adminpanel] No need to get it again... You already got the admin group.');
return;
}
}

async function adminpanelShowAllUsers(player: alt.Player) {
// useWebview(player).show('Adminpanel', 'page', true);
const playersOnline = getter.online();
const view = Rebar.player.useWebview(player);

Rebar.player.useWorld(player).disableControls();
Rebar.player.useAudio(player).playFrontendSound('Click_Special', 'WEB_NAVIGATION_SOUNDS_PHONE');

view.show('Users', 'persistent');

Expand All @@ -51,58 +90,107 @@ async function adminpanelShowAllUsers(player: alt.Player) {
name: p.name,
discordId: p.discordID,
}));
view.emit(adminPanelEvents.WebView.getUsers, playerDetails);

view.emit(adminpanelEvents.webview.getUsers, playerDetails);
}

async function adminpanelHideUser(player: alt.Player) {
const view = Rebar.player.useWebview(player);
view.hide('Users');
Rebar.player.useWorld(player).enableControls();
/**
* Gets the waypoint set by the player and then teleports them to the new position
* @param player the player to teleport to the marker
*/
async function adminpanelTpMarker(player: alt.Player) {
if (!player?.valid) return;

const rPlayer = Rebar.usePlayer(player);
const waypoint = await Rebar.usePlayer(player).waypoint.get();

if (!waypoint) {
return;
}

const interval = alt.setInterval(async () => {
rPlayer.native.invoke('setFocusPosAndVel', waypoint.x, waypoint.y, waypoint.z, 0.0, 0.0, 0.0);

const groundZResponse = await rPlayer.native.invokeWithResult(
'getGroundZFor3dCoord',
waypoint.x,
waypoint.y,
waypoint.z,
1000,
false,
false,
);

if (groundZResponse[0] === true && typeof groundZResponse[1] === 'number') {
const groundZ = groundZResponse[1];

alt.clearInterval(interval);

rPlayer.native.invoke('requestCollisionAtCoord', waypoint.x, waypoint.y, groundZ);

const nextTick = alt.nextTick(async () => {
player.frozen = true;
alt.log(player.dimension);
rPlayer.native.invoke('clearFocus');
player.pos = new alt.Vector3(waypoint.x, waypoint.y, groundZ);
player.frozen = false;
rPlayer.notify.showNotification('Teleported successfully');
alt.clearNextTick(nextTick);
});
} else {
alt.clearInterval(interval);
rPlayer.native.invoke('clearFocus');
return;
}
}, 1000);
}

alt.onRpc(adminPanelEvents.RPC.giveAdmin, async (player: alt.Player) => {
alt.onRpc(adminpanelEvents.rpc.giveAdmin, async (player: alt.Player) => {
try {
alt.log(`${player.name} called adminpanel:giveadmin rpc`);
await makeAdmin(player);
await getAdmin(player);
} catch (error) {
alt.log(`${player.name} called adminpanel rpc but got an error ${error}`);
alt.log(`${player.name} called adminpanel:giveadmin rpc but with an error ${error}`);
}
});

alt.onRpc(adminPanelEvents.RPC.toWaypoint, async (player: alt.Player, x: number, y: number, z: number) => {
alt.onRpc(adminpanelEvents.rpc.toWaypoint, async (player: alt.Player, x: number, y: number, z: number) => {
const isClear = await worldGetter.positionIsClear(new alt.Vector3(x, y, z), 'all');

try {
alt.log(`${player.name} called adminpanel:towaypoint rpc with coords: ${x}, ${y}, ${z}`);

if (player && player.valid) {
if (player && player.valid && isClear) {
player.pos = new alt.Vector3(x, y, z); // Teleport the player
alt.log(`${player.name} has been teleported to coordinates`);
} else {
alt.log(`Invalid player attempted to teleport: ${player.name}`);
alt.log(`Invalid player attempted to teleport: ${player.name} or new position is not clear.`);
}
} catch (error) {
alt.log(`${player.name} encountered an error: ${error}`);
} catch (err) {
alt.log(`${player.name} encountered an error with adminpanel:towaypoint rpc: ${err}`);
}
});

alt.onRpc(adminPanelEvents.RPC.showAllUsers, async (player: alt.Player) => {
alt.onRpc(adminpanelEvents.rpc.showAllUsers, async (player: alt.Player) => {
await adminpanelShowAllUsers(player);
});

alt.onClient(adminPanelEvents.ToServer.closePanel, async (player: alt.Player) => {
alt.onClient(adminpanelEvents.toServer.closePanel, async (player: alt.Player) => {
await adminpanelHide(player);
});

alt.onClient(adminPanelEvents.ToServer.closeUsers, async (player: alt.Player) => {
alt.onClient(adminpanelEvents.toServer.closeUsers, async (player: alt.Player) => {
await adminpanelHideUser(player);
await adminpanelShow(player);
});

alt.once('playerSpawn', async () => {
await showView();
alt.onClient(adminpanelEvents.toServer.tpMarker, async (player: alt.Player) => {
await adminpanelTpMarker(player);
});

async function showView() {
Keybinder.on(adminPanelEvents.KeyCodes.f4, (player) => {
adminpanelShow(player);
});
};
alt.on('playerConnect', async (player: alt.Player) => {
await showView(player);
});

alt.on('playerDisconnect', async (player: alt.Player) => {
keyBinding.off(adminpanelEvents.bindings.F4, keybinding);
});
2 changes: 1 addition & 1 deletion shared/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ export const adminpanelConfig = {
debug: false,
adminMode: false,
}
};
};
25 changes: 13 additions & 12 deletions shared/events.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
export const adminPanelEvents = {
ToServer: {
export const adminpanelEvents = {
toClient: {},
toServer: {
closePanel: 'adminpanel:close',
closeUsers: 'adminpanel:closeUsers',
closeUsers: 'adminpanel:close:users',
tpMarker: 'adminpanel:teleport:marker:hud',
},
WebView: {
webview: {
closeAdminpanelCallback: 'adminpanel',
closeUserpanelCallback: 'adminpanel:users',
getUsers: 'adminpanel:getUsers',

getUsers: 'adminpanel:get:users',
},
RPC: {
showAllUsers: 'adminpanel:showAllUsers',
giveAdmin: 'adminpanel:giveadmin',
rpc: {
showAllUsers: 'adminpanel:show:all:users',
giveAdmin: 'adminpanel:admin',
toWaypoint: 'adminpanel:towaypoint',
},
KeyCodes: {
escape: 27,
f4: 115,
bindings: {
ESC: 27,
F4: 115,
}
};
Loading
Loading