Skip to content
This repository has been archived by the owner on Jun 5, 2024. It is now read-only.

Commit

Permalink
Move Systems to Session Storage
Browse files Browse the repository at this point in the history
  • Loading branch information
Stuyk committed Apr 16, 2023
1 parent f6f2a39 commit 58f66e0
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 147 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,14 @@ Dynamic Doors
- Dynamic doors can teleport to any dimension, or position.
- Dynamic doors also have onEnter, or beforeEnter callbacks for additional door functionality.
- Includes better handling of ytyp, and ipl loading; no more falling through map.
- Utilizes Session Storage
Drop Tables
- Create a drop table and pull random loot from it.
- Athena.systems.dropTable.get
Documents (Account, Character, Vehicle)
- Utilizes Session Storage
```

Expand Down
25 changes: 16 additions & 9 deletions src/core/server/controllers/dynamicDoors/cooldowns.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
import * as alt from 'alt-server';
import * as Athena from '@AthenaServer/api';

const cooldowns: { [id: string]: number } = {};
const SessionKey = 'athena-dd-cooldown-instance';

declare global {
namespace AthenaSession {
interface Player {
[SessionKey]: number;
}
}
}

/**
* Register a cooldown, with predetermiend
Expand All @@ -9,7 +18,7 @@ const cooldowns: { [id: string]: number } = {};
* @param {alt.Player} player
*/
export function updateCooldown(player: alt.Player) {
cooldowns[player.id] = Date.now() + 2000;
Athena.session.player.set(player, SessionKey, Date.now() + 2000);
}

/**
Expand All @@ -20,11 +29,11 @@ export function updateCooldown(player: alt.Player) {
* @return {*}
*/
export function isCooldownDone(player: alt.Player) {
if (!cooldowns[player.id]) {
if (!Athena.session.player.has(player, SessionKey)) {
return true;
}

return Date.now() > cooldowns[player.id];
return Date.now() > Athena.session.player.get(player, SessionKey);
}

/**
Expand All @@ -34,7 +43,7 @@ export function isCooldownDone(player: alt.Player) {
* @param {alt.Player} player
*/
export function clearCooldown(player: alt.Player) {
delete cooldowns[player.id];
Athena.session.player.clearKey(player, SessionKey);
}

/**
Expand All @@ -45,11 +54,9 @@ export function clearCooldown(player: alt.Player) {
* @return {*}
*/
export function getExpiration(player: alt.Player) {
if (!cooldowns[player.id]) {
if (!Athena.session.player.has(player, SessionKey)) {
return Date.now();
}

return cooldowns[player.id];
return Athena.session.player.get(player, SessionKey);
}

alt.on('playerDisconnect', clearCooldown);
19 changes: 13 additions & 6 deletions src/core/server/controllers/dynamicDoors/player.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,23 @@
import * as alt from 'alt-server';
import * as Athena from '@AthenaServer/api';

const playerLoadingInstance: { [id: string]: boolean } = {};
const SessionKey = 'athena-dd-loading-instance';

declare global {
namespace AthenaSession {
interface Player {
[SessionKey]: boolean;
}
}
}

/**
* Unregister a player that is loading.
*
* @param {alt.Player} player
*/
export function unregister(player: alt.Player) {
delete playerLoadingInstance[player.id];
Athena.session.player.clearKey(player, SessionKey);
}

/**
Expand All @@ -18,7 +27,7 @@ export function unregister(player: alt.Player) {
* @param {alt.Player} player
*/
export function register(player: alt.Player) {
playerLoadingInstance[player.id] = true;
Athena.session.player.set(player, SessionKey, true);
}

/**
Expand All @@ -29,7 +38,5 @@ export function register(player: alt.Player) {
* @return {*}
*/
export function isLoading(player: alt.Player) {
return playerLoadingInstance[player.id] ? true : false;
return Athena.session.player.has(player, SessionKey);
}

alt.on('playerDisconnect', unregister);
78 changes: 41 additions & 37 deletions src/core/server/document/accountData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,17 @@ import { deepCloneObject } from '@AthenaShared/utility/deepCopy';

export type KeyChangeCallback = (player: alt.Player, newValue: any, oldValue: any) => void;

const callbacks: { [key: string]: Array<KeyChangeCallback> } = {};
const cache: { [id: string]: Account } = {};
const DEBUG_MODE = false; // Use this to see what state is being set.
const SessionKey = 'athena-document-account-data';

declare global {
namespace AthenaSession {
interface Player {
[SessionKey]: Account;
}
}
}

const callbacks: { [key: string]: Array<KeyChangeCallback> } = {};
const restrictedFields = ['username', 'password', 'salt', 'hardware', 'ips', 'banned'];

/**
Expand Down Expand Up @@ -51,10 +58,10 @@ export function bind(player: alt.Player, document: Account) {
return;
}

cache[player.id] = document;
Athena.session.player.set(player, SessionKey, document);

try {
const dataCopy = deepCloneObject<Account>(cache[player.id]);
const dataCopy = deepCloneObject<Account>(document);
const cleanedData = removeRestrictedFields(dataCopy);
Athena.webview.emit(player, SYSTEM_EVENTS.PLAYER_EMIT_ACCOUNT_STATE, cleanedData);
Athena.config.player.set(player, 'account-data', cleanedData);
Expand All @@ -71,7 +78,7 @@ export function unbind(id: number) {
return Overrides.unbind(id);
}

delete cache[id];
Athena.session.player.clearKey(id, SessionKey);
}

/**
Expand All @@ -86,9 +93,11 @@ export function get<T = Account>(player: alt.Player): T | undefined {
return Overrides.get(player);
}

return cache[player.id] as T;
return <T>Athena.session.player.get(player, SessionKey);
}

type Combine<A, B> = A & B;

/**
* Get the current value of a specific field inside of the player data object.
* Can be extended to obtain any value easily.
Expand All @@ -106,11 +115,11 @@ export function getField<T = {}, ReturnType = any>(
return Overrides.getField(player, fieldName);
}

if (!cache[player.id]) {
if (!Athena.session.player.has(player, SessionKey)) {
return undefined;
}

return cache[player.id][String(fieldName)];
return Athena.session.player.get(player, SessionKey)[String(fieldName)];
}

/**
Expand All @@ -132,30 +141,26 @@ export async function set<T = {}, Keys = keyof KnownKeys<Account & T>>(
return Overrides.set(player, fieldName, value);
}

if (!cache[player.id]) {
if (!Athena.session.player.has(player, SessionKey)) {
return undefined;
}

const typeSafeFieldName = String(fieldName);
let data = Athena.session.player.get(player, SessionKey);
let oldValue = undefined;
if (cache[player.id][typeSafeFieldName]) {
oldValue = JSON.parse(JSON.stringify(cache[player.id][typeSafeFieldName]));

if (data[typeSafeFieldName]) {
oldValue = JSON.parse(JSON.stringify(data[typeSafeFieldName]));
}

const newData = { [typeSafeFieldName]: value };

cache[player.id] = Object.assign(cache[player.id], newData);
await Database.updatePartialData(cache[player.id]._id, newData, Athena.database.collections.Accounts);

if (DEBUG_MODE) {
alt.logWarning(
`DEBUG: ${cache[player.id]._id} state updated for ${typeSafeFieldName} with value: ${JSON.stringify(
newData,
)}`,
);
}
data = Object.assign(data, newData);
Athena.session.player.set(player, SessionKey, data);
await Database.updatePartialData(data._id, newData, Athena.database.collections.Accounts);

try {
const dataCopy = deepCloneObject<Account>(cache[player.id]);
const dataCopy = deepCloneObject<Account>(data);
const cleanedData = removeRestrictedFields(dataCopy);
Athena.config.player.set(player, 'account-data', cleanedData);
Athena.webview.emit(player, SYSTEM_EVENTS.PLAYER_EMIT_ACCOUNT_STATE, cleanedData);
Expand Down Expand Up @@ -184,22 +189,29 @@ export async function setBulk<T = {}, Keys = Partial<Account & T>>(player: alt.P
return Overrides.setBulk(player, fields);
}

if (!Athena.session.player.has(player, SessionKey)) {
return undefined;
}

let data = Athena.session.player.get(player, SessionKey);

const oldValues = {};

Object.keys(fields).forEach((key) => {
if (typeof cache[player.id][key] === 'undefined') {
if (typeof data[key] === 'undefined') {
oldValues[key] = undefined;
return;
}

oldValues[key] = JSON.parse(JSON.stringify(cache[player.id][key]));
oldValues[key] = JSON.parse(JSON.stringify(data[key]));
});

cache[player.id] = Object.assign(cache[player.id], fields);
await Database.updatePartialData(cache[player.id]._id, fields, Athena.database.collections.Accounts);
data = Object.assign(data, fields);
Athena.session.player.set(player, SessionKey, data);
await Database.updatePartialData(data._id, fields, Athena.database.collections.Accounts);

try {
const dataCopy = deepCloneObject<Account>(cache[player.id]);
const dataCopy = deepCloneObject<Account>(data);
const cleanedData = removeRestrictedFields(dataCopy);
Athena.webview.emit(player, SYSTEM_EVENTS.PLAYER_EMIT_ACCOUNT_STATE, cleanedData);
Athena.config.player.set(player, 'account-data', cleanedData);
Expand All @@ -211,7 +223,7 @@ export async function setBulk<T = {}, Keys = Partial<Account & T>>(player: alt.P
}

for (let cb of callbacks[key]) {
cb(player, cache[player.id][key], oldValues[key]);
cb(player, data[key], oldValues[key]);
}
});
}
Expand All @@ -237,14 +249,6 @@ export function onChange<T = {}>(fieldName: keyof KnownKeys<Account & T>, callba
}
}

alt.on('playerDisconnect', (player: alt.Player) => {
if (typeof player.id === 'undefined' || player.id === null) {
return;
}

unbind(player.id);
});

interface AccountDataDocFuncs {
bind: typeof bind;
unbind: typeof unbind;
Expand Down

0 comments on commit 58f66e0

Please sign in to comment.