-
Notifications
You must be signed in to change notification settings - Fork 41
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
* feat: local interactions, closes #66 * chore: update version
- Loading branch information
Showing
8 changed files
with
366 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
import * as alt from 'alt-client'; | ||
import { Events } from '../../shared/events/index.js'; | ||
import { useMessenger } from '../system/messenger.js'; | ||
|
||
type ColshapeTypes = { | ||
Circle: ConstructorParameters<typeof alt.ColshapeCircle>; | ||
Cuboid: ConstructorParameters<typeof alt.ColshapeCuboid>; | ||
Cylinder: ConstructorParameters<typeof alt.ColshapeCylinder>; | ||
Polygon: ConstructorParameters<typeof alt.ColshapePolygon>; | ||
Rectangle: ConstructorParameters<typeof alt.ColshapeRectangle>; | ||
Sphere: ConstructorParameters<typeof alt.ColshapeSphere>; | ||
}; | ||
|
||
const DEFAULT_COOLDOWN = 1000; | ||
const DEFAULT_KEY = 69; // E | ||
|
||
const messenger = useMessenger(); | ||
const colshapes: { [uid: string]: alt.Colshape } = {}; | ||
const sessionKey = 'colshape-identifier'; | ||
let currentInteraction: string; | ||
let timeout = Date.now(); | ||
|
||
function onCreate<K extends keyof ColshapeTypes>(uid: string, type: K, args: ColshapeTypes[K]) { | ||
if (colshapes[uid]) { | ||
try { | ||
colshapes[uid].destroy(); | ||
} catch (err) {} | ||
|
||
delete colshapes[uid]; | ||
} | ||
|
||
switch (type) { | ||
case 'Circle': | ||
// @ts-ignore | ||
colshapes[uid] = new alt.ColshapeCircle(...args); | ||
break; | ||
case 'Cuboid': | ||
// @ts-ignore | ||
colshapes[uid] = new alt.ColshapeCuboid(...args); | ||
break; | ||
case 'Cylinder': | ||
// @ts-ignore | ||
colshapes[uid] = new alt.ColshapeCylinder(...args); | ||
break; | ||
case 'Polygon': | ||
// @ts-ignore | ||
colshapes[uid] = new alt.ColshapePolygon(...args); | ||
break; | ||
case 'Rectangle': | ||
// @ts-ignore | ||
colshapes[uid] = new alt.ColshapeRectangle(...args); | ||
break; | ||
case 'Sphere': | ||
// @ts-ignore | ||
colshapes[uid] = new alt.ColshapeSphere(...args); | ||
break; | ||
} | ||
|
||
colshapes[uid].setMeta(sessionKey, uid); | ||
} | ||
|
||
function onDestroy(uid: string) { | ||
if (!colshapes[uid]) { | ||
return; | ||
} | ||
|
||
try { | ||
colshapes[uid].destroy(); | ||
} catch (err) {} | ||
|
||
delete colshapes[uid]; | ||
} | ||
|
||
function onEnter(colshape: alt.Colshape, entity: alt.Entity) { | ||
if (!(entity instanceof alt.Player)) { | ||
return; | ||
} | ||
|
||
if (!colshape.hasMeta(sessionKey)) { | ||
return; | ||
} | ||
|
||
currentInteraction = colshape.getMeta(sessionKey) as string; | ||
alt.emitServer(Events.controllers.interactionLocal.onEnter, currentInteraction); | ||
} | ||
|
||
function onLeave(colshape: alt.Colshape, entity: alt.Entity) { | ||
if (!(entity instanceof alt.Player)) { | ||
return; | ||
} | ||
|
||
if (!colshape.hasMeta(sessionKey)) { | ||
return; | ||
} | ||
|
||
const uid = colshape.getMeta(sessionKey) as string; | ||
alt.emitServer(Events.controllers.interactionLocal.onLeave, uid); | ||
currentInteraction = undefined; | ||
} | ||
|
||
function on(key: alt.KeyCode) { | ||
if (!currentInteraction) { | ||
return; | ||
} | ||
|
||
if (DEFAULT_KEY !== key) { | ||
return; | ||
} | ||
|
||
if (timeout > Date.now()) { | ||
return; | ||
} | ||
|
||
if (messenger.isChatFocused()) { | ||
return; | ||
} | ||
|
||
timeout = Date.now() + DEFAULT_COOLDOWN; | ||
alt.emitServer(Events.controllers.interactionLocal.on, currentInteraction); | ||
} | ||
|
||
alt.onServer(Events.controllers.interactionLocal.create, onCreate); | ||
alt.onServer(Events.controllers.interactionLocal.destroy, onDestroy); | ||
alt.on('entityEnterColshape', onEnter); | ||
alt.on('entityLeaveColshape', onLeave); | ||
alt.on('keyup', on); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
import * as alt from 'alt-server'; | ||
import { Events } from '../../shared/events/index.js'; | ||
|
||
type ColshapeTypes = { | ||
Circle: ConstructorParameters<typeof alt.ColshapeCircle>; | ||
Cuboid: ConstructorParameters<typeof alt.ColshapeCuboid>; | ||
Cylinder: ConstructorParameters<typeof alt.ColshapeCylinder>; | ||
Polygon: ConstructorParameters<typeof alt.ColshapePolygon>; | ||
Rectangle: ConstructorParameters<typeof alt.ColshapeRectangle>; | ||
Sphere: ConstructorParameters<typeof alt.ColshapeSphere>; | ||
}; | ||
|
||
type Callback = (player: alt.Player, destroy: Function) => void; | ||
type Invoke = (player: alt.Player) => void; | ||
|
||
const invokers: { | ||
[id: string]: { uid: string; invokeEnter: Invoke; invokeLeave: Invoke; invoke: Invoke; destroy: Function }[]; | ||
} = {}; | ||
|
||
function removeByUid(id: number, uid: string) { | ||
if (!invokers[id]) { | ||
return; | ||
} | ||
|
||
for (let i = invokers[id].length - 1; i >= 0; i--) { | ||
if (invokers[id][i].uid !== uid) { | ||
continue; | ||
} | ||
|
||
invokers[id].splice(i, 1); | ||
break; | ||
} | ||
} | ||
|
||
function removeAll(id: number) { | ||
if (!invokers[id]) { | ||
return; | ||
} | ||
|
||
for (let invoker of invokers[id]) { | ||
invoker.destroy(); | ||
} | ||
|
||
delete invokers[id]; | ||
} | ||
|
||
function getInvoker(player: alt.Player, uid: string) { | ||
if (!player || !player.valid) { | ||
return undefined; | ||
} | ||
|
||
if (!invokers[player.id]) { | ||
return undefined; | ||
} | ||
|
||
return invokers[player.id].find((x) => x.uid === uid); | ||
} | ||
|
||
/** | ||
* Called when a player enters the interaction | ||
* | ||
* @param {alt.Player} player | ||
* @param {string} uid | ||
* @return | ||
*/ | ||
function onClientEnter(player: alt.Player, uid: string) { | ||
const invoker = getInvoker(player, uid); | ||
if (!invoker) { | ||
return; | ||
} | ||
|
||
invoker.invokeEnter(player); | ||
} | ||
|
||
/** | ||
* Called when a player leaves the interaction | ||
* | ||
* @param {alt.Player} player | ||
* @param {string} uid | ||
* @return | ||
*/ | ||
function onClientLeave(player: alt.Player, uid: string) { | ||
const invoker = getInvoker(player, uid); | ||
if (!invoker) { | ||
return; | ||
} | ||
|
||
invoker.invokeLeave(player); | ||
} | ||
|
||
/** | ||
* Called when a player presses 'E' | ||
* | ||
* @param {alt.Player} player | ||
* @param {string} uid | ||
* @return | ||
*/ | ||
function onClient(player: alt.Player, uid: string) { | ||
const invoker = getInvoker(player, uid); | ||
if (!invoker) { | ||
return; | ||
} | ||
|
||
invoker.invoke(player); | ||
} | ||
|
||
export function useInteractionLocal<K extends keyof ColshapeTypes>( | ||
player: alt.Player, | ||
uid: string, | ||
type: K, | ||
args: ColshapeTypes[K], | ||
) { | ||
const _type: keyof ColshapeTypes = type; | ||
const _args: ColshapeTypes[K] = args; | ||
const _uid = uid; | ||
const onEnterCallbacks: Callback[] = []; | ||
const onLeaveCallbacks: Callback[] = []; | ||
const onCallbacks: Callback[] = []; | ||
|
||
function getUid() { | ||
return _uid; | ||
} | ||
|
||
function destroy() { | ||
if (!player || !player.valid) { | ||
return; | ||
} | ||
|
||
player.emit(Events.controllers.interactionLocal.destroy, _uid); | ||
removeByUid(player.id, _uid); | ||
} | ||
|
||
function onEnter(cb: Callback) { | ||
onEnterCallbacks.push(cb); | ||
} | ||
|
||
function onLeave(cb: Callback) { | ||
onLeaveCallbacks.push(cb); | ||
} | ||
|
||
function on(cb: Callback) { | ||
onCallbacks.push(cb); | ||
} | ||
|
||
function invokeEnter(player: alt.Player) { | ||
for (let cb of onEnterCallbacks) { | ||
cb(player, destroy); | ||
} | ||
} | ||
|
||
function invokeLeave(player: alt.Player) { | ||
for (let cb of onLeaveCallbacks) { | ||
cb(player, destroy); | ||
} | ||
} | ||
|
||
function invoke(player: alt.Player) { | ||
for (let cb of onCallbacks) { | ||
cb(player, destroy); | ||
} | ||
} | ||
|
||
if (!invokers[player.id]) { | ||
invokers[player.id] = []; | ||
} | ||
|
||
invokers[player.id].push({ uid, invokeEnter, invokeLeave, invoke, destroy }); | ||
player.emit(Events.controllers.interactionLocal.create, _uid, _type, _args); | ||
|
||
return { | ||
destroy, | ||
getUid, | ||
onEnter, | ||
onLeave, | ||
on, | ||
}; | ||
} | ||
|
||
alt.on('playerDisconnect', (player: alt.Player) => removeAll(player.id)); | ||
alt.onClient(Events.controllers.interactionLocal.on, onClient); | ||
alt.onClient(Events.controllers.interactionLocal.onEnter, onClientEnter); | ||
alt.onClient(Events.controllers.interactionLocal.onLeave, onClientLeave); |
Oops, something went wrong.