Created
December 1, 2021 16:24
-
-
Save Cheaterman/0d566655c748d6442a5b485e1fdc4937 to your computer and use it in GitHub Desktop.
gates.py
This file contains hidden or 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
from dataclasses import dataclass | |
from typing import Optional, Tuple | |
from samp import ( | |
KEY_CROUCH, | |
GetPlayerFacingAngle, | |
GetPlayerPos, | |
IsPlayerInAnyVehicle, | |
KillTimer, | |
SendClientMessage, | |
SetTimer, | |
) | |
from .cmdparser import cmd | |
from .elevators import distance, rotate | |
from .model import Gate as DBGate, session as sessionmaker | |
from .streamer import ( | |
CreateDynamicObject, | |
DestroyDynamicObject, | |
MoveDynamicObject, | |
StopDynamicObject, | |
) | |
from .tms import admin_level | |
@dataclass | |
class GateType: | |
name: str | |
model_id: int | |
closed_offset: Tuple[float, float, float] | |
open_offset: Tuple[float, float, float] | |
@dataclass | |
class Gate: | |
type: GateType | |
position: Tuple[float, float, float] | |
rotation: float | |
object_id: int | |
id: Optional[int] = None | |
opened: bool = False | |
_close_timer_id: Optional[int] = None | |
_types = { | |
type.name: type | |
for type in ( | |
GateType( | |
name='small', | |
model_id=19870, | |
closed_offset=(-2.37, 0, .8), | |
open_offset=(-2.37, 0, -2.75), | |
), | |
GateType( | |
name='large', | |
model_id=976, | |
closed_offset=(-4.43, 0, -0.85), | |
open_offset=(-4.43, 0, -4.18), | |
), | |
GateType( | |
name='xl', | |
model_id=980, | |
closed_offset=(0, 0, 1.75), | |
open_offset=(0, 0, -3.78), | |
), | |
) | |
} | |
def toggle(self): | |
if not self.opened: | |
self.open() | |
else: | |
self.close() | |
def open(self): | |
open_offset = self.type.open_offset | |
gate_position = tuple( | |
xyz + offset_xyz | |
for xyz, offset_xyz in zip( | |
self.position, | |
rotate(open_offset[:2], self.rotation) + open_offset[2:], | |
) | |
) | |
StopDynamicObject(self.object_id) | |
MoveDynamicObject(self.object_id, *gate_position, 2.5) | |
self._kill_close_timer() | |
self._close_timer_id = SetTimer(self.close, 5000, False) | |
self.opened = True | |
def close(self): | |
closed_offset = self.type.closed_offset | |
gate_position = tuple( | |
xyz + offset_xyz | |
for xyz, offset_xyz in zip( | |
self.position, | |
rotate(closed_offset[:2], self.rotation) + closed_offset[2:], | |
) | |
) | |
StopDynamicObject(self.object_id) | |
MoveDynamicObject(self.object_id, *gate_position, 2.5) | |
self._kill_close_timer() | |
self.opened = False | |
def _kill_close_timer(self): | |
if self._close_timer_id is not None: | |
KillTimer(self._close_timer_id) | |
self._close_timer_id = None | |
def destroy(self): | |
DestroyDynamicObject(self.object_id) | |
gates = [] | |
def OnGameModeInit(): | |
with sessionmaker() as session: | |
for db_gate in session.query(DBGate): | |
gate = add_gate( | |
db_gate.type, | |
(db_gate.x, db_gate.y, db_gate.z), | |
db_gate.rotation | |
) | |
gate.id = db_gate.id | |
def OnGameModeExit(): | |
global gates | |
for gate in gates: | |
gate.destroy() | |
def OnPlayerKeyStateChange(playerid, newkeys, oldkeys): | |
if not IsPlayerInAnyVehicle(playerid): | |
return | |
if (newkeys & KEY_CROUCH) and not (oldkeys & KEY_CROUCH): | |
gate = find_closest_gate(GetPlayerPos(playerid)) | |
if not gate: | |
return | |
gate.toggle() | |
def add_gate(type: str, position: Tuple[float, float, float], rotation: float): | |
if type not in Gate._types: | |
raise ValueError(f'Unknown gate type {type}') | |
gate_type = Gate._types[type] | |
closed_offset = gate_type.closed_offset | |
gate_position = tuple( | |
xyz + offset_xyz | |
for xyz, offset_xyz in zip( | |
position, | |
rotate(closed_offset[:2], rotation) + closed_offset[2:], | |
) | |
) | |
gate = Gate( | |
type=gate_type, | |
position=position, | |
rotation=rotation, | |
object_id=CreateDynamicObject( | |
gate_type.model_id, | |
*gate_position, | |
0, | |
0, | |
rotation, | |
), | |
) | |
global gates | |
gates.append(gate) | |
return gate | |
def find_closest_gate(from_coords): | |
for gate in gates: | |
if distance(from_coords, gate.position) < 5: | |
return gate | |
@cmd('addgate', requires=admin_level(5)) | |
def addgate(playerid, type=''): | |
if not type: | |
types = ', '.join(f'"{type}"' for type in Gate._types) | |
SendClientMessage( | |
playerid, | |
0xFF0000FF, | |
'USAGE: /addgate type ' | |
f'(possible choices: {types})', | |
) | |
return | |
position = GetPlayerPos(playerid) | |
rotation = GetPlayerFacingAngle(playerid) | |
try: | |
gate = add_gate(type, position, rotation) | |
except ValueError: | |
types = ', '.join(f'"{type}"' for type in Gate._types) | |
SendClientMessage( | |
playerid, | |
0xFF0000FF, | |
f'ERROR: Gate type "{type}" does not exist ' | |
f'(possible choices: {types})', | |
) | |
return | |
with sessionmaker() as session: | |
db_gate = DBGate( | |
type=type, | |
x=position[0], | |
y=position[1], | |
z=position[2], | |
rotation=rotation, | |
) | |
session.add(db_gate) | |
session.commit() | |
gate.id = db_gate.id | |
SendClientMessage(playerid, 0x4080FFFF, 'Gate was successfully added.') | |
@cmd('delgate', requires=admin_level(5)) | |
def delgate(playerid): | |
gate = find_closest_gate(GetPlayerPos(playerid)) | |
if not gate: | |
SendClientMessage( | |
playerid, | |
0xFF0000FF, | |
'ERROR: Not in range of any gate', | |
) | |
return | |
with sessionmaker() as session: | |
db_gate = session.query(DBGate).get(gate.id) | |
if db_gate: | |
session.delete(db_gate) | |
session.commit() | |
gate.destroy() | |
global gates | |
gates.remove(gate) | |
SendClientMessage(playerid, 0x4080FFFF, 'Gate was successfully removed.') | |
@cmd | |
def open(playerid): | |
gate = find_closest_gate(GetPlayerPos(playerid)) | |
if not gate: | |
SendClientMessage( | |
playerid, | |
0xFF0000FF, | |
'ERROR: Not in range of any gate', | |
) | |
return | |
if not gate.opened: | |
gate.open() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment