import { IContextData } from './../../../../components/Context' ; import api from './../../../../api/api' ; import * as I from './../../../../api/interfaces' ; import { Row , Col , Button } from 'reactstrap' ; import Panel from './Panel' ; import { socket } from '../Live/Live' ; import Switch from './../../../../components/Switch/Switch' ; import ElectronOnly from './../../../../components/ElectronOnly' ; import DragInput from './../../../DragFileInput' ; import HudEntry from './HudEntry' ; import config from './../../../../api/config' ; import { withTranslation } from 'react-i18next' ; import { GameOnly } from '../Config/Config' ; import { Component } from 'react' ; import { canPlanUseCloudStorage } from '../../../../utils' ; const isElectron = config . isElectron ; function createCFG ( customRadar , customKillfeed , afx , port , aco , autoexec = true ) { let cfg = `cl_draw_only_deathnotices 1` ; let file = 'hud' ; if ( ! customRadar ) { cfg += `\ncl_drawhud_force_radar 1` ; } else { cfg += `\ncl_drawhud_force_radar 0` ; file += '_radar' ; } if ( customKillfeed ) { file += '_killfeed' ; cfg += `\ncl_drawhud_force_deathnotices -1` ; } if ( customKillfeed || aco ) { if ( aco ) file += '_aco' ; cfg += `\nmirv_pgl url "ws://localhost:${ port }/socket.io/?EIO=3&transport=websocket"` ; cfg += `\nmirv_pgl start` ; } if ( afx ) { file += '_interop' ; cfg = 'afx_interop connect 1' ; cfg += `\nexec ${ createCFG ( customRadar , customKillfeed , false , port , aco ) . file }` ; } file += '.cfg' ; if ( ! autoexec ) { file = '' ; } return { cfg , file } ; } interface IProps { cxt : IContextData ; t : any ; toggle : ( tab : string , data ? : any ) => void ; setOnBackClick : I . HeaderHandler ; } interface IForm { killfeed : boolean ; radar : boolean ; afx : boolean ; ar : boolean ; autoexec : boolean ; } interface IState { config : I . Config ; huds : I . HUD [ ] ; loadingHUDs : string [ ] ; form : IForm ; active : I . HUD | null ; currentHUD : string | null ; enableTest : boolean ; isOnLoop : boolean ; blocked : string [ ] ; isHUDOpened : boolean ; } class Huds extends Component < IProps , IState > { constructor ( props ) { super ( props ) ; this . state = { loadingHUDs : [ ] , huds : [ ] , config : { steamApiKey : '' , hlaePath : '' , port : 1349 , token : '' , afxCEFHudInteropPath : '' , sync : true , cg : false , autoSwitch : false } , form : { killfeed : false , radar : false , afx : false , autoexec : true , ar : false } , active : null , currentHUD : null , enableTest : true , isOnLoop : false , blocked : [ ] , isHUDOpened : false } ; } runGame = async ( ) => { switch ( this . props . cxt . game ) { case 'csgo' : api . game . run ( this . state . form ) ; break ; case 'rocketleague' : await api . bakkesmod . installSos ( ) ; await api . bakkesmod . run ( ) ; break ; } } ; handleZIPs = ( files ) => { const file = files [ 0 ] ; const reader = new FileReader ( ) ; reader . readAsDataURL ( file ) ; reader . onload = ( ) => { const name = file . name . substr ( 0 , file . name . lastIndexOf ( '.' ) ) . replace ( /\W/g , '' ) ; if ( file . name . substr ( - 4 ) === '.rar' || ! name ) { return ; } api . huds . save ( reader . result , name ) ; } ; } ; changeForm = ( name ) => ( ) => { const { form } = this . state ; form [ name ] = ! form [ name ] ; this . setState ( { form } , ( ) => { if ( name === 'ar' ) { this . forceBlock ( true , 'afx' ) ; } } ) ; } ; getConfig = async ( ) => { const config = await api . config . get ( ) ; this . setState ( { config } ) ; } ; loadHUDs = async ( ) => { const huds = await api . huds . get ( ) ; this . setState ( { huds } ) ; } ; setHUDLoading = ( uuid , isLoading ) => { const { loadingHUDs } = this . state ; if ( isLoading && ! loadingHUDs . includes ( uuid ) ) { this . setState ( { loadingHUDs : [ ... loadingHUDs , uuid ] } ) ; } else if ( ! isLoading && loadingHUDs . includes ( uuid ) ) { this . setState ( { loadingHUDs : loadingHUDs . filter ( hudUUID => hudUUID !== uuid ) } ) ; } } ; async componentDidMount ( ) { socket . on ( 'reloadHUDs' , this . loadHUDs ) ; socket . on ( 'active_hlae' , ( hud ) => { this . setState ( { currentHUD : hud } ) ; } ) ; socket . on ( 'enableTest' , ( status , isOnLoop ) => { this . setState ( { enableTest : status , isOnLoop } ) ; } ) ; socket . on ( 'config' , ( ) => { this . getConfig ( ) ; } ) ; socket . on ( 'hud_opened' , ( status ) => { this . setState ( { isHUDOpened : status } ) ; } ) ; socket . emit ( 'get_active_hlae' ) ; socket . emit ( 'get_test_settings' ) ; socket . emit ( 'is_hud_opened' ) ; this . loadHUDs ( ) ; this . getConfig ( ) ; } startHUD ( dir ) { api . huds . start ( dir ) ; } toggleConfig = ( hud ? ) => ( ) => { this . setState ( { active : hud || null } , ( ) => { this . props . setOnBackClick ( hud ? this . toggleConfig ( ) : null ) ; } ) ; } ; forceBlock = ( status , ... blockedToggles ) => { this . setState ( ( state ) => { for ( const blocked of blockedToggles ) { if ( blocked in state . form ) { state . form [ blocked ] = status ; } if ( state . blocked . includes ( blocked ) ) { state . blocked = state . blocked . filter ( ( el ) => el !== blocked ) ; } else { state . blocked . push ( blocked ) ; } } return state ; } ) ; } ; render ( ) { const { killfeed , radar , afx } = this . state . form ; const { active , config , isHUDOpened , huds } = this . state ; const t = this . props . t ; const available = canPlanUseCloudStorage ( this . props . cxt . customer ?. license ?. type ) ; if ( active ) { return ( < > { } < div className = "tab-content-container full-scroll no-padding" > < Panel hud = { active } cxt = { this . props . cxt } / > < /div> < />); } const gameHUDs = huds . filter ( hud => hud . game !== 'all' && ! hud . isDev ) ; const independentOrDevHUDs = huds . filter ( hud => hud . game === 'all' || hud . isDev ) ; return ( < > < div className = { `tab-content-container no-padding ${ ! isElectron ? 'full-scroll' : '' }` } > < GameOnly game = "csgo" > < Row className = "config-container" > < Col md = "12" className = "config-entry wrap" > < div className = "config-area" > < div className = "config-description" > { t ( 'huds.config.customRadar' ) } < /div> < Switch isOn = { this . state . form . radar } id = "radar-toggle" handleToggle = { this . changeForm ( 'radar' ) } disabled = { this . state . blocked . includes ( 'radar' ) } / > < /div> < div className = "config-area" > < div className = "config-description" > { t ( 'huds.config.customKillfeedOrACO' ) } < /div> < Switch isOn = { this . state . form . killfeed } id = "killfeed-toggle" handleToggle = { this . changeForm ( 'killfeed' ) } disabled = { this . state . blocked . includes ( 'killfeed' ) } / > < /div> < div className = "config-area" > < div className = "config-description" > { t ( 'huds.config.embeddedHUD' ) } < /div> < Switch isOn = { this . state . form . afx } id = "afx-toggle" handleToggle = { this . changeForm ( 'afx' ) } disabled = { this . state . blocked . includes ( 'afx' ) } / > < /div> < ElectronOnly > < div className = "config-area" > < div className = "config-description" > { t ( 'huds.config.playTestLoop' ) } < /div> < Switch isOn = { this . state . isOnLoop } id = "gamelopp-toggle" handleToggle = { api . game . toggleLoop } / > < /div> < /ElectronOnly> < div className = "config-area" > < div className = "config-description" > { t ( 'huds.config.ar' ) } < /div> < Switch isOn = { this . state . form . ar } id = "ar-toggle" handleToggle = { this . changeForm ( 'ar' ) } disabled = { this . state . blocked . includes ( 'ar' ) } / > < /div> < div className = "config-area" > < div className = "config-description" > { t ( 'huds.config.autoexecute' ) } < /div> < Switch isOn = { this . state . form . autoexec } id = "autoexec-toggle" handleToggle = { this . changeForm ( 'autoexec' ) } disabled = { this . state . blocked . includes ( 'autoexec' ) } / > < /div> < /Col> < Col md = "12" className = "config-entry" > < div className = "running-game-container" > < div > < div className = "config-description" > { t ( 'huds.config.console' ) } < /div> < code className = "exec-code" > exec { createCFG ( radar , killfeed , afx , config . port , killfeed ) . file } < /code> < ElectronOnly > < div className = "config-description" > { t ( 'common.or' ) . toUpperCase ( ) } < /div> < Button className = "button green strong" disabled = { ( killfeed && ! config . hlaePath ) || ( afx && ( ! config . hlaePath || ! config . afxCEFHudInteropPath ) ) } onClick = { this . runGame } > { t ( 'huds.config.runGame' ) } < /Button> < Button className = "button green strong empty" onClick = { api . game . runTest } > { ! this . state . enableTest ? t ( 'huds.config.pauseTest' ) : t ( 'huds.config.runTest' ) } < /Button> < /ElectronOnly> < /div> < div className = "warning" > < ElectronOnly > { ( killfeed || afx ) && ! config . hlaePath ? ( < div > { t ( 'huds.warning.specifyHLAEPath' ) } < /div>) : null} { killfeed ? ( < div > If you only want ACO without killfeed , remove < code > _killfeed < /code>{' '} from execute line < /div>) : null} { afx && ! config . afxCEFHudInteropPath ? ( < div > { t ( 'huds.warning.specifyAFXInteropPath' ) } < /div>) : null} { afx && config . afxCEFHudInteropPath && config . hlaePath ? ( < div > { t ( 'huds.warning.specifyAFXModeInfo' ) } < /div>) : null} < /ElectronOnly> < /div> < /div> < /Col> < /Row> < /GameOnly> < GameOnly game = "rocketleague" > < Row className = "config-container" > < Col md = "12" className = "config-entry" > < div className = "running-game-container" > < div > < ElectronOnly > < Button className = "round-btn run-game" disabled = { ( killfeed && ! config . hlaePath ) || ( afx && ( ! config . hlaePath || ! config . afxCEFHudInteropPath ) ) } onClick = { this . runGame } > RUN GAME < /Button> < /ElectronOnly> < /div> < div className = "warning" > < ElectronOnly > { ( killfeed || afx ) && ! config . hlaePath ? ( < div > Specify HLAE path in Settings in order to use custom killfeeds < /div>) : null} { afx && ! config . afxCEFHudInteropPath ? ( < div > Specify AFX Interop path in Settings in order to use AFX mode < /div>) : null} { afx && config . afxCEFHudInteropPath && config . hlaePath ? ( < div > When using AFX mode , after joining the match click on the SET button - no need to start the overlay . < /div>) : null} < /ElectronOnly> < /div> < /div> < /Col> < /Row> < /GameOnly> < div className = "huds-options" > < div className = "hud-tabs" > < /div> < div className = "huds-buttons" > < input type = "file" id = { 'hud-upload' } accept = { '.zip' } onChange = { e => { e . target . files && this . handleZIPs ( e . target . files ) ; } } /> < label htmlFor = "hud-upload" > < div className = "button empty green dashed" > Add new HUD < /div> < /label> < div className = "button empty green" onClick = { api . huds . openDirectory } > { t ( 'huds.config.openDirectory' ) } < /div> < /div> < /div> < div className = "huds-container" > { ! ! false && isElectron ? ( < Col s = { 12 } > < DragInput id = { `hud_zip` } onChange = { this . handleZIPs } label = { t ( 'huds.config.add' ) } accept = ".zip" / > < /Col>) : null} { independentOrDevHUDs . map ( hud => ( < HudEntry key = { hud . dir } hud = { hud } toggleConfig = { this . toggleConfig } isActive = { hud . url === this . state . currentHUD } customFields = { this . props . cxt . fields } loadHUDs = { this . loadHUDs } setHUDLoading = { this . setHUDLoading } isLoading = { ! ! hud . uuid && this . state . loadingHUDs . includes ( hud . uuid ) } isCloudAvailable = { available } isHUDOpened = { isHUDOpened } isHUDActive = { ! ! this . state . currentHUD } />))} { independentOrDevHUDs . length && gameHUDs . length ? < div className = "huds-separator" / > : null } { gameHUDs . map ( hud => ( < HudEntry key = { hud . dir } hud = { hud } toggleConfig = { this . toggleConfig } isActive = { hud . url === this . state . currentHUD } customFields = { this . props . cxt . fields } loadHUDs = { this . loadHUDs } setHUDLoading = { this . setHUDLoading } isLoading = { ! ! hud . uuid && this . state . loadingHUDs . includes ( hud . uuid ) } isCloudAvailable = { available } isHUDOpened = { isHUDOpened } isHUDActive = { ! ! this . state . currentHUD } />))} < /div> { isElectron && ! ! false ? ( < Row > < Col className = "main-buttons-container" > < Button onClick = { api . huds . openDirectory } color = "primary" > { t ( 'huds.config.openDirectory' ) } < /Button> < /Col> < /Row>) : ('')} < /div> < />); } } export default withTranslation ( ) ( Huds ) ;