mirror of
https://github.com/lexogrine/cs2-react-hud.git
synced 2026-05-04 04:03:10 +02:00
Updated setup to vite and moved to hooks instead of class
This commit is contained in:
@@ -1,49 +1,18 @@
|
||||
import React from "react";
|
||||
|
||||
import { GSI } from "./../../App";
|
||||
import BombTimer from "./Countdown";
|
||||
import { MAX_TIMER, useBombTimer } from "./Countdown";
|
||||
import { C4 } from "./../../assets/Icons";
|
||||
|
||||
export default class Bomb extends React.Component<any, { height: number; show: boolean }> {
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
this.state = {
|
||||
height: 0,
|
||||
show: false
|
||||
};
|
||||
}
|
||||
hide = () => {
|
||||
this.setState({ show: false, height: 100 });
|
||||
};
|
||||
componentDidMount() {
|
||||
const bomb = new BombTimer(time => {
|
||||
let height = time > 40 ? 4000 : time * 100;
|
||||
this.setState({ height: height / 40 });
|
||||
});
|
||||
bomb.onReset(this.hide);
|
||||
GSI.on("data", data => {
|
||||
if (data.bomb && data.bomb.countdown) {
|
||||
if (data.bomb.state === "planted") {
|
||||
this.setState({ show: true });
|
||||
return bomb.go(data.bomb.countdown);
|
||||
}
|
||||
if (data.bomb.state !== "defusing") {
|
||||
this.hide();
|
||||
}
|
||||
} else {
|
||||
this.hide();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div id={`bomb_container`}>
|
||||
<div className={`bomb_timer ${this.state.show ? "show" : "hide"}`} style={{ height: `${this.state.height}%` }}></div>
|
||||
<div className={`bomb_icon ${this.state.show ? "show" : "hide"}`}>
|
||||
<C4 fill="white" />
|
||||
</div>
|
||||
const Bomb = () => {
|
||||
const bombData = useBombTimer();
|
||||
const show = bombData.state === "planted" || bombData.state === "defusing";
|
||||
|
||||
return (
|
||||
<div id={`bomb_container`}>
|
||||
<div className={`bomb_timer ${show ? "show" : "hide"}`} style={{ height: `${bombData.bombTime*100/MAX_TIMER.bomb}%` }}></div>
|
||||
<div className={`bomb_icon ${show ? "show" : "hide"}`}>
|
||||
<C4 fill="white" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default Bomb;
|
||||
+77
-40
@@ -1,46 +1,83 @@
|
||||
export default class Countdown {
|
||||
last: number;
|
||||
time: number;
|
||||
step: (time: number) => void;
|
||||
on: boolean;
|
||||
resetFunc?: Function;
|
||||
import { Bomb, Events, Player } from "csgogsi";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { GSI } from "../../API/HUD";
|
||||
|
||||
constructor(step: (time: number) => void){
|
||||
this.last = 0;
|
||||
this.time = 0;
|
||||
this.on = false;
|
||||
this.step = step;
|
||||
}
|
||||
onReset(func: Function) {
|
||||
this.resetFunc = func;
|
||||
}
|
||||
stepWrapper = (time: number) =>{
|
||||
if(this.time < 0) return this.reset();
|
||||
if(!this.on) return this.reset();
|
||||
if(!this.last) this.last = time;
|
||||
if(this.time !== Number((this.time - (time - this.last)/1000))){
|
||||
this.time = Number((this.time - (time - this.last)/1000));
|
||||
this.step(this.time);
|
||||
export const MAX_TIMER = {
|
||||
planting: 3,
|
||||
defuse_kit: 5,
|
||||
defuse_nokit: 10,
|
||||
bomb: 40
|
||||
}
|
||||
const findNewTime = (current: number, newTime: number) => Math.abs(current - newTime) > 2 ? newTime : current;
|
||||
|
||||
export const useBombTimer = () => {
|
||||
const [ player, setPlayerSteamId ] = useState<Player | null>(null);
|
||||
const [ bombState, setBombState ] = useState<Bomb["state"] | null>(null);
|
||||
const [ site, setBombSite ] = useState<string | null>(null);
|
||||
|
||||
const [ plantTime, setPlantTime ] = useState(0);
|
||||
const [ bombTime, setBombTime ] = useState(0);
|
||||
const [ defuseTime, setDefuseTime ] = useState(0);
|
||||
|
||||
// Inner loop logic
|
||||
const previousTimeRef = useRef(0);
|
||||
const rAFRef = useRef<number>();
|
||||
|
||||
useEffect(() => {
|
||||
const onData: Events["data"] = data => {
|
||||
const { bomb } = data;
|
||||
|
||||
const bombPlayer = bomb?.player || null;
|
||||
const state = bomb?.state || null;
|
||||
const site = bomb?.site || null;
|
||||
|
||||
const countdown = parseFloat(bomb?.countdown || '0');
|
||||
|
||||
setPlayerSteamId(bombPlayer);
|
||||
setBombState(state);
|
||||
setBombSite(site);
|
||||
|
||||
const plantNewTime = state === "planting" ? countdown : 0;
|
||||
const defuseNewTime = state === "defusing" ? countdown : 0;
|
||||
|
||||
|
||||
setPlantTime(curr => findNewTime(curr, plantNewTime));
|
||||
setDefuseTime(curr => findNewTime(curr, defuseNewTime));
|
||||
setBombTime(p => state === "planted" ? findNewTime(p, countdown) : p);
|
||||
}
|
||||
|
||||
GSI.on("data", onData);
|
||||
|
||||
const animationFrame = (time: number) => {
|
||||
if(previousTimeRef.current){
|
||||
const deltaTime = time - previousTimeRef.current;
|
||||
const dTs = deltaTime/1000;
|
||||
|
||||
setPlantTime(p => p <= 0 ? 0 : p - dTs);
|
||||
setDefuseTime(p => p <= 0 ? 0 : p - dTs);
|
||||
setBombTime(p => p <= 0 ? 0 : p - dTs);
|
||||
}
|
||||
previousTimeRef.current = time;
|
||||
rAFRef.current = requestAnimationFrame(animationFrame);
|
||||
}
|
||||
|
||||
rAFRef.current = requestAnimationFrame(animationFrame);
|
||||
|
||||
return () => {
|
||||
GSI.off("data", onData);
|
||||
if(rAFRef.current) cancelAnimationFrame(rAFRef.current);
|
||||
}
|
||||
this.last =time;
|
||||
|
||||
|
||||
if(this.last) requestAnimationFrame(this.stepWrapper)
|
||||
}
|
||||
}, []);
|
||||
|
||||
go(duration: string | number){
|
||||
//console.log("STARTED WITH ", duration);
|
||||
if(typeof duration === "string") duration = Number(duration);
|
||||
if(Math.abs(duration - this.time) > 2) this.time = duration;
|
||||
this.on = true;
|
||||
if(!this.last ) requestAnimationFrame(this.stepWrapper);
|
||||
|
||||
}
|
||||
|
||||
reset(){
|
||||
this.last = 0;
|
||||
this.time = 0;
|
||||
this.on = false;
|
||||
if(this.resetFunc) this.resetFunc();
|
||||
}
|
||||
}
|
||||
return ({
|
||||
state: bombState,
|
||||
player,
|
||||
site,
|
||||
defuseTime,
|
||||
bombTime,
|
||||
plantTime
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,41 +1,39 @@
|
||||
import React from "react";
|
||||
|
||||
import { Timer } from "../MatchBar/MatchBar";
|
||||
import { Player } from "csgogsi";
|
||||
import * as I from "./../../assets/Icons";
|
||||
import { MAX_TIMER } from "./Countdown";
|
||||
|
||||
interface IProps {
|
||||
timer: Timer | null;
|
||||
side: "right" | "left"
|
||||
}
|
||||
|
||||
export default class Bomb extends React.Component<IProps> {
|
||||
getCaption = (type: "defusing" | "planting", player: Player | null) => {
|
||||
if(!player) return null;
|
||||
if(type === "defusing"){
|
||||
return <>
|
||||
<I.Defuse height={22} width={22} fill="var(--color-new-ct)" />
|
||||
<div className={'CT'}>{player.name} is defusing the bomb</div>
|
||||
</>;
|
||||
}
|
||||
const getCaption = (type: "defusing" | "planting", player: Player | null) => {
|
||||
if(!player) return null;
|
||||
if(type === "defusing"){
|
||||
return <>
|
||||
<I.SmallBomb height={22} fill="var(--color-new-t)"/>
|
||||
<div className={'T'}>{player.name} is planting the bomb</div>
|
||||
<I.Defuse height={22} width={22} fill="var(--color-new-ct)" />
|
||||
<div className={'CT'}>{player.name} is defusing the bomb</div>
|
||||
</>;
|
||||
}
|
||||
render() {
|
||||
const { side, timer } = this.props;
|
||||
return (
|
||||
<div className={`defuse_plant_container ${side} ${timer && timer.active ? 'show' :'hide'}`}>
|
||||
{
|
||||
timer ?
|
||||
<div className={`defuse_plant_caption`}>
|
||||
{this.getCaption(timer.type, timer.player)}
|
||||
</div> : null
|
||||
}
|
||||
|
||||
<div className="defuse_plant_bar" style={{ width: `${(timer && timer.width) || 0}%` }}></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return <>
|
||||
<I.SmallBomb height={22} fill="var(--color-new-t)"/>
|
||||
<div className={'T'}>{player.name} is planting the bomb</div>
|
||||
</>;
|
||||
}
|
||||
const Bomb = ({ timer, side }: IProps) =>{
|
||||
if(!timer) return null;
|
||||
return (
|
||||
<div className={`defuse_plant_container ${side} ${timer && timer.active ? 'show' :'hide'}`}>
|
||||
{
|
||||
timer ?
|
||||
<div className={`defuse_plant_caption`}>
|
||||
{getCaption(timer.type, timer.player)}
|
||||
</div> : null
|
||||
}
|
||||
|
||||
<div className="defuse_plant_bar" style={{ width: `${(timer.time * 100 / (timer.type === "planting" ? MAX_TIMER.planting : timer.player?.state.defusekit ? MAX_TIMER.defuse_kit : MAX_TIMER.defuse_nokit ))}%` }}></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
export default Bomb;
|
||||
Reference in New Issue
Block a user