├── .gitignore ├── .storybook ├── addons.js ├── config.js └── webpack.config.js ├── README.md ├── gameConfig ├── gamestate_integration_observerspectator.cfg └── observer.cfg ├── index.html ├── jestconfig.json ├── lint.tsconfig.json ├── package-lock.json ├── package.json ├── src ├── config │ ├── hudSettings.ts │ ├── playerInfo.ts │ └── teamInfo.ts ├── container │ └── container.tsx ├── dataTypes │ └── index.ts ├── index.tsx ├── redux │ ├── modules │ │ ├── actions.ts │ │ ├── defuseType │ │ │ └── defuseType.ts │ │ ├── gsi │ │ │ ├── __tests__ │ │ │ │ └── gst-test.ts │ │ │ └── gsi.ts │ │ ├── hudVisibility │ │ │ └── hudVisibility.ts │ │ ├── index.ts │ │ ├── paused │ │ │ └── paused.ts │ │ ├── players │ │ │ ├── __tests__ │ │ │ │ └── players-test.ts │ │ │ └── players.ts │ │ ├── roundPhase │ │ │ └── roundPhase.ts │ │ ├── roundWinner │ │ │ └── roundWinner.ts │ │ ├── score │ │ │ └── score.ts │ │ ├── slotSide │ │ │ └── slotSide.ts │ │ ├── spectatingPlayer │ │ │ └── spectatingPlayer.ts │ │ ├── teamInfo │ │ │ └── teamInfo.ts │ │ └── teamMoney │ │ │ ├── __tests__ │ │ │ └── teamMoney-test.ts │ │ │ └── teamMoney.ts │ └── store.ts ├── resources │ ├── armors │ │ ├── armor.png │ │ └── helmet.png │ ├── miscs │ │ ├── bomb.png │ │ ├── death.png │ │ ├── defuse.png │ │ ├── eq.png │ │ ├── hp.png │ │ └── team.png │ ├── players │ │ ├── noimage.png │ │ └── shroud.jpg │ ├── teams │ │ └── magixgod.png │ └── weapons │ │ ├── weapon_decoy.png │ │ ├── weapon_flashbang.png │ │ ├── weapon_hegrenade.png │ │ ├── weapon_incgrenade.png │ │ ├── weapon_molotov.png │ │ └── weapon_smokegrenade.png ├── server.ts ├── shortcut │ └── shortcut.ts ├── util │ ├── __tests__ │ │ └── slotSideResolver-test.ts │ ├── armorIconResolver.ts │ ├── createAction.ts │ ├── miscIconResolver.ts │ ├── playerImageResolver.ts │ ├── slotSideResolver.ts │ ├── teamLogoResolver.ts │ └── weaponIconResolver.ts └── views │ ├── blinkingC4Icon │ ├── BlinkingC4Icon.tsx │ ├── Story.tsx │ └── blinking_c4_icon.scss │ ├── index.ts │ ├── kda │ ├── Kda.tsx │ ├── Story.tsx │ └── kda.scss │ ├── percentageTimer │ ├── PercentageTimer.tsx │ ├── Story.tsx │ └── percentage_timer.scss │ ├── player │ ├── Player.tsx │ ├── Story.tsx │ └── player.scss │ ├── roundCounter │ ├── RoundCounter.tsx │ ├── Story.tsx │ └── round_counter.scss │ ├── spectatingPlayer │ ├── SpectatingPlayer.tsx │ ├── Story.tsx │ └── spectating_player.scss │ ├── teamMoney │ ├── Story.tsx │ ├── TeamMoney.tsx │ └── team_money.scss │ ├── teamStats │ ├── Story.tsx │ ├── TeamStats.tsx │ └── team_stats.scss │ ├── template │ ├── Story.tsx │ └── Template.tsx │ ├── theme │ ├── color.scss │ └── common.scss │ ├── timer │ ├── Story.tsx │ ├── Timer.tsx │ └── timer.scss │ ├── topBar │ ├── Story.tsx │ ├── TopBar.tsx │ └── top_bar.scss │ ├── util │ └── baseComponent.tsx │ └── winnerTeamAnnounce │ ├── Story.tsx │ ├── WinnerTeamAnnounce.tsx │ └── winner_team_announce.scss ├── test ├── fixtures │ ├── c4Planted.json │ └── c4Refusing.json └── util │ └── loadFixture.ts ├── tsconfig.json ├── tsconfig.server.json ├── tslint.json └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | ### project specific settings 2 | 3 | # build target 4 | build/ 5 | server/ 6 | 7 | ### https://raw.github.com/github/gitignore/ead0f8e25c9cc58ca70594d557d0dec8a9c08a1d/Node.gitignore 8 | 9 | # Logs 10 | logs 11 | *.log 12 | npm-debug.log* 13 | 14 | # Runtime data 15 | pids 16 | *.pid 17 | *.seed 18 | *.pid.lock 19 | 20 | # Directory for instrumented libs generated by jscoverage/JSCover 21 | lib-cov 22 | 23 | # Coverage directory used by tools like istanbul 24 | coverage 25 | 26 | # nyc test coverage 27 | .nyc_output 28 | 29 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 30 | .grunt 31 | 32 | # node-waf configuration 33 | .lock-wscript 34 | 35 | # Compiled binary addons (http://nodejs.org/api/addons.html) 36 | build/Release 37 | 38 | # Dependency directories 39 | node_modules 40 | jspm_packages 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional REPL history 46 | .node_repl_history 47 | 48 | 49 | ### https://raw.github.com/github/gitignore/fceac113a3a20e00718d6317e468eec27f6e2d99/Global/VisualStudioCode.gitignore 50 | 51 | .vscode 52 | 53 | 54 | ### https://raw.github.com/github/gitignore/fceac113a3a20e00718d6317e468eec27f6e2d99/Global/JetBrains.gitignore 55 | 56 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 57 | 58 | *.iml 59 | 60 | ## Directory-based project format: 61 | .idea/ 62 | # if you remove the above rule, at least ignore the following: 63 | 64 | # User-specific stuff: 65 | # .idea/workspace.xml 66 | # .idea/tasks.xml 67 | # .idea/dictionaries 68 | # .idea/shelf 69 | 70 | # Sensitive or high-churn files: 71 | # .idea/dataSources.ids 72 | # .idea/dataSources.xml 73 | # .idea/sqlDataSources.xml 74 | # .idea/dynamic.xml 75 | # .idea/uiDesigner.xml 76 | 77 | # Gradle: 78 | # .idea/gradle.xml 79 | # .idea/libraries 80 | 81 | # Mongo Explorer plugin: 82 | # .idea/mongoSettings.xml 83 | 84 | ## File-based project format: 85 | *.ipr 86 | *.iws 87 | 88 | ## Plugin-specific files: 89 | 90 | # IntelliJ 91 | /out/ 92 | 93 | # mpeltonen/sbt-idea plugin 94 | .idea_modules/ 95 | 96 | # JIRA plugin 97 | atlassian-ide-plugin.xml 98 | 99 | # Crashlytics plugin (for Android Studio and IntelliJ) 100 | com_crashlytics_export_strings.xml 101 | crashlytics.properties 102 | crashlytics-build.properties 103 | fabric.properties 104 | 105 | .DS_Store 106 | -------------------------------------------------------------------------------- /.storybook/addons.js: -------------------------------------------------------------------------------- 1 | // To get our default addons (actions and links) 2 | import "@storybook/addons"; 3 | // To add the knobs addon 4 | import "@storybook/addon-knobs/register" 5 | -------------------------------------------------------------------------------- /.storybook/config.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { configure } from "@storybook/react"; 3 | 4 | 5 | const req = require.context("../src/views", true, /Story\.tsx$/); 6 | 7 | function loadStories() { 8 | req.keys().sort().forEach(req) 9 | } 10 | 11 | configure(loadStories, module); 12 | 13 | -------------------------------------------------------------------------------- /.storybook/webpack.config.js: -------------------------------------------------------------------------------- 1 | const config = require("../webpack.config.js"); 2 | const path = require("path"); 3 | 4 | config.entry = undefined; 5 | config.plugins = undefined; 6 | config.externals = undefined; 7 | config.output = undefined; 8 | config.target = undefined; 9 | 10 | config.module.rules.push( 11 | { 12 | test: /\.ts(x?)$/, 13 | enforce: "pre", 14 | use: "tslint-loader", 15 | include: { 16 | include: [path.join(__dirname, "../src/views")] 17 | }, 18 | } 19 | ); 20 | 21 | module.exports = config; 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | csgo-custom-hud 2 | ======= 3 | 4 | react based cs:go custom hud. 5 | 6 | # How to use 7 | ## before running app. 8 | - `gameConfig/gamestate_integration_observerspectator.cfg` needs to be placed in cfg folder in CS:GO location 9 | - `gameConfig/observer.cfg` needs to be placed in cfg folder in CS:GO location. 10 | 11 | ## run app 12 | ```sh 13 | npm i 14 | npm run build 15 | npm start 16 | ``` 17 | ## configuration 18 | ## hud settings 19 | you may edit `/src/config/hudSettings.ts`. 20 | For example, 21 | ```js 22 | export const hudSettings: HudSettings = { 23 | showTeamMoney: true, // show team money when round is freeze time. 24 | }; 25 | ``` 26 | 27 | ### team config 28 | you may edit `/src/config/teamInfo.ts`. 29 | For example, 30 | ```js 31 | export const team1: TeamInfo = { 32 | name: "NiP", 33 | logo: "nip.png", // You need to place the file in `/src/resources/teams` 34 | }; 35 | 36 | export const team2: TeamInfo = { 37 | name: "fnatic", 38 | logo: "fnatic.png", // You need to place the file in `/src/resources/teams` 39 | }; 40 | ``` 41 | ### player config 42 | you may edit `/src/config/playerInfo`. 43 | For example, 44 | ```js 45 | export const playerInfoList: PlayerInfoList = { 46 | // `76561198005627722` is Steam ID. 47 | "76561198005627722": { 48 | twitterId: "@thiry_sk", 49 | image: "shroud.jpg", 50 | }, 51 | }; 52 | ``` 53 | ### shortcuts 54 | - `Alt+Left` => swap team information. 55 | - `Alt+Up` => Toggle show/hide HUD. 56 | 57 | # For developer 58 | ## how to enable Chrome dev tools 59 | ```sh 60 | npm run install:sdk 61 | npm run build 62 | npm start 63 | ``` 64 | Now you may press `F12`, then you can use Chrome dev tools. 65 | ## how to start storybook 66 | ```sh 67 | npm i 68 | npm run start:storybook 69 | ``` 70 | access [http://localhost:3000/](http://localhost:3000/). 71 | Story subjects are currently written in Japanese. 72 | I will change to English whenever I feel like. -------------------------------------------------------------------------------- /gameConfig/gamestate_integration_observerspectator.cfg: -------------------------------------------------------------------------------- 1 | "Observer All Players v.1" 2 | { 3 | "uri" "http://127.0.0.1:3000" 4 | "timeout" "5.0" 5 | "buffer" "0.1" 6 | "throttle" "0.1" 7 | "heartbeat" "0.1" 8 | "data" 9 | { 10 | "provider" "1" 11 | "map" "1" 12 | "round" "1" 13 | "player_id" "1" 14 | "allplayers_id" "1" // Same as 'player_id' but for all players. 'allplayers' versions are only valid for HLTV and observers 15 | "player_state" "1" 16 | "allplayers_state" "1" 17 | "allplayers_match_stats" "1" 18 | "allplayers_weapons" "1" 19 | "allplayers_position" "1" // output the player world positions, only valid for HLTV or spectators. 20 | "phase_countdowns" "1" // countdowns of each second remaining for game phases, eg round time left, time until bomb explode, freezetime. Only valid for HLTV or spectators. 21 | } 22 | } -------------------------------------------------------------------------------- /gameConfig/observer.cfg: -------------------------------------------------------------------------------- 1 | cl_draw_only_deathnotices 1 2 | cl_drawhud_force_radar 1 -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /jestconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "transform": { 3 | "^.+\\.tsx?$": "ts-jest" 4 | }, 5 | "roots": [ 6 | "{this.props.twitterId}
180 | ); 181 | }; 182 | 183 | render() { 184 | if (!this.props.name) { 185 | return null; 186 | } 187 | const playerImage = PlayerImageResolver.resolve(this.props.image); 188 | return ( 189 |{this.props.name}
206 | {this.createPlayerInfo()} 207 |52 | Team money: 53 |
54 |59 | ${this.props.totalTeamMoney} 60 |
61 |74 | Equipment value: 75 |
76 |81 | ${this.props.totalEquipmentValue} 82 |
83 |DEFUSING
97 |{teamInfo.score}
125 |{teamInfo.name}
130 |extends React.Component
{
3 |
4 | private previousProps: string;
5 | private previousState: string;
6 |
7 | shouldComponentUpdate(nextProps: P, nextState: S) {
8 | const stringifiedNextProps = JSON.stringify(nextProps);
9 | const stringifiedNextState = JSON.stringify(nextState);
10 |
11 | const hasDifference =
12 | this.previousProps !== stringifiedNextProps || this.previousState !== stringifiedNextState;
13 |
14 | if (hasDifference) {
15 | this.previousProps = stringifiedNextProps;
16 | this.previousState = stringifiedNextState;
17 | }
18 |
19 | return hasDifference;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/views/winnerTeamAnnounce/Story.tsx:
--------------------------------------------------------------------------------
1 | import * as React from "react";
2 | import { storiesOf } from "@storybook/react";
3 | import { WinnerTeamAnnounce, WinnerTeamAnnounceProps } from "./WinnerTeamAnnounce";
4 | import { GameStateIntegration } from "../../dataTypes";
5 | import Team = GameStateIntegration.Team;
6 | import { select, withKnobs } from "@storybook/addon-knobs";
7 | import { SlotSide } from "../../util/slotSideResolver";
8 |
9 | export const props = (team: Team): WinnerTeamAnnounceProps => {
10 | const slotSide = select