Compare commits
34 commits
Author | SHA1 | Date | |
---|---|---|---|
1ab9848ee7 | |||
3c7d101d72 | |||
c210ae8e81 | |||
a6359cca7b | |||
ffebff3229 | |||
106dc517f5 | |||
f9fb8d7a4e | |||
bbd8d882e6 | |||
aeba107b31 | |||
33571dc3ef | |||
1a7f50476b | |||
d823e55e92 | |||
5df7dca06f | |||
854cf56bce | |||
f8418e36e3 | |||
1fb7e162df | |||
fa37d4390b | |||
b37cca33c4 | |||
1e5ce5fda2 | |||
beabe6b56a | |||
0317053e4c | |||
25184a27d2 | |||
22de1eee4b | |||
3fd5113d20 | |||
4dc04d25da | |||
4c10c59b3b | |||
f59718a144 | |||
b517914b45 | |||
d509a618b4 | |||
f78c0ccd8b | |||
7d15cf225f | |||
c39649d1ff | |||
195e44c005 | |||
b2b7074213 |
30 changed files with 1363 additions and 969 deletions
10
.vscode/settings.json
vendored
10
.vscode/settings.json
vendored
|
@ -1,5 +1,13 @@
|
|||
{
|
||||
"cSpell.words": ["Behaviour", "Prefs", "headshot", "leaderboard", "wbm"],
|
||||
"cSpell.words": [
|
||||
"Behaviour",
|
||||
"developomp",
|
||||
"headshot",
|
||||
"leaderboard",
|
||||
"Prefs",
|
||||
"wbm"
|
||||
],
|
||||
|
||||
"editor.formatOnSave": true,
|
||||
"editor.formatOnPaste": true,
|
||||
|
||||
|
|
18
CONTRIBUTING.md
Normal file
18
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Contribution guide
|
||||
|
||||
## feature structure
|
||||
|
||||
- All features should be contained in the `WBM/features` folder.
|
||||
|
||||
### Feature functions
|
||||
|
||||
- All features can have at most one function to be called in each event functions.
|
||||
- feature function should have the following format: `<prefix><feature name>`
|
||||
|
||||
| Event function | feature function prefix |
|
||||
| -------------: | :---------------------- |
|
||||
| `Awake` | `init` |
|
||||
| `Start` | `setup` |
|
||||
| `Update` | `do` |
|
||||
| `OnGUI` | `draw` |
|
||||
| `onDestroy` | `destroy` |
|
224
README.md
224
README.md
|
@ -1,15 +1,23 @@
|
|||
# [War Brokers Mods (WBM)](https://github.com/War-Brokers-Mods/WBM)
|
||||
|
||||

|
||||
[](https://discord.gg/aQqamSCUcS)
|
||||
WBM has been officially included into the game
|
||||
|
||||
> **IF YOU USE THIS TO DEVELOP HACKS YOUR MOM IS GAY.**
|
||||
<details>
|
||||
<summary>Potentially outdated information (click to unfold)</summary>
|
||||
|
||||
[](https://developomp.com/portfolio/wbm)
|
||||
[](https://discord.gg/aQqamSCUcS)
|
||||
[](https://www.youtube.com/watch?v=ZBE3nVvHwF8&t=64s)
|
||||
|
||||
<p align="center">
|
||||
<strong>IF YOU USE THIS TO DEVELOP HACKS YOUR MOM IS GAY.</strong>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<img src="images/WBM.png" alt="WBM logo"/>
|
||||
</p>
|
||||
|
||||
**W**ar **B**rokers **M**ods, AKA **WBM** is a unofficial mod for [War Brokers](https://store.steampowered.com/app/750470).<br />
|
||||
**W**ar **B**rokers **M**ods, AKA **WBM** is a mod for [War Brokers](https://store.steampowered.com/app/750470).<br />
|
||||
|
||||
<details>
|
||||
<summary>Example Images (click to unfold)</summary>
|
||||
|
@ -22,36 +30,38 @@
|
|||
|
||||
## Installation
|
||||
|
||||
Only Windows, MacOS, and Linux are officially supported. It is Not compatible with browsers.
|
||||
Only Windows, MacOS, and Linux are officially supported. It does **NOT** work on browsers.
|
||||
|
||||
> **WARNING**<br />
|
||||
> I do not upload WBM anywhere other than github. If you find it elsewhere, IT IS NOT UPLOADED BY ME.
|
||||
Usage of the [WBM Installer](https://github.com/War-Brokers-Mods/WBM-installer/releases) is recommended.
|
||||
|
||||
<details>
|
||||
<summary>Manual Installation Instruction (not recommended) (click to unfold)</summary>
|
||||
|
||||
### 1. Install BepInEx
|
||||
|
||||
1. Download the latest version of BepInEx **version 5** from [here](https://github.com/BepInEx/BepInEx/releases). It is important that you download the right version.
|
||||
1. Download the latest version of [BepInEx](https://github.com/BepInEx/BepInEx/releases) **version 5**.
|
||||
|
||||
| Platform | Filename |
|
||||
| ------------: | :---------------------------- |
|
||||
| Linux & MacOS | BepInEx\_**unix_5**.Y.Z.W.zip |
|
||||
| Windows | BepInEx\_**x86_5**.Y.Z.W.zip |
|
||||
|
||||
2. Extract (Unzip) the content**S** to where the game is installed.
|
||||
2. Extract all the contents to where the game is installed.
|
||||
|
||||
How to find game location:<br />
|
||||

|
||||
|
||||
The folder structure should look like this after unzipping file:
|
||||
Now the folder structure should look like this:
|
||||
|
||||
```
|
||||
WarBrokers/
|
||||
├── BepInEx/
|
||||
│ ├── core/
|
||||
│ └ other files...
|
||||
└ other files...
|
||||
│ ├── core/
|
||||
│ └── ...
|
||||
└── ...
|
||||
```
|
||||
|
||||
3. If you are using Linux or MacOS, you must also perform the following setup:
|
||||
3. **If you are using Linux or MacOS:**
|
||||
|
||||
1. make `run_bepinex.sh` executable: `chmod u+x run_bepinex.sh`
|
||||
2. Add launch option
|
||||
|
@ -59,102 +69,102 @@ Only Windows, MacOS, and Linux are officially supported. It is Not compatible wi
|
|||
where to find game properties:<br />
|
||||

|
||||
|
||||
If you're on linux, set the launch option to:
|
||||
**If you're using linux**, set the launch option to:
|
||||
|
||||
```bash
|
||||
./run_bepinex.sh %command%
|
||||
```
|
||||
|
||||
If you're on Mac, open a terminal in the game folder and run
|
||||
**If you're using Mac**, open a terminal in the game folder and run
|
||||
|
||||
```bash
|
||||
pwd
|
||||
```
|
||||
|
||||
This will print the full path to the game folder. Copy it. Next, set launch option to
|
||||
This will print the full path to the game folder. Copy it, then set the launch option to:
|
||||
|
||||
```bash
|
||||
"PUT_RESULT_FROM_PWD_HERE/run_bepinex.sh" %command%
|
||||
"PWD_RESULT_HERE/run_bepinex.sh" %command%
|
||||
```
|
||||
|
||||
4. Run the game at least once to generate the plugins folder as well as other necessary files.
|
||||
|
||||
### 2. Install WBM
|
||||
|
||||
1. [Download](https://github.com/War-Brokers-Mods/WBM/releases/latest) the latest version of WBM. (`WBM.zip` file)
|
||||
2. Unzip it in the `<Game folder>/BepInEx/plugins` folder.
|
||||
2. Unzip it in the `<game folder>/BepInEx/plugins` folder. Create one if it doesn't exist.
|
||||
|
||||
It should look like this:
|
||||
The folder structure should look like this after unzipping the file:
|
||||
|
||||
```
|
||||
plugins (in the BepInEx folder)
|
||||
└── WBM
|
||||
├── assets
|
||||
│ └── audio
|
||||
│ └── ...
|
||||
└── WBM.dll
|
||||
WarBrokers/
|
||||
├── BepInEx/
|
||||
│ ├── plugins/
|
||||
│ │ └── WBM
|
||||
│ │ ├── assets/
|
||||
│ │ ├── WBM.dll
|
||||
│ │ └── ...
|
||||
│ ├── core/
|
||||
│ └── ...
|
||||
└── ...
|
||||
```
|
||||
|
||||
### 3. Set up OBS (optional)
|
||||
|
||||
1. [Download](https://github.com/War-Brokers-Mods/WBM-Overlays/archive/refs/heads/master.zip) the overlays and Unzip it anywhere. (Source code can be found [here](https://github.com/War-Brokers-Mods/WBM-Overlays))
|
||||
2. Create a new browser source in OBS studio.
|
||||
|
||||

|
||||
|
||||
3. Check the `Local file` checkbox and use a `.html` file of the overlay you want to use. Width and height of the overlays can be found [here](#obs-overlays).
|
||||
|
||||

|
||||
That's it! You can open War Brokers now.
|
||||
|
||||
### Updating
|
||||
|
||||
Simply go through the installation process again and replace existing files. You don't have to reinstall BepInEx to reinstall WBM.
|
||||
|
||||
</details>
|
||||
|
||||
## Usage
|
||||
|
||||
### Warning
|
||||
|
||||
The order of keystroke matters.<br />
|
||||
For example, pressing <kbd>RShift</kbd>+<kbd>A</kbd> is different from pressing <kbd>A</kbd>+<kbd>RShift</kbd>.<br/>
|
||||
This is to prevent situation where <kbd>RShift</kbd>+<kbd>A</kbd> fires when the user intended to press <kbd>LCtrl</kbd>+<kbd>RShift</kbd>+<kbd>A</kbd>.
|
||||
|
||||
### Default shortcuts
|
||||
|
||||
- Hold down <kbd>LCtrl</kbd> or <kbd>RShift</kbd> to show shortcuts in-game.
|
||||
- Press F1 to show menu. Press outside the menu to close.
|
||||
- Press F1 to show menu. Click outside the menu to close it.
|
||||
|
||||
| Function | Default Shortcut |
|
||||
| ------------------------------------ | --------------------------------------------------- |
|
||||
| Show Menu | <kbd>F1</kbd> |
|
||||
| <br /> | |
|
||||
| Move GUI | <kbd>LCtrl</kbd>+<kbd>LShift</kbd>+<kbd>Arrow</kbd> |
|
||||
| Move GUI by one pixel | <kbd>LCtrl</kbd>+<kbd>Arrow</kbd> |
|
||||
| Reset GUI position | <kbd>LCtrl</kbd>+<kbd>R</kbd> |
|
||||
| <br /> | |
|
||||
| Toggle All GUI visibility | <kbd>RShift</kbd>+<kbd>A</kbd> |
|
||||
| Toggle Player statistics visibility | <kbd>RShift</kbd>+<kbd>P</kbd> |
|
||||
| Toggle Weapon statistics visibility | <kbd>RShift</kbd>+<kbd>W</kbd> |
|
||||
| Toggle Team statistics visibility | <kbd>RShift</kbd>+<kbd>L</kbd> |
|
||||
| Toggle Elo visibility on leaderboard | <kbd>RShift</kbd>+<kbd>E</kbd> |
|
||||
| Squad server visibility | <kbd>RShift</kbd>+<kbd>S</kbd> |
|
||||
| Testing servers visibility | <kbd>RShift</kbd>+<kbd>T</kbd> |
|
||||
| Kill streak sound effect | <kbd>RShift</kbd>+<kbd>F</kbd> |
|
||||
| Clear chat | <kbd>RShift</kbd>+<kbd>Z</kbd> |
|
||||
| Clear Messages (kills and death log) | <kbd>RShift</kbd>+<kbd>X</kbd> |
|
||||
| <br /> | |
|
||||
| Toggle shift to crouch | <kbd>RShift</kbd>+<kbd>C</kbd> |
|
||||
|
||||
#### Warning
|
||||
|
||||
The order of keystroke matter. For example, pressing <kbd>RShift</kbd>+<kbd>A</kbd> is different from pressing <kbd>A</kbd>+<kbd>RShift</kbd>. This is to prevent situation where <kbd>RShift</kbd>+<kbd>A</kbd> fires when the user intended to press <kbd>LCtrl</kbd>+<kbd>RShift</kbd>+<kbd>A</kbd>.
|
||||
| Function | Default Shortcut |
|
||||
| ------------------------------------------ | --------------------------------------------------- |
|
||||
| Show Menu | <kbd>F1</kbd> |
|
||||
| <br /> | |
|
||||
| Move GUI (long press) | <kbd>LCtrl</kbd>+<kbd>LShift</kbd>+<kbd>Arrow</kbd> |
|
||||
| Move GUI by one pixel | <kbd>LCtrl</kbd>+<kbd>Arrow</kbd> |
|
||||
| Reset GUI position | <kbd>LCtrl</kbd>+<kbd>R</kbd> |
|
||||
| <br /> | |
|
||||
| Toggle All GUI visibility | <kbd>RShift</kbd>+<kbd>A</kbd> |
|
||||
| Toggle player statistics visibility | <kbd>RShift</kbd>+<kbd>P</kbd> |
|
||||
| Toggle weapon statistics visibility | <kbd>RShift</kbd>+<kbd>W</kbd> |
|
||||
| Toggle team statistics visibility | <kbd>RShift</kbd>+<kbd>L</kbd> |
|
||||
| Toggle kills Elo visibility on leaderboard | <kbd>RShift</kbd>+<kbd>E</kbd> |
|
||||
| Toggle squad server visibility | <kbd>RShift</kbd>+<kbd>S</kbd> |
|
||||
| Toggle Testing servers visibility | <kbd>RShift</kbd>+<kbd>T</kbd> |
|
||||
| Toggle kill streak sound effect | <kbd>RShift</kbd>+<kbd>F</kbd> |
|
||||
| Clear chat | <kbd>RShift</kbd>+<kbd>Z</kbd> |
|
||||
| Clear kills and death log | <kbd>RShift</kbd>+<kbd>X</kbd> |
|
||||
| <br /> | |
|
||||
| Toggle shift to crouch | <kbd>RShift</kbd>+<kbd>C</kbd> |
|
||||
|
||||
## Features
|
||||
|
||||
<details>
|
||||
<summary>A list of all the features in WBM (click to unfold)</summary>
|
||||
|
||||
- in-game menu
|
||||
- reconfigure shortcut keys
|
||||
- custom shortcut keys
|
||||
- clear chat
|
||||
- clear game messages (kills, deaths, missile launch, bomb diffuse, etc.)
|
||||
- Extended fps limit (5~240 => disabled~1000)
|
||||
- Extended fps limit (5\~240 => disabled\~1000) (may be buggy)
|
||||
|
||||
### in-game overlays
|
||||
|
||||
- Tab Leaderboard
|
||||
- Leaderboard
|
||||
|
||||
- show kills Elo
|
||||
- kills Elo for each player
|
||||
|
||||
- Player statistics
|
||||
|
||||
|
@ -189,76 +199,92 @@ The order of keystroke matter. For example, pressing <kbd>RShift</kbd>+<kbd>A</k
|
|||
|
||||
### Controls
|
||||
|
||||
- Shift to crouch
|
||||
- Shift to crouch (does not interfere with breath holding)
|
||||
|
||||
### Sound effects
|
||||
|
||||
- 10 kill streak: "rampage"
|
||||
- 20 kill streak: "killing spree"
|
||||
- 30 kill streak: "unstoppable"
|
||||
- 50 kill streak: "godlike"
|
||||
- 69 kill streak: "nice"
|
||||
- 10 kill streak: ["rampage"](./assets/audio/rampage.wav)
|
||||
- 20 kill streak: ["killing spree"](<./assets/audio/killing spree.wav>)
|
||||
- 30 kill streak: ["unstoppable"](./assets/audio/unstoppable.wav)
|
||||
- 50 kill streak: ["godlike"](./assets/audio/godlike.wav)
|
||||
- 69 kill streak: ["nice"](./assets/audio/nice.wav)
|
||||
|
||||
### OBS overlays
|
||||
|
||||
- kills and games Elo (size: 355x140)
|
||||
|
||||

|
||||
### [OBS overlays](https://github.com/War-Brokers-Mods/WBM-Overlays)
|
||||
|
||||
### Etc
|
||||
|
||||
- persistent configuration
|
||||
- kill streak sound effect
|
||||
- Quickly change settings with keyboard shortcut
|
||||
- Quickly change settings with keyboard shortcuts
|
||||
|
||||
</details>
|
||||
|
||||
## Limitations
|
||||
|
||||
WBM is not a hack. WBM will not include any features that will give unfair advantage. These features include but not limited to: extended minimap zoom, quick weapon swap, instant zoom, extended field of view, audio filter, etc.
|
||||
WBM is not a hack.
|
||||
WBM will not include any features that will give unfair advantages.
|
||||
These features include but are not limited to:
|
||||
extended minimap zoom, quick weapon swap, instant zoom, extended field of view, audio filter, etc.
|
||||
|
||||
WBM will not include any custom skins. Micro-transaction accounts for a significant portion of the developers' income and WBM will not include any feature that will damage it.
|
||||
WBM will not include any custom skins.
|
||||
Micro-transaction accounts for a significant portion of the developers' income,
|
||||
and WBM will not include any feature that will affect it.
|
||||
|
||||
## Building
|
||||
|
||||
If you are a casual user, this is completely unnecessary. **This is only recommended for developers.**
|
||||
If you are a casual user, this is completely unnecessary.
|
||||
**This is only intended for developers.**
|
||||
|
||||
<details>
|
||||
<summary>Building instructions (click to unfold)</summary>
|
||||
|
||||
<br />
|
||||
|
||||
The guide is intentionally left incomplete.
|
||||
To prevent any regular developers from using this mod to develop hacks,
|
||||
I won't provide any help when it comes to building the mod from scratch.
|
||||
|
||||
This guide is only useful to people who's already familiar with reverse engineering,
|
||||
and can create hacks on their own anyway.
|
||||
|
||||
> Assumes that working directory is project root.
|
||||
|
||||
1. Install .NET sdk.
|
||||
2. Clone this repository.
|
||||
3. Copy all DLL files from `<WB install path>/war_brokers_Data/Managed/` and `<WB install path>/BepInEx/core` to `WBM/dll/`. Create directory if it does not exist.
|
||||
4. Download [BepInEx configuration manager v16](https://github.com/BepInEx/BepInEx.ConfigurationManager/releases) and put the dll file in `WBM/dll` directory. Other file(s) in the zip file can be deleted.
|
||||
5. Create `scripts/config.sh`.
|
||||
2. Copy all DLL files from `<WB install path>/war_brokers_Data/Managed/` and `<WB install path>/BepInEx/core` to `WBM/dll/`. Create directory if it does not exist.
|
||||
3. Download and unzip [BepInEx configuration manager v16](https://github.com/BepInEx/BepInEx.ConfigurationManager/releases) then copy the dll file to the `WBM/dll` directory.
|
||||
4. Create `scripts/config.sh`. This will be used to quickly test the mod without having to manually install it.
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
|
||||
WB_PLUGINS_DIR="<PATH_TO_PLUGINS_DIRECTORY_HERE>"
|
||||
WB_PLUGINS_DIR="<PATH_TO_PLUGIN_INSTALL_DIRECTORY>"
|
||||
```
|
||||
|
||||
5. Install the `zip` cli. Most likely you already have it.
|
||||
6. Now you can run the scripts.
|
||||
|
||||
- `scripts/debug.sh`: Build WBM in debug mode and copy the files to the plugins directory.
|
||||
- `scripts/release.sh`: Create a zip file that can be uploaded in the gh release section.
|
||||
- `scripts/debug.sh`: Builds WBM in debug mode and copy the files to the plugins directory.
|
||||
- `scripts/release.sh`: Creates a zip file that can be uploaded to the gh release section.
|
||||
|
||||
</details>
|
||||
|
||||
## Bug reports / Suggestions
|
||||
|
||||
If you have a cool idea that will make WBM better, or if WBM misbehaves in any way (no matter how minor the problem is), feel free go to the [Issues page](https://github.com/War-Brokers-Mods/WBM/issues) and open a new issue!
|
||||
|
||||
## Contributing
|
||||
|
||||
- use GH pull request
|
||||
- use vscode and install [recommended extensions](.vscode/extensions.json). This is required for code formatting.
|
||||
If you have a cool idea that will make WBM better, or if WBM misbehaves in any way (no matter how minor the problem is), feel free go to the [Issues page](https://github.com/War-Brokers-Mods/WBM/issues) and open a new issue! Alternatively, you can report the bug in my [discord server](https://discord.gg/aQqamSCUcS).
|
||||
|
||||
## Special thanks
|
||||
|
||||
- [inorganik](https://github.com/inorganik) for [countUp.js](https://github.com/inorganik/countUp.js)
|
||||
- [l3lackShark](https://github.com/l3lackShark) for [inspiration](https://github.com/l3lackShark/gosumemory)
|
||||
- [jassper0](https://github.com/jassper0) for [Elo overlay design](https://github.com/l3lackShark/static/tree/master/Simplistic)
|
||||
- REKT (discord: `REKT#7777`, 710249221609226320) for:
|
||||
- fps improvement by modifying `boot.config`
|
||||
- shader rework
|
||||
- video tutorial
|
||||
|
||||
## License
|
||||
|
||||
This project is licenced under the [MIT License](https://opensource.org/licenses/MIT).
|
||||
The source code for this project is available under the [MIT License](https://opensource.org/licenses/MIT).
|
||||
|
||||
Fonts:
|
||||
|
||||
- https://fonts.google.com/specimen/Architects+Daughter : OFL (used in WBM logo)
|
||||
|
||||
</details>
|
||||
|
|
119
WBM/Data.cs
119
WBM/Data.cs
|
@ -2,84 +2,51 @@ using System.Runtime.Serialization;
|
|||
|
||||
namespace WBM
|
||||
{
|
||||
public class Data
|
||||
{
|
||||
public enum TeamEnum
|
||||
{
|
||||
None,
|
||||
Red,
|
||||
Blue
|
||||
}
|
||||
public class Data
|
||||
{
|
||||
public enum TeamEnum
|
||||
{
|
||||
None,
|
||||
Red,
|
||||
Blue
|
||||
}
|
||||
|
||||
private enum QuestTypeEnum
|
||||
{
|
||||
Kill,
|
||||
Damage,
|
||||
Package,
|
||||
Missile,
|
||||
Capture,
|
||||
Play,
|
||||
Travel,
|
||||
Assist,
|
||||
Finish
|
||||
}
|
||||
public struct PlayerStatsStruct
|
||||
{
|
||||
public int kills;
|
||||
public int deaths;
|
||||
public int damage;
|
||||
public int longestKill;
|
||||
public int points;
|
||||
public int headShots;
|
||||
public int vote;
|
||||
public int mapVote;
|
||||
public int gamesElo;
|
||||
public int gamesEloDelta;
|
||||
public int killsElo;
|
||||
public int killsEloDelta;
|
||||
}
|
||||
|
||||
public struct PlayerStatsStruct
|
||||
{
|
||||
public int kills;
|
||||
public int deaths;
|
||||
public int damage;
|
||||
public int longestKill;
|
||||
public int points;
|
||||
public int headShots;
|
||||
public int vote;
|
||||
public int mapVote;
|
||||
public int gamesElo;
|
||||
public int gamesEloDelta;
|
||||
public int killsElo;
|
||||
public int killsEloDelta;
|
||||
}
|
||||
public enum GameStateEnum
|
||||
{
|
||||
WaitingOnPlayers,
|
||||
Countdown,
|
||||
GameInProgress,
|
||||
Results
|
||||
}
|
||||
|
||||
public enum GameModeEnum
|
||||
{
|
||||
DeathMatch,
|
||||
DemolitionDerby,
|
||||
ProtectLeader,
|
||||
ResourceCapture,
|
||||
Race,
|
||||
TankBattle,
|
||||
TankKing,
|
||||
CapturePoint,
|
||||
VehicleEscort,
|
||||
PackageDrop,
|
||||
ScudLaunch,
|
||||
BattleRoyale,
|
||||
Competitive,
|
||||
LobbyCompetitive,
|
||||
LobbyBR,
|
||||
Count
|
||||
}
|
||||
[DataContract]
|
||||
public class SerializableData
|
||||
{
|
||||
// game version
|
||||
// gamemode
|
||||
// teammate list
|
||||
// team rank (array of player index)
|
||||
|
||||
public enum GameStateEnum
|
||||
{
|
||||
WaitingOnPlayers,
|
||||
Countdown,
|
||||
GameInProgress,
|
||||
Results
|
||||
}
|
||||
|
||||
[DataContract]
|
||||
public class SerializableData
|
||||
{
|
||||
// game version
|
||||
// gamemode
|
||||
// teammate list
|
||||
// team rank (array of player index)
|
||||
|
||||
[DataMember] public int localPlayerIndex = -1;
|
||||
[DataMember] public string[] nickList = new string[] { };
|
||||
[DataMember] public PlayerStatsStruct[] playerStatsArray = new PlayerStatsStruct[] { };
|
||||
[DataMember] public Data.GameStateEnum gameState;
|
||||
}
|
||||
}
|
||||
[DataMember] public int localPlayerIndex = -1;
|
||||
[DataMember] public string[] nickList = new string[] { };
|
||||
[DataMember] public PlayerStatsStruct[] playerStatsArray = new PlayerStatsStruct[] { };
|
||||
[DataMember] public Data.GameStateEnum gameState;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
38
WBM/MangledNames.cs
Normal file
38
WBM/MangledNames.cs
Normal file
|
@ -0,0 +1,38 @@
|
|||
/// This file contains all information related to matching
|
||||
/// mangles names to something more readable
|
||||
|
||||
namespace WBM
|
||||
{
|
||||
public static class MangledNames
|
||||
{
|
||||
//
|
||||
// Variables
|
||||
//
|
||||
|
||||
public const string AKRifleShotClip = "AJLCLOJGKLF";
|
||||
public const string SMGShotClip = "GDKKJENDFOF";
|
||||
// fps limit value
|
||||
public const string fpsValue = "PFOMGOFNIOE";
|
||||
public const string showElo = "JEFPGBDBGFF";
|
||||
// show squad servers
|
||||
public const string isClan = "GHAAFBAPMMH";
|
||||
// show testing servers
|
||||
public const string isTesting = "CIAFOJDAKFA";
|
||||
public const string chatList = "CBKINJHGBOM";
|
||||
public const string gameState = "HHBJFNILCBJ";
|
||||
public const string nickList = "MBFCFOPONAI";
|
||||
public const string personGun = "FDHBIGANHOH";
|
||||
public const string localPlayerIndex = "INGKMFAPBJC";
|
||||
public const string teamList = "GKDEFMOHMGH";
|
||||
public const string statsList = "GNKKKHEDFAN";
|
||||
|
||||
//
|
||||
// functions
|
||||
//
|
||||
|
||||
public const string drawChatMessage = "IACLHANNPED";
|
||||
public const string clearMessages = "NFNFPNGMKFD";
|
||||
public const string onFPSChanged = "EFDAECNGBEP";
|
||||
public const string addMessage = "GPIKJGHDPEA";
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
using HarmonyLib;
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace WBM
|
||||
{
|
||||
[HarmonyPatch(typeof(webguy))]
|
||||
[HarmonyPatch("FHBMKCDMGII")]
|
||||
class FPSSliderPatch
|
||||
{
|
||||
private static int defaultTargetFrameRate = -1;
|
||||
private static int maxTargetFrameRate = 1000;
|
||||
|
||||
private static GameObject fpsSliderTextObj = GameObject.Find("fpsSlideFuckText");
|
||||
private static Slider slider = GameObject.Find("fpsSlider").GetComponent<Slider>();
|
||||
private static AccessTools.FieldRef<webguy, float> fpsValueRef = AccessTools.FieldRefAccess<webguy, float>("CLLNACDIPHE");
|
||||
|
||||
static bool Prefix(webguy __instance, float JKNNNLEEIAO)
|
||||
{
|
||||
fpsValueRef(__instance) = JKNNNLEEIAO;
|
||||
int targetFrameRate = (int)(JKNNNLEEIAO * maxTargetFrameRate);
|
||||
|
||||
if (targetFrameRate == 0)
|
||||
{
|
||||
((InfernalBehaviour)__instance).KKFJBNFGKEP(fpsSliderTextObj, __instance.HNDAMJPNGAE("Disabled"));
|
||||
targetFrameRate = defaultTargetFrameRate;
|
||||
}
|
||||
else
|
||||
{
|
||||
((InfernalBehaviour)__instance).KKFJBNFGKEP(fpsSliderTextObj, targetFrameRate.ToString());
|
||||
}
|
||||
|
||||
if (targetFrameRate > 0 && targetFrameRate < 5) targetFrameRate = 5;
|
||||
|
||||
Application.targetFrameRate = targetFrameRate;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
namespace WBM
|
||||
{
|
||||
class PrefNames
|
||||
{
|
||||
public const string showSquadServer = "showSquadServer";
|
||||
public const string showTestingServer = "showTestingServer";
|
||||
public const string GUIOffsetX = "GUIOffsetX";
|
||||
public const string GUIOffsetY = "GUIOffsetY";
|
||||
public const string showGUI = "showGUI";
|
||||
public const string showPlayerStats = "showPlayerStats";
|
||||
public const string showWeaponStats = "showWeaponStats";
|
||||
public const string showTeammateStats = "showTeammateStats";
|
||||
public const string showElo = "showElo";
|
||||
public const string shiftToCrouch = "shiftToCrouch";
|
||||
}
|
||||
}
|
109
WBM/Util.cs
109
WBM/Util.cs
|
@ -6,73 +6,74 @@ using System.Text;
|
|||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using System.Runtime.Serialization.Json;
|
||||
using CPersonGun = JABKDMKNMKE;
|
||||
|
||||
namespace WBM
|
||||
{
|
||||
public class Util
|
||||
{
|
||||
public async static Task<AudioClip> fetchAudioClip(string where)
|
||||
{
|
||||
using (UnityWebRequest uwr = UnityWebRequestMultimedia.GetAudioClip("file://" + where, AudioType.WAV))
|
||||
{
|
||||
uwr.SendWebRequest();
|
||||
public class Util
|
||||
{
|
||||
public async static Task<AudioClip> fetchAudioClip(string where)
|
||||
{
|
||||
using (UnityWebRequest uwr = UnityWebRequestMultimedia.GetAudioClip("file://" + where, AudioType.WAV))
|
||||
{
|
||||
uwr.SendWebRequest();
|
||||
|
||||
while (!uwr.isDone) await Task.Delay(10);
|
||||
while (!uwr.isDone) await Task.Delay(10);
|
||||
|
||||
return DownloadHandlerAudioClip.GetContent(uwr);
|
||||
}
|
||||
}
|
||||
return DownloadHandlerAudioClip.GetContent(uwr);
|
||||
}
|
||||
}
|
||||
|
||||
public static string data2JSON(Data.SerializableData data)
|
||||
{
|
||||
MemoryStream stream = new MemoryStream();
|
||||
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Data.SerializableData));
|
||||
public static string data2JSON(Data.SerializableData data)
|
||||
{
|
||||
MemoryStream stream = new MemoryStream();
|
||||
DataContractJsonSerializer serializer = new DataContractJsonSerializer(typeof(Data.SerializableData));
|
||||
|
||||
serializer.WriteObject(stream, data);
|
||||
byte[] json = stream.ToArray();
|
||||
stream.Close();
|
||||
serializer.WriteObject(stream, data);
|
||||
byte[] json = stream.ToArray();
|
||||
stream.Close();
|
||||
|
||||
return Encoding.UTF8.GetString(json, 0, json.Length);
|
||||
}
|
||||
return Encoding.UTF8.GetString(json, 0, json.Length);
|
||||
}
|
||||
|
||||
public static string formatKDR(int kills, int deaths)
|
||||
{
|
||||
return deaths == 0 ? "inf" : formatDecimal((float)kills / deaths);
|
||||
}
|
||||
public static string formatKDR(int kills, int deaths)
|
||||
{
|
||||
return deaths == 0 ? "inf" : formatDecimal((float)kills / deaths);
|
||||
}
|
||||
|
||||
public static string formatDecimal(float number)
|
||||
{
|
||||
return String.Format("{0:0.0}", number);
|
||||
}
|
||||
public static string formatDecimal(float number)
|
||||
{
|
||||
return String.Format("{0:0.0}", number);
|
||||
}
|
||||
|
||||
public static float getGunZoom(NGNJNHEFLHB gun)
|
||||
{
|
||||
return gun.ADLGCCMDNED;
|
||||
}
|
||||
public static float getGunZoom(CPersonGun gun)
|
||||
{
|
||||
// CPersonGun.cameraZoom
|
||||
return gun.IDOOGDDHKOG;
|
||||
}
|
||||
|
||||
public static float getGunFireTimer(NGNJNHEFLHB gun)
|
||||
{
|
||||
return gun.MAKBOBOAAHG;
|
||||
}
|
||||
public static float getGunFireTimer(CPersonGun gun)
|
||||
{
|
||||
// CPersonGun.fireTimer
|
||||
return gun.ABENIMBBCFL;
|
||||
}
|
||||
|
||||
public static float getGunFireVelocity(NGNJNHEFLHB gun)
|
||||
{
|
||||
return gun.HOIKHOJJBOG;
|
||||
}
|
||||
public static float getGunFireVelocity(CPersonGun gun)
|
||||
{
|
||||
// CPersonGun.fireVel
|
||||
return gun.EMDMIEBFHDL;
|
||||
}
|
||||
|
||||
public static float getGunFireRate(NGNJNHEFLHB gun)
|
||||
{
|
||||
return gun.IHEEIAIOABG;
|
||||
}
|
||||
public static float getGunFireRate(CPersonGun gun)
|
||||
{
|
||||
// CPersonGun.fireRate
|
||||
return gun.EDHPPDGFLEB;
|
||||
}
|
||||
|
||||
public static float getGunReloadTimer(NGNJNHEFLHB gun)
|
||||
{
|
||||
return gun.NBLDKJAKFIB;
|
||||
}
|
||||
|
||||
public static float getGunCooldownTimer(NGNJNHEFLHB gun)
|
||||
{
|
||||
return gun.LBOBALHJBDM;
|
||||
}
|
||||
}
|
||||
public static float getGunReloadTimer(CPersonGun gun)
|
||||
{
|
||||
// CPersonGun.reloadTimer
|
||||
return gun.ALNGHNHLNGP;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
387
WBM/WBM.cs
387
WBM/WBM.cs
|
@ -1,334 +1,87 @@
|
|||
using BepInEx;
|
||||
using BepInEx.Configuration;
|
||||
|
||||
using HarmonyLib;
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace WBM
|
||||
{
|
||||
[BepInPlugin("com.developomp.wbm", "War Brokers Mods", "1.7.1.0")]
|
||||
public partial class WBM : BaseUnityPlugin
|
||||
{
|
||||
private void Awake()
|
||||
{
|
||||
this.harmony = new Harmony("com.developomp.wbm");
|
||||
this.harmony.PatchAll();
|
||||
}
|
||||
/// <summary>
|
||||
/// Class <c>WBM</c> is a regular unity script component (<c>GameObject</c>).
|
||||
/// The functions <c>Awake</c>, <c>Start</c>, <c>Update</c>, <c>OnGUI</c>, and <c>onDestroy</c>
|
||||
/// are event functions that gets called on specific stages of the component's lifecycle.
|
||||
/// More information can be found in the <see href="https://docs.unity3d.com/Manual/ExecutionOrder.html">unity's documentation page</see>.
|
||||
/// </summary>
|
||||
[BepInPlugin(WBM.programID, WBM.programName, WBM.programVersion)]
|
||||
public partial class WBM : BaseUnityPlugin
|
||||
{
|
||||
public const string programID = "com.developomp.wbm";
|
||||
public const string programName = "War Brokers Mods";
|
||||
public const string programVersion = "1.14.0.0";
|
||||
|
||||
private async void Start()
|
||||
{
|
||||
Logger.LogDebug("Initializing");
|
||||
/// This function is called as soon as the component becomes active.
|
||||
/// It is the first event function that's called during the component's lifecycle.
|
||||
private void Awake()
|
||||
{
|
||||
Logger.LogDebug("Initializing");
|
||||
|
||||
this.webguy = FindObjectOfType<webguy>();
|
||||
this.initCore();
|
||||
}
|
||||
|
||||
System.Type webguyType = typeof(webguy);
|
||||
/// This function is called only once before the first frame update.
|
||||
/// The component is more or less initialized at this point,
|
||||
/// and it is this function that completes the initialization process.
|
||||
private async void Start()
|
||||
{
|
||||
await this.setupCore();
|
||||
|
||||
this.showEloOnLeaderboardRef = webguyType.GetField("KDOBENAOLLF", bindFlags);
|
||||
this.showSquadServerRef = webguyType.GetField("PHPIBBCFKFI", bindFlags);
|
||||
this.showTestingServerRef = webguyType.GetField("LHHEGFHLNJE", bindFlags);
|
||||
this.playerStatsArrayRef = webguyType.GetField("NAFCGDLLFJC", bindFlags);
|
||||
this.currentAreaRef = webguyType.GetField("FLJLJNLDFAM", bindFlags);
|
||||
this.teamListRef = webguyType.GetField("MNEJLPDLMBH", bindFlags);
|
||||
this.localPlayerIndexRef = webguyType.GetField("ALEJJPEPFOG", bindFlags);
|
||||
this.personGunRef = webguyType.GetField("IEGLIMLBDPH", bindFlags);
|
||||
this.nickListRef = webguyType.GetField("CLLDJOMEKIP", bindFlags);
|
||||
this.gameStateRef = webguyType.GetField("MCGMEPGBCKK", bindFlags);
|
||||
this.chatListRef = webguyType.GetField("MOOBJBOCANE", bindFlags);
|
||||
this.setupOldGunSound();
|
||||
this.setupWSSever();
|
||||
this.setupClearChat();
|
||||
this.setupShiftToCrouch();
|
||||
this.setupShowEloOnLeaderBoard();
|
||||
this.setupShowSquadServer();
|
||||
this.setupShowTestingServer();
|
||||
this.setupKillStreakSFX();
|
||||
|
||||
this.addMessageFuncRef = webguyType.GetMethod("NBPKLIOLLEI", bindFlags);
|
||||
this.clearMessagesFuncRef = webguyType.GetMethod("IOCHBBACKFA", bindFlags);
|
||||
this.drawChatMessageFuncRef = webguyType.GetMethod("EBDKFEJMEMB", bindFlags);
|
||||
StartCoroutine(UpdateValuesFunction());
|
||||
|
||||
this.oldGunSoundRef = webguyType.GetField("PINGEJAHHDI", bindFlags);
|
||||
this.AKSoundRef = webguyType.GetField("BJFBGCMEELH", bindFlags);
|
||||
this.SMGSoundRef = webguyType.GetField("HKDDIMFIHCE", bindFlags);
|
||||
Logger.LogDebug("Ready!");
|
||||
}
|
||||
|
||||
// Configurations
|
||||
this.showGUI = Config.Bind("Config", "show GUI", true);
|
||||
this.showGUIShortcut = Config.Bind("Hotkeys", "show GUI Shortcut", new KeyboardShortcut(KeyCode.A, KeyCode.RightShift));
|
||||
/// This function is called on each frame.
|
||||
private void Update()
|
||||
{
|
||||
this.doCore();
|
||||
|
||||
this.GUIOffsetX = Config.Bind("Config", "GUI Horizontal position", 38, new ConfigDescription("WBM GUI Horizontal position", new AcceptableValueRange<int>(0, Screen.width)));
|
||||
this.GUIOffsetY = Config.Bind("Config", "GUI Vertical position", 325, new ConfigDescription("WBM GUI Vertical position", new AcceptableValueRange<int>(0, Screen.height)));
|
||||
this.resetGUIShortcut = Config.Bind("Hotkeys", "reset GUI position", new KeyboardShortcut(KeyCode.R, KeyCode.LeftControl));
|
||||
this.doKillStreakSFX();
|
||||
this.doPlayerStats();
|
||||
this.doWeaponStats();
|
||||
this.doTeamStats();
|
||||
this.doLeaderboardElo();
|
||||
this.doShowSquadServer();
|
||||
this.doTestingServer();
|
||||
this.doClearChat();
|
||||
this.doclearMessage();
|
||||
this.doShiftToCrouch();
|
||||
}
|
||||
|
||||
this.shiftToCrouch = Config.Bind("Config", "shift to crouch", true);
|
||||
this.shiftToCrouchShortcut = Config.Bind("Hotkeys", "shift to crouch", new KeyboardShortcut(KeyCode.C, KeyCode.RightShift));
|
||||
/// Called multiple times per frame in response to GUI events.
|
||||
/// The Layout and Repaint events are processed first,
|
||||
/// followed by a Layout and keyboard/mouse event for each input event.
|
||||
private void OnGUI()
|
||||
{
|
||||
this.drawCoreUI();
|
||||
|
||||
this.killStreakSFX = Config.Bind("Config", "kill streak sound effect", true);
|
||||
this.killStreakSFXShortcut = Config.Bind("Hotkeys", "kill streak sound effect", new KeyboardShortcut(KeyCode.F, KeyCode.RightShift));
|
||||
// don't draw if player is not in a games
|
||||
if (this.data.localPlayerIndex < 0) return;
|
||||
|
||||
this.showPlayerStats = Config.Bind("Config", "show player statistics", true);
|
||||
this.showPlayerStatsShortcut = Config.Bind("Hotkeys", "show player statistics", new KeyboardShortcut(KeyCode.P, KeyCode.RightShift));
|
||||
this.drawPlayerStats();
|
||||
this.drawWeaponStats();
|
||||
this.drawTeamStats();
|
||||
}
|
||||
|
||||
this.showWeaponStats = Config.Bind("Config", "show weapon statistics", true);
|
||||
this.showWeaponStatsShortcut = Config.Bind("Hotkeys", "show weapon statistics", new KeyboardShortcut(KeyCode.W, KeyCode.RightShift));
|
||||
|
||||
this.showTeamStats = Config.Bind("Config", "show team statistics", true);
|
||||
this.showTeamStatsShortcut = Config.Bind("Hotkeys", "show team statistics", new KeyboardShortcut(KeyCode.L, KeyCode.RightShift));
|
||||
|
||||
this.showEloOnLeaderboard = Config.Bind("Config", "show Elo on leaderboard", true);
|
||||
this.showEloOnLeaderboard.SettingChanged += this.showEloOnLeaderboardChanged;
|
||||
this.showEloOnLeaderboardShortcut = Config.Bind("Hotkeys", "show Elo on leaderboard", new KeyboardShortcut(KeyCode.E, KeyCode.RightShift));
|
||||
this.showEloOnLeaderboardRaw = this.showEloOnLeaderboard.Value;
|
||||
|
||||
this.showSquadServer = Config.Bind("Config", "show squad server", true);
|
||||
this.showSquadServer.SettingChanged += this.showSquadServerChanged;
|
||||
this.showSquadServerShortcut = Config.Bind("Hotkeys", "show squad server", new KeyboardShortcut(KeyCode.S, KeyCode.RightShift));
|
||||
this.showSquadServerRaw = this.showSquadServer.Value;
|
||||
|
||||
this.showTestingServer = Config.Bind("Config", "show testing server", true);
|
||||
this.showTestingServer.SettingChanged += this.showTestingServerChanged;
|
||||
this.showTestingServerShortcut = Config.Bind("Hotkeys", "show testing server", new KeyboardShortcut(KeyCode.T, KeyCode.RightShift));
|
||||
this.showTestingServerRaw = this.showTestingServer.Value;
|
||||
|
||||
this.clearChatShortcut = Config.Bind("Hotkeys", "clear chat", new KeyboardShortcut(KeyCode.Z, KeyCode.RightShift));
|
||||
this.clearDeathLogShortcut = Config.Bind("Hotkeys", "clear messages", new KeyboardShortcut(KeyCode.X, KeyCode.RightShift));
|
||||
|
||||
this.useOldGunSoundConf = Config.Bind("Config", "use old gun sound", true);
|
||||
this.useOldGunSoundConf.SettingChanged += this.useOldGunSoundChanged;
|
||||
|
||||
// Audio
|
||||
|
||||
this.killStreakAudioSource = this.gameObject.AddComponent<AudioSource>();
|
||||
|
||||
if (!Directory.Exists(this.audioPath))
|
||||
{
|
||||
Logger.LogError($"Directory {this.audioPath} does not exist. Aborting!");
|
||||
GameObject.Destroy(this);
|
||||
}
|
||||
|
||||
foreach (string fileName in Directory.GetFiles(this.audioPath))
|
||||
{
|
||||
Logger.LogDebug("Loading AudioClip " + Path.GetFileNameWithoutExtension(fileName));
|
||||
|
||||
this.AudioDict.Add(
|
||||
Path.GetFileNameWithoutExtension(fileName),
|
||||
await Util.fetchAudioClip(Path.Combine(this.audioPath, fileName))
|
||||
);
|
||||
}
|
||||
|
||||
this.oldGunSound = this.oldGunSoundRaw;
|
||||
this.newAKSound = this.AKSoundRaw.ADCOCHNNCHM;
|
||||
this.newSMGSound = this.SMGSoundRaw.ADCOCHNNCHM;
|
||||
|
||||
// Websocket
|
||||
|
||||
server = new WebSocketSharp.Server.WebSocketServer($"ws://127.0.0.1:{this.serverPort}");
|
||||
server.AddWebSocketService<WSJSONService>("/json");
|
||||
server.Start();
|
||||
|
||||
StartCoroutine(UpdateValuesFunction());
|
||||
|
||||
// Final tasks
|
||||
|
||||
this.useOldGunSoundChanged(new object(), new EventArgs());
|
||||
|
||||
Logger.LogDebug("Ready!");
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
// Move UI
|
||||
if (Input.GetKey(KeyCode.LeftControl))
|
||||
{
|
||||
// move GUI
|
||||
if (Input.GetKey(KeyCode.LeftShift))
|
||||
{
|
||||
if (Input.GetKey(KeyCode.UpArrow)) this.GUIOffsetY.Value -= 1;
|
||||
if (Input.GetKey(KeyCode.DownArrow)) this.GUIOffsetY.Value += 1;
|
||||
if (Input.GetKey(KeyCode.LeftArrow)) this.GUIOffsetX.Value -= 1;
|
||||
if (Input.GetKey(KeyCode.RightArrow)) this.GUIOffsetX.Value += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Input.GetKeyDown(KeyCode.UpArrow)) this.GUIOffsetY.Value -= 1;
|
||||
if (Input.GetKeyDown(KeyCode.DownArrow)) this.GUIOffsetY.Value += 1;
|
||||
if (Input.GetKeyDown(KeyCode.LeftArrow)) this.GUIOffsetX.Value -= 1;
|
||||
if (Input.GetKeyDown(KeyCode.RightArrow)) this.GUIOffsetX.Value += 1;
|
||||
}
|
||||
}
|
||||
|
||||
// reset GUI position
|
||||
if (this.resetGUIShortcut.Value.IsDown())
|
||||
{
|
||||
this.GUIOffsetX.Value = (int)this.GUIOffsetX.DefaultValue;
|
||||
this.GUIOffsetY.Value = (int)this.GUIOffsetY.DefaultValue;
|
||||
}
|
||||
|
||||
if (this.showGUIShortcut.Value.IsDown()) this.showGUI.Value = !this.showGUI.Value;
|
||||
if (this.shiftToCrouchShortcut.Value.IsDown()) this.shiftToCrouch.Value = !this.shiftToCrouch.Value;
|
||||
if (this.killStreakSFXShortcut.Value.IsDown()) this.killStreakSFX.Value = !this.killStreakSFX.Value;
|
||||
if (this.showPlayerStatsShortcut.Value.IsDown()) this.showPlayerStats.Value = !this.showPlayerStats.Value;
|
||||
if (this.showWeaponStatsShortcut.Value.IsDown()) this.showWeaponStats.Value = !this.showWeaponStats.Value;
|
||||
if (this.showTeamStatsShortcut.Value.IsDown()) this.showTeamStats.Value = !this.showTeamStats.Value;
|
||||
if (this.showEloOnLeaderboardShortcut.Value.IsDown()) this.showEloOnLeaderboard.Value = !this.showEloOnLeaderboard.Value;
|
||||
if (this.showSquadServerShortcut.Value.IsDown()) this.showSquadServer.Value = !this.showSquadServer.Value;
|
||||
if (this.showTestingServerShortcut.Value.IsDown()) this.showTestingServer.Value = !this.showTestingServer.Value;
|
||||
if (this.clearChatShortcut.Value.IsDown()) this.clearChat();
|
||||
if (this.clearDeathLogShortcut.Value.IsDown()) this.clearMessagesFuncRef.Invoke(this.webguy, new object[] { });
|
||||
|
||||
// config visibility
|
||||
if (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightShift)) this._showConfig = true;
|
||||
if (!Input.GetKey(KeyCode.LeftControl) && !Input.GetKey(KeyCode.RightShift)) this._showConfig = false;
|
||||
|
||||
// only if right buttton is not held
|
||||
if (this.shiftToCrouch.Value && !Input.GetMouseButton(1))
|
||||
{
|
||||
if (Input.GetKeyDown(KeyCode.LeftShift)) OMOJPGNNKFN.NEELEHFDKBP.EGACOOOGDDC = true;
|
||||
if (Input.GetKeyUp(KeyCode.LeftShift)) OMOJPGNNKFN.NEELEHFDKBP.EGACOOOGDDC = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
GUI.skin.box.fontSize = 15;
|
||||
GUI.skin.label.fontSize = 15;
|
||||
GUI.skin.label.wordWrap = false;
|
||||
|
||||
if (this._showConfig)
|
||||
{
|
||||
GUI.Box(
|
||||
new Rect(Screen.width - 370, 60, 360, 370), $@"Configuration
|
||||
|
||||
move GUI: LCtrl+LShift+Arrow
|
||||
move GUI by pixel: LCtrl+Arrow
|
||||
reset GUI position: {this.resetGUIShortcut.Value}
|
||||
clear chat: {this.clearChatShortcut.Value}
|
||||
clear death log: {this.clearDeathLogShortcut.Value}
|
||||
|
||||
GUI X offset: {this.GUIOffsetX.Value}
|
||||
GUI Y offset: {this.GUIOffsetY.Value}
|
||||
Show WBM GUI: {this.showGUI.Value} ({this.showGUIShortcut.Value})
|
||||
Show Elo on leaderboard: {this.showEloOnLeaderboard.Value} ({this.showEloOnLeaderboardShortcut.Value})
|
||||
Show player stats: {this.showPlayerStats.Value} ({this.showPlayerStatsShortcut.Value})
|
||||
Show weapon stats: {this.showWeaponStats.Value} ({this.showWeaponStatsShortcut.Value})
|
||||
Show teammate stats: {this.showTeamStats.Value} ({this.showTeamStatsShortcut.Value})
|
||||
show squad server: {this.showSquadServer.Value} ({this.showSquadServerShortcut.Value})
|
||||
show testing server: {this.showTestingServer.Value} ({this.showTestingServerShortcut.Value})
|
||||
shift to crouch: {this.shiftToCrouch.Value} ({this.shiftToCrouchShortcut.Value})
|
||||
kill streak SFX: {this.killStreakSFX.Value} ({this.killStreakSFXShortcut.Value})"
|
||||
);
|
||||
}
|
||||
|
||||
if (!this.showGUI.Value) return;
|
||||
|
||||
GUI.Box(
|
||||
new Rect(this.GUIOffsetX.Value, this.GUIOffsetY.Value, 220, 60),
|
||||
@"War Brokers Mods
|
||||
Made by [LP] POMP
|
||||
v1.7.1.0"
|
||||
);
|
||||
|
||||
if (this.data.localPlayerIndex >= 0)
|
||||
{
|
||||
if (this.showPlayerStats.Value)
|
||||
{
|
||||
try
|
||||
{
|
||||
string killsEloDeltaSign = this.myPlayerStats.killsEloDelta >= 0 ? "+" : "";
|
||||
string gamesEloDeltaSign = this.myPlayerStats.gamesEloDelta >= 0 ? "+" : "";
|
||||
|
||||
GUI.Box(
|
||||
new Rect(this.GUIOffsetX.Value, this.GUIOffsetY.Value + 65, 220, 180),
|
||||
$@"Player stats
|
||||
|
||||
KDR: {Util.formatKDR(this.myPlayerStats.kills, this.myPlayerStats.deaths)}
|
||||
kills Elo: {this.myPlayerStats.killsElo} {killsEloDeltaSign}{Util.formatDecimal((float)this.myPlayerStats.killsEloDelta / 10)}
|
||||
games Elo: {this.myPlayerStats.gamesElo} {gamesEloDeltaSign}{Util.formatDecimal((float)this.myPlayerStats.gamesEloDelta / 10)}
|
||||
Damage dealt: {this.myPlayerStats.damage}
|
||||
Longest Kill: {this.myPlayerStats.longestKill}m
|
||||
Points: {this.myPlayerStats.points}
|
||||
Headshots: {this.myPlayerStats.headShots}
|
||||
Kill streak: {this.killStreak}"
|
||||
);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.showWeaponStats.Value)
|
||||
{
|
||||
try
|
||||
{
|
||||
GUI.Box(
|
||||
new Rect(this.GUIOffsetX.Value, this.GUIOffsetY.Value + 250, 230, 130),
|
||||
$@"Weapon stats
|
||||
|
||||
fire Timer: {String.Format("{0:0.00}", Util.getGunFireTimer(this.personGun))}s (max: {String.Format("{0:0.00}", Util.getGunFireRate(this.personGun))}s)
|
||||
reload Timer: {Util.getGunReloadTimer(this.personGun)}
|
||||
cooldown Timer: {Util.getGunCooldownTimer(this.personGun)}
|
||||
speed: {Util.getGunFireVelocity(this.personGun)}
|
||||
zoom: {Util.getGunZoom(this.personGun)}"
|
||||
);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError(e);
|
||||
}
|
||||
}
|
||||
|
||||
if (this.showTeamStats.Value)
|
||||
{
|
||||
try
|
||||
{
|
||||
string teamNames = "Nickname\n\n";
|
||||
string teamKDR = "KDR\n\n";
|
||||
string teamPoints = "pts\n\n";
|
||||
string teamDamage = "Damage\n\n";
|
||||
|
||||
int teamTotalKills = 0;
|
||||
int teamTotalDeaths = 0;
|
||||
int teamTotalDamage = 0;
|
||||
|
||||
for (int i = 0; i < this.data.playerStatsArray.Length; i++)
|
||||
{
|
||||
Data.PlayerStatsStruct stat = this.data.playerStatsArray[i];
|
||||
|
||||
// if player is not a bot and if player is in my team
|
||||
if ((stat.killsElo != 0) && (this.teamList[i] == this.myTeam))
|
||||
{
|
||||
teamNames += $"{this.data.nickList[i]}\n";
|
||||
teamKDR += $"{Util.formatKDR(stat.kills, stat.deaths)}\n";
|
||||
teamPoints += $"{stat.points}\n";
|
||||
teamDamage += $"{stat.damage}\n";
|
||||
|
||||
teamTotalKills += stat.kills;
|
||||
teamTotalDeaths += stat.deaths;
|
||||
teamTotalDamage += stat.damage;
|
||||
}
|
||||
}
|
||||
|
||||
int teamStatOffset = (this.data.gameState == Data.GameStateEnum.Results) ? 280 : 0;
|
||||
GUI.Box(new Rect(Screen.width - 320, 445 + teamStatOffset, 300, 270), "Team Stats");
|
||||
GUI.Label(new Rect(Screen.width - 315, 470 + teamStatOffset, 105, 190), teamNames);
|
||||
GUI.Label(new Rect(Screen.width - 200, 470 + teamStatOffset, 40, 190), teamKDR);
|
||||
GUI.Label(new Rect(Screen.width - 150, 470 + teamStatOffset, 40, 190), teamPoints);
|
||||
GUI.Label(new Rect(Screen.width - 100, 470 + teamStatOffset, 70, 190), teamDamage);
|
||||
|
||||
GUI.Label(
|
||||
new Rect(Screen.width - 315, 655 + teamStatOffset, 300, 55),
|
||||
$@"total damage: {teamTotalDamage}
|
||||
total deaths: {teamTotalDeaths}
|
||||
total kills: {teamTotalKills}"
|
||||
);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void onDestroy()
|
||||
{
|
||||
this.server.Stop();
|
||||
}
|
||||
}
|
||||
/// This function is called after the component has been disabled and is ready to be destroyed.
|
||||
/// It is the last event function that's called during the component's lifecycle.
|
||||
private void onDestroy()
|
||||
{
|
||||
this.destroyWSSever();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,360 +0,0 @@
|
|||
using BepInEx.Configuration;
|
||||
|
||||
using HarmonyLib;
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace WBM
|
||||
{
|
||||
public partial class WBM
|
||||
{
|
||||
// important boy
|
||||
private webguy webguy;
|
||||
private Harmony harmony;
|
||||
private IEnumerator UpdateValues;
|
||||
|
||||
// websocket data stuff
|
||||
private WebSocketSharp.Server.WebSocketServer server;
|
||||
private ushort serverPort = 24601;
|
||||
private Data.SerializableData data = new Data.SerializableData();
|
||||
|
||||
// internal or temporary
|
||||
private bool _showConfig;
|
||||
|
||||
// Configurations
|
||||
private ConfigEntry<bool> showGUI;
|
||||
private ConfigEntry<KeyboardShortcut> showGUIShortcut;
|
||||
|
||||
private ConfigEntry<int> GUIOffsetX;
|
||||
private ConfigEntry<int> GUIOffsetY;
|
||||
private ConfigEntry<KeyboardShortcut> resetGUIShortcut;
|
||||
|
||||
private ConfigEntry<bool> shiftToCrouch;
|
||||
private ConfigEntry<KeyboardShortcut> shiftToCrouchShortcut;
|
||||
|
||||
private ConfigEntry<bool> killStreakSFX;
|
||||
private ConfigEntry<KeyboardShortcut> killStreakSFXShortcut;
|
||||
|
||||
private ConfigEntry<bool> showPlayerStats;
|
||||
private ConfigEntry<KeyboardShortcut> showPlayerStatsShortcut;
|
||||
private ConfigEntry<bool> showWeaponStats;
|
||||
private ConfigEntry<KeyboardShortcut> showWeaponStatsShortcut;
|
||||
private ConfigEntry<bool> showTeamStats;
|
||||
private ConfigEntry<KeyboardShortcut> showTeamStatsShortcut;
|
||||
|
||||
private ConfigEntry<bool> showEloOnLeaderboard;
|
||||
private void showEloOnLeaderboardChanged(object sender, EventArgs e)
|
||||
{
|
||||
this.showEloOnLeaderboardRaw = this.showEloOnLeaderboard.Value;
|
||||
}
|
||||
private ConfigEntry<KeyboardShortcut> showEloOnLeaderboardShortcut;
|
||||
|
||||
private ConfigEntry<bool> showSquadServer;
|
||||
private void showSquadServerChanged(object sender, EventArgs e)
|
||||
{
|
||||
this.showSquadServerRaw = this.showSquadServer.Value;
|
||||
}
|
||||
private ConfigEntry<KeyboardShortcut> showSquadServerShortcut;
|
||||
|
||||
private ConfigEntry<bool> showTestingServer;
|
||||
private void showTestingServerChanged(object sender, EventArgs e)
|
||||
{
|
||||
this.showTestingServerRaw = this.showTestingServer.Value;
|
||||
}
|
||||
private ConfigEntry<KeyboardShortcut> showTestingServerShortcut;
|
||||
|
||||
private ConfigEntry<KeyboardShortcut> clearChatShortcut;
|
||||
private ConfigEntry<KeyboardShortcut> clearDeathLogShortcut;
|
||||
|
||||
private ConfigEntry<bool> useOldGunSoundConf;
|
||||
private void useOldGunSoundChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (this.useOldGunSoundConf.Value)
|
||||
{
|
||||
this.AKSoundRaw.ADCOCHNNCHM = this.oldGunSound;
|
||||
this.SMGSoundRaw.ADCOCHNNCHM = this.oldGunSound;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.AKSoundRaw.ADCOCHNNCHM = this.newAKSound;
|
||||
this.SMGSoundRaw.ADCOCHNNCHM = this.newSMGSound;
|
||||
}
|
||||
}
|
||||
|
||||
// Audio
|
||||
private AudioClip oldGunSound;
|
||||
private AudioClip newAKSound;
|
||||
private AudioClip newSMGSound;
|
||||
|
||||
private Dictionary<string, AudioClip> AudioDict = new Dictionary<string, AudioClip>();
|
||||
private string audioPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "assets/audio");
|
||||
private AudioSource killStreakAudioSource;
|
||||
private Dictionary<int, string> killStreakSFXDictionary = new Dictionary<int, string>()
|
||||
{
|
||||
{10, "rampage"},
|
||||
{20, "killing spree"},
|
||||
{30, "unstoppable"},
|
||||
{50, "godlike"},
|
||||
{69, "nice"},
|
||||
};
|
||||
|
||||
// memory stuff
|
||||
private static BindingFlags bindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
|
||||
|
||||
private FieldInfo showEloOnLeaderboardRef;
|
||||
private bool showEloOnLeaderboardRaw
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)this.showEloOnLeaderboardRef.GetValue(this.webguy);
|
||||
}
|
||||
set
|
||||
{
|
||||
this.showEloOnLeaderboardRef.SetValue(this.webguy, value);
|
||||
}
|
||||
}
|
||||
|
||||
private FieldInfo showSquadServerRef;
|
||||
private bool showSquadServerRaw
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)this.showSquadServerRef.GetValue(this.webguy);
|
||||
}
|
||||
set
|
||||
{
|
||||
this.showSquadServerRef.SetValue(this.webguy, value);
|
||||
}
|
||||
}
|
||||
|
||||
private FieldInfo showTestingServerRef;
|
||||
private bool showTestingServerRaw
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)this.showTestingServerRef.GetValue(this.webguy);
|
||||
}
|
||||
set
|
||||
{
|
||||
this.showTestingServerRef.SetValue(this.webguy, value);
|
||||
}
|
||||
}
|
||||
|
||||
private FieldInfo playerStatsArrayRef;
|
||||
private Data.PlayerStatsStruct[] playerStatsArrayRaw
|
||||
{
|
||||
get
|
||||
{
|
||||
PDEMAFHPNBD[] rawPlayerStatsArray = (PDEMAFHPNBD[])this.playerStatsArrayRef.GetValue(this.webguy);
|
||||
Data.PlayerStatsStruct[] result = new Data.PlayerStatsStruct[rawPlayerStatsArray.Length];
|
||||
|
||||
for (int i = 0; i < rawPlayerStatsArray.Length; i++)
|
||||
{
|
||||
PDEMAFHPNBD currentlyParsing = rawPlayerStatsArray[i];
|
||||
|
||||
result[i] = new Data.PlayerStatsStruct
|
||||
{
|
||||
kills = currentlyParsing.CFMGCOGACPA,
|
||||
deaths = currentlyParsing.GABHLIIJHBJ,
|
||||
damage = currentlyParsing.CECNBFABADA,
|
||||
longestKill = currentlyParsing.GDFIBEEKMJA,
|
||||
points = currentlyParsing.HNHFAABONHO,
|
||||
headShots = currentlyParsing.GJLLOFLEHHD,
|
||||
vote = currentlyParsing.JCBAKMONPGC,
|
||||
mapVote = currentlyParsing.BOFANBBCNOH,
|
||||
gamesElo = currentlyParsing.IBHFIBAOKCB,
|
||||
gamesEloDelta = currentlyParsing.JMGOHGIGLPI,
|
||||
killsElo = currentlyParsing.GBIABKEEFOC,
|
||||
killsEloDelta = currentlyParsing.JAAKOCPIGJL,
|
||||
};
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
private Data.PlayerStatsStruct myPlayerStats;
|
||||
private int prevDeaths = 0;
|
||||
private int prevKills = 0;
|
||||
private int killCountBeforeDeath = 0;
|
||||
private int killStreak = 0;
|
||||
|
||||
private FieldInfo currentAreaRef;
|
||||
private int currentAreaRaw
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)this.currentAreaRef.GetValue(this.webguy);
|
||||
}
|
||||
}
|
||||
|
||||
private FieldInfo teamListRef;
|
||||
private Data.TeamEnum[] teamListRaw
|
||||
{
|
||||
get
|
||||
{
|
||||
return (Data.TeamEnum[])this.teamListRef.GetValue(this.webguy);
|
||||
}
|
||||
}
|
||||
private Data.TeamEnum[] teamList;
|
||||
private Data.TeamEnum myTeam;
|
||||
|
||||
private FieldInfo localPlayerIndexRef;
|
||||
private int localPlayerIndexRaw
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)this.localPlayerIndexRef.GetValue(this.webguy);
|
||||
}
|
||||
}
|
||||
|
||||
private FieldInfo personGunRef;
|
||||
private NGNJNHEFLHB personGunRaw
|
||||
{
|
||||
get
|
||||
{
|
||||
return (NGNJNHEFLHB)this.personGunRef.GetValue(this.webguy);
|
||||
}
|
||||
}
|
||||
private NGNJNHEFLHB personGun;
|
||||
|
||||
private FieldInfo nickListRef;
|
||||
private string[] nickListRaw
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string[])this.nickListRef.GetValue(this.webguy);
|
||||
}
|
||||
}
|
||||
|
||||
private FieldInfo gameStateRef;
|
||||
private Data.GameStateEnum gameStateRaw
|
||||
{
|
||||
get
|
||||
{
|
||||
return (Data.GameStateEnum)this.gameStateRef.GetValue(this.webguy);
|
||||
}
|
||||
}
|
||||
|
||||
private FieldInfo chatListRef;
|
||||
private string[] chatListRaw
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string[])this.chatListRef.GetValue(this.webguy);
|
||||
}
|
||||
set
|
||||
{
|
||||
this.chatListRef.SetValue(this.webguy, value);
|
||||
}
|
||||
}
|
||||
|
||||
private FieldInfo oldGunSoundRef;
|
||||
private AudioClip oldGunSoundRaw
|
||||
{
|
||||
get
|
||||
{
|
||||
return ((LPJKBALIFCC)this.oldGunSoundRef.GetValue(this.webguy)).ADCOCHNNCHM;
|
||||
}
|
||||
}
|
||||
|
||||
private FieldInfo AKSoundRef;
|
||||
private LPJKBALIFCC AKSoundRaw
|
||||
{
|
||||
get
|
||||
{
|
||||
return (LPJKBALIFCC)this.AKSoundRef.GetValue(this.webguy);
|
||||
}
|
||||
set
|
||||
{
|
||||
this.AKSoundRef.SetValue(this.webguy, value);
|
||||
}
|
||||
}
|
||||
|
||||
private FieldInfo SMGSoundRef;
|
||||
private LPJKBALIFCC SMGSoundRaw
|
||||
{
|
||||
get
|
||||
{
|
||||
return (LPJKBALIFCC)this.SMGSoundRef.GetValue(this.webguy);
|
||||
}
|
||||
set
|
||||
{
|
||||
this.SMGSoundRef.SetValue(this.webguy, value);
|
||||
}
|
||||
}
|
||||
|
||||
// Methods
|
||||
private MethodInfo addMessageFuncRef;
|
||||
private MethodInfo clearMessagesFuncRef;
|
||||
private MethodInfo drawChatMessageFuncRef;
|
||||
|
||||
private IEnumerator UpdateValuesFunction()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.data.localPlayerIndex = this.localPlayerIndexRaw;
|
||||
|
||||
if (this.data.localPlayerIndex >= 0)
|
||||
{
|
||||
this.data.playerStatsArray = this.playerStatsArrayRaw;
|
||||
this.myPlayerStats = this.data.playerStatsArray[this.data.localPlayerIndex];
|
||||
this.teamList = this.teamListRaw;
|
||||
this.myTeam = this.teamList[this.data.localPlayerIndex];
|
||||
this.personGun = this.personGunRaw;
|
||||
this.data.nickList = this.nickListRaw;
|
||||
this.data.gameState = this.gameStateRaw;
|
||||
|
||||
// check if deaths has changed since the last value update
|
||||
if (this.prevDeaths == this.myPlayerStats.deaths)
|
||||
{
|
||||
this.killStreak = this.myPlayerStats.kills - this.killCountBeforeDeath;
|
||||
|
||||
if (this.prevKills != this.myPlayerStats.kills)
|
||||
{
|
||||
if (this.killStreakSFX.Value && this.killStreakSFXDictionary.ContainsKey(this.killStreak))
|
||||
{
|
||||
this.killStreakAudioSource.clip = this.AudioDict[this.killStreakSFXDictionary[this.killStreak]];
|
||||
this.killStreakAudioSource.Play();
|
||||
|
||||
this.addMessageFuncRef.Invoke(this.webguy, new object[] { $"You are on a {this.killStreak} kill streak", -1 });
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// reset kill streak when death count changes
|
||||
|
||||
this.killCountBeforeDeath = this.myPlayerStats.kills;
|
||||
this.prevDeaths = this.myPlayerStats.deaths;
|
||||
this.killStreak = 0;
|
||||
}
|
||||
this.prevKills = this.myPlayerStats.kills;
|
||||
}
|
||||
|
||||
this.server.WebSocketServices["/json"].Sessions.Broadcast(Util.data2JSON(data));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError(e);
|
||||
}
|
||||
|
||||
yield return new WaitForSeconds(0.1f);
|
||||
|
||||
this.UpdateValues = UpdateValuesFunction();
|
||||
StartCoroutine(this.UpdateValues);
|
||||
}
|
||||
|
||||
private void clearChat()
|
||||
{
|
||||
Logger.LogDebug($"clear1 {chatListRaw.Length}");
|
||||
for (int i = 0; i < this.chatListRaw.Length; i++) this.chatListRaw[i] = string.Empty;
|
||||
this.drawChatMessageFuncRef.Invoke(this.webguy, new object[] { "" });
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
namespace WBM
|
||||
{
|
||||
public class WSJSONService : WebSocketSharp.Server.WebSocketBehavior
|
||||
{
|
||||
}
|
||||
}
|
0
WBM/features/BRStats.cs
Normal file
0
WBM/features/BRStats.cs
Normal file
26
WBM/features/WSServer.cs
Normal file
26
WBM/features/WSServer.cs
Normal file
|
@ -0,0 +1,26 @@
|
|||
namespace WBM
|
||||
{
|
||||
public partial class WBM
|
||||
{
|
||||
private WebSocketSharp.Server.WebSocketServer server;
|
||||
private ushort serverPort = 24601;
|
||||
private Data.SerializableData data = new Data.SerializableData();
|
||||
|
||||
private void setupWSSever()
|
||||
{
|
||||
this.server = new WebSocketSharp.Server.WebSocketServer($"ws://127.0.0.1:{this.serverPort}");
|
||||
this.server.AddWebSocketService<WSService>("/json");
|
||||
this.server.Start();
|
||||
}
|
||||
|
||||
private void destroyWSSever()
|
||||
{
|
||||
// properly stop websocket server
|
||||
this.server.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
public class WSService : WebSocketSharp.Server.WebSocketBehavior
|
||||
{
|
||||
}
|
||||
}
|
32
WBM/features/clearChat.cs
Normal file
32
WBM/features/clearChat.cs
Normal file
|
@ -0,0 +1,32 @@
|
|||
using BepInEx.Configuration;
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
using System.Reflection;
|
||||
|
||||
namespace WBM
|
||||
{
|
||||
partial class WBM
|
||||
{
|
||||
private MethodInfo drawChatMessageFuncRef;
|
||||
|
||||
private ConfigEntry<KeyboardShortcut> clearChatShortcut;
|
||||
|
||||
private void setupClearChat()
|
||||
{
|
||||
this.drawChatMessageFuncRef = webguyType.GetMethod(MangledNames.drawChatMessage, bindFlags);
|
||||
this.clearChatShortcut = Config.Bind("Hotkeys", "clear chat", new KeyboardShortcut(KeyCode.Z, KeyCode.RightShift));
|
||||
}
|
||||
|
||||
private void doClearChat()
|
||||
{
|
||||
if (this.clearChatShortcut.Value.IsDown()) this.clearChat();
|
||||
}
|
||||
|
||||
private void clearChat()
|
||||
{
|
||||
for (int i = 0; i < this.chatListRaw.Length; i++) this.chatListRaw[i] = string.Empty;
|
||||
this.drawChatMessageFuncRef.Invoke(this.webguy, new object[] { "" });
|
||||
}
|
||||
}
|
||||
}
|
23
WBM/features/clearMessage.cs
Normal file
23
WBM/features/clearMessage.cs
Normal file
|
@ -0,0 +1,23 @@
|
|||
using BepInEx.Configuration;
|
||||
|
||||
using System.Reflection;
|
||||
|
||||
namespace WBM
|
||||
{
|
||||
partial class WBM
|
||||
{
|
||||
private ConfigEntry<KeyboardShortcut> clearDeathLogShortcut;
|
||||
|
||||
private MethodInfo clearMessagesFuncRef;
|
||||
|
||||
private void setupClearMessage()
|
||||
{
|
||||
this.clearMessagesFuncRef = webguyType.GetMethod(MangledNames.clearMessages, bindFlags);
|
||||
}
|
||||
|
||||
private void doclearMessage()
|
||||
{
|
||||
if (this.clearDeathLogShortcut.Value.IsDown()) this.clearMessagesFuncRef.Invoke(this.webguy, new object[] { });
|
||||
}
|
||||
}
|
||||
}
|
281
WBM/features/core/core.cs
Normal file
281
WBM/features/core/core.cs
Normal file
|
@ -0,0 +1,281 @@
|
|||
using BepInEx.Configuration;
|
||||
|
||||
using HarmonyLib;
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using CPersonGun = JABKDMKNMKE;
|
||||
using SPlayerStats = INPDBACNIGK;
|
||||
|
||||
namespace WBM
|
||||
{
|
||||
partial class WBM
|
||||
{
|
||||
private webguy webguy;
|
||||
private System.Type webguyType;
|
||||
private Harmony harmony;
|
||||
private IEnumerator UpdateValues;
|
||||
|
||||
//
|
||||
// internal or temporary
|
||||
//
|
||||
|
||||
private bool _showConfig;
|
||||
|
||||
//
|
||||
// memory stuff
|
||||
//
|
||||
|
||||
private static BindingFlags bindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
|
||||
|
||||
//
|
||||
// Methods
|
||||
//
|
||||
|
||||
private MethodInfo addMessageFuncRef;
|
||||
|
||||
private IEnumerator UpdateValuesFunction()
|
||||
{
|
||||
try
|
||||
{
|
||||
this.data.localPlayerIndex = this.localPlayerIndexRaw;
|
||||
|
||||
if (this.data.localPlayerIndex >= 0)
|
||||
{
|
||||
this.data.playerStatsArray = this.playerStatsArrayRaw;
|
||||
this.myPlayerStats = this.data.playerStatsArray[this.data.localPlayerIndex];
|
||||
this.teamList = this.teamListRaw;
|
||||
this.myTeam = this.teamList[this.data.localPlayerIndex];
|
||||
this.personGun = this.personGunRaw;
|
||||
this.data.nickList = this.nickListRaw;
|
||||
this.data.gameState = this.gameStateRaw;
|
||||
|
||||
// check if deaths has changed since the last value update
|
||||
if (this.prevDeaths == this.myPlayerStats.deaths)
|
||||
{
|
||||
this.killStreak = this.myPlayerStats.kills - this.killCountBeforeDeath;
|
||||
|
||||
if (this.prevKills != this.myPlayerStats.kills)
|
||||
{
|
||||
if (this.killStreakSFX.Value && this.killStreakSFXDictionary.ContainsKey(this.killStreak))
|
||||
{
|
||||
this.killStreakAudioSource.clip = this.AudioDict[this.killStreakSFXDictionary[this.killStreak]];
|
||||
this.killStreakAudioSource.Play();
|
||||
|
||||
this.addMessageFuncRef.Invoke(this.webguy, new object[] { $"You are on a {this.killStreak} kill streak", -1 });
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// reset kill streak when death count changes
|
||||
|
||||
this.killCountBeforeDeath = this.myPlayerStats.kills;
|
||||
this.prevDeaths = this.myPlayerStats.deaths;
|
||||
this.killStreak = 0;
|
||||
}
|
||||
this.prevKills = this.myPlayerStats.kills;
|
||||
}
|
||||
|
||||
this.server.WebSocketServices["/json"].Sessions.Broadcast(Util.data2JSON(data));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError(e);
|
||||
}
|
||||
|
||||
yield return new WaitForSeconds(0.1f);
|
||||
|
||||
this.UpdateValues = UpdateValuesFunction();
|
||||
StartCoroutine(this.UpdateValues);
|
||||
}
|
||||
|
||||
private FieldInfo playerStatsArrayRef;
|
||||
private Data.PlayerStatsStruct[] playerStatsArrayRaw
|
||||
{
|
||||
get
|
||||
{
|
||||
SPlayerStats[] rawPlayerStatsArray = (SPlayerStats[])this.playerStatsArrayRef.GetValue(this.webguy);
|
||||
Data.PlayerStatsStruct[] result = new Data.PlayerStatsStruct[rawPlayerStatsArray.Length];
|
||||
|
||||
for (int i = 0; i < rawPlayerStatsArray.Length; i++)
|
||||
{
|
||||
SPlayerStats currentlyParsing = rawPlayerStatsArray[i];
|
||||
|
||||
result[i] = new Data.PlayerStatsStruct
|
||||
{
|
||||
kills = currentlyParsing.JJEIOHLJMHO,
|
||||
deaths = currentlyParsing.CADBJPEGEAL,
|
||||
damage = currentlyParsing.MBNBFDFDBAN,
|
||||
longestKill = currentlyParsing.FNOCIFHHINH,
|
||||
points = currentlyParsing.AIDBBHHNCAK,
|
||||
headShots = currentlyParsing.FJPBIMILEPN,
|
||||
vote = currentlyParsing.ILNFHPIOPCI,
|
||||
mapVote = currentlyParsing.DPMNDAMAHML,
|
||||
gamesElo = currentlyParsing.OPMKKKJPDON,
|
||||
gamesEloDelta = currentlyParsing.BIFCAPOBMIO,
|
||||
killsElo = currentlyParsing.ICIBGMLJNHJ,
|
||||
killsEloDelta = currentlyParsing.ONICDMLDBFL,
|
||||
};
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
private Data.PlayerStatsStruct myPlayerStats;
|
||||
private int prevDeaths = 0;
|
||||
private int prevKills = 0;
|
||||
private int killCountBeforeDeath = 0;
|
||||
|
||||
private FieldInfo teamListRef;
|
||||
private Data.TeamEnum[] teamListRaw
|
||||
{
|
||||
get
|
||||
{
|
||||
return (Data.TeamEnum[])this.teamListRef.GetValue(this.webguy);
|
||||
}
|
||||
}
|
||||
private Data.TeamEnum[] teamList;
|
||||
private Data.TeamEnum myTeam;
|
||||
|
||||
private FieldInfo localPlayerIndexRef;
|
||||
private int localPlayerIndexRaw
|
||||
{
|
||||
get
|
||||
{
|
||||
return (int)this.localPlayerIndexRef.GetValue(this.webguy);
|
||||
}
|
||||
}
|
||||
|
||||
private FieldInfo personGunRef;
|
||||
private CPersonGun personGunRaw
|
||||
{
|
||||
get
|
||||
{
|
||||
return (CPersonGun)this.personGunRef.GetValue(this.webguy);
|
||||
}
|
||||
}
|
||||
private CPersonGun personGun;
|
||||
|
||||
private FieldInfo nickListRef;
|
||||
private string[] nickListRaw
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string[])this.nickListRef.GetValue(this.webguy);
|
||||
}
|
||||
}
|
||||
|
||||
private FieldInfo gameStateRef;
|
||||
private Data.GameStateEnum gameStateRaw
|
||||
{
|
||||
get
|
||||
{
|
||||
return (Data.GameStateEnum)this.gameStateRef.GetValue(this.webguy);
|
||||
}
|
||||
}
|
||||
|
||||
private FieldInfo chatListRef;
|
||||
private string[] chatListRaw
|
||||
{
|
||||
get
|
||||
{
|
||||
return (string[])this.chatListRef.GetValue(this.webguy);
|
||||
}
|
||||
set
|
||||
{
|
||||
this.chatListRef.SetValue(this.webguy, value);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Audio
|
||||
//
|
||||
|
||||
private Dictionary<string, AudioClip> AudioDict = new Dictionary<string, AudioClip>();
|
||||
private string audioPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "assets/audio");
|
||||
|
||||
private void initCore()
|
||||
{
|
||||
this.harmony = new Harmony(WBM.programID);
|
||||
this.harmony.PatchAll();
|
||||
}
|
||||
|
||||
private async System.Threading.Tasks.Task setupCore()
|
||||
{
|
||||
this.webguy = FindObjectOfType<webguy>();
|
||||
this.webguyType = typeof(webguy);
|
||||
|
||||
//
|
||||
// References
|
||||
//
|
||||
|
||||
this.playerStatsArrayRef = webguyType.GetField(MangledNames.statsList, bindFlags);
|
||||
this.teamListRef = webguyType.GetField(MangledNames.teamList, bindFlags);
|
||||
this.localPlayerIndexRef = webguyType.GetField(MangledNames.localPlayerIndex, bindFlags);
|
||||
this.personGunRef = webguyType.GetField(MangledNames.personGun, bindFlags);
|
||||
this.nickListRef = webguyType.GetField(MangledNames.nickList, bindFlags);
|
||||
this.gameStateRef = webguyType.GetField(MangledNames.gameState, bindFlags);
|
||||
this.chatListRef = webguyType.GetField(MangledNames.chatList, bindFlags);
|
||||
|
||||
this.addMessageFuncRef = webguyType.GetMethod(MangledNames.addMessage, bindFlags);
|
||||
|
||||
//
|
||||
// Configurations
|
||||
//
|
||||
|
||||
this.showGUI = Config.Bind("Config", "show GUI", true);
|
||||
this.showGUIShortcut = Config.Bind("Hotkeys", "show GUI Shortcut", new KeyboardShortcut(KeyCode.A, KeyCode.RightShift));
|
||||
|
||||
this.GUIOffsetX = Config.Bind("Config", "GUI Horizontal position", 38, new ConfigDescription("WBM GUI Horizontal position", new AcceptableValueRange<int>(0, Screen.width)));
|
||||
this.GUIOffsetY = Config.Bind("Config", "GUI Vertical position", 325, new ConfigDescription("WBM GUI Vertical position", new AcceptableValueRange<int>(0, Screen.height)));
|
||||
this.resetGUIShortcut = Config.Bind("Hotkeys", "reset GUI position", new KeyboardShortcut(KeyCode.R, KeyCode.LeftControl));
|
||||
|
||||
this.showPlayerStats = Config.Bind("Config", "show player statistics", true);
|
||||
this.showPlayerStatsShortcut = Config.Bind("Hotkeys", "show player statistics", new KeyboardShortcut(KeyCode.P, KeyCode.RightShift));
|
||||
|
||||
this.showWeaponStats = Config.Bind("Config", "show weapon statistics", true);
|
||||
this.showWeaponStatsShortcut = Config.Bind("Hotkeys", "show weapon statistics", new KeyboardShortcut(KeyCode.W, KeyCode.RightShift));
|
||||
|
||||
this.showTeamStats = Config.Bind("Config", "show team statistics", true);
|
||||
this.showTeamStatsShortcut = Config.Bind("Hotkeys", "show team statistics", new KeyboardShortcut(KeyCode.L, KeyCode.RightShift));
|
||||
|
||||
this.clearDeathLogShortcut = Config.Bind("Hotkeys", "clear messages", new KeyboardShortcut(KeyCode.X, KeyCode.RightShift));
|
||||
|
||||
//
|
||||
// Audio
|
||||
//
|
||||
|
||||
this.killStreakAudioSource = this.gameObject.AddComponent<AudioSource>();
|
||||
|
||||
if (!Directory.Exists(this.audioPath))
|
||||
{
|
||||
Logger.LogError($"Directory {this.audioPath} does not exist. Aborting!");
|
||||
GameObject.Destroy(this);
|
||||
}
|
||||
|
||||
foreach (string fileName in Directory.GetFiles(this.audioPath))
|
||||
{
|
||||
Logger.LogDebug("Loading AudioClip " + Path.GetFileNameWithoutExtension(fileName));
|
||||
|
||||
this.AudioDict.Add(
|
||||
Path.GetFileNameWithoutExtension(fileName),
|
||||
await Util.fetchAudioClip(Path.Combine(this.audioPath, fileName))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void doCore()
|
||||
{
|
||||
this.moveUIOnKeyPress();
|
||||
this.resetUIOnKeyPress();
|
||||
this.toggleUIOnKeyPress();
|
||||
this.showConfigOnKeyPress();
|
||||
}
|
||||
}
|
||||
}
|
106
WBM/features/core/ui.cs
Normal file
106
WBM/features/core/ui.cs
Normal file
|
@ -0,0 +1,106 @@
|
|||
using BepInEx.Configuration;
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace WBM
|
||||
{
|
||||
partial class WBM
|
||||
{
|
||||
private ConfigEntry<bool> showGUI;
|
||||
private ConfigEntry<KeyboardShortcut> showGUIShortcut;
|
||||
|
||||
private ConfigEntry<int> GUIOffsetX;
|
||||
private ConfigEntry<int> GUIOffsetY;
|
||||
private ConfigEntry<KeyboardShortcut> resetGUIShortcut;
|
||||
|
||||
private void drawCoreUI()
|
||||
{
|
||||
GUI.skin.box.fontSize = 15;
|
||||
GUI.skin.label.fontSize = 15;
|
||||
GUI.skin.label.wordWrap = false;
|
||||
|
||||
if (this._showConfig) this.showConfig();
|
||||
|
||||
if (!this.showGUI.Value) return;
|
||||
|
||||
this.showWBMVersion();
|
||||
}
|
||||
|
||||
private void showConfig()
|
||||
{
|
||||
GUI.Box(
|
||||
new Rect(Screen.width - 370, 60, 360, 370), $@"Configuration
|
||||
|
||||
move GUI: LCtrl+LShift+Arrow
|
||||
move GUI by pixel: LCtrl+Arrow
|
||||
reset GUI position: {this.resetGUIShortcut.Value}
|
||||
clear chat: {this.clearChatShortcut.Value}
|
||||
clear death log: {this.clearDeathLogShortcut.Value}
|
||||
|
||||
GUI X offset: {this.GUIOffsetX.Value}
|
||||
GUI Y offset: {this.GUIOffsetY.Value}
|
||||
Show WBM GUI: {this.showGUI.Value} ({this.showGUIShortcut.Value})
|
||||
Show Elo on leaderboard: {this.showEloOnLeaderboard.Value} ({this.showEloOnLeaderboardShortcut.Value})
|
||||
Show player stats: {this.showPlayerStats.Value} ({this.showPlayerStatsShortcut.Value})
|
||||
Show weapon stats: {this.showWeaponStats.Value} ({this.showWeaponStatsShortcut.Value})
|
||||
Show teammate stats: {this.showTeamStats.Value} ({this.showTeamStatsShortcut.Value})
|
||||
show squad server: {this.showSquadServer.Value} ({this.showSquadServerShortcut.Value})
|
||||
show testing server: {this.showTestingServer.Value} ({this.showTestingServerShortcut.Value})
|
||||
shift to crouch: {this.shiftToCrouch.Value} ({this.shiftToCrouchShortcut.Value})
|
||||
kill streak SFX: {this.killStreakSFX.Value} ({this.killStreakSFXShortcut.Value})"
|
||||
);
|
||||
}
|
||||
|
||||
private void showWBMVersion()
|
||||
{
|
||||
GUI.Box(
|
||||
new Rect(this.GUIOffsetX.Value, this.GUIOffsetY.Value, 220, 60),
|
||||
$@"{WBM.programName}
|
||||
Made by [LP] POMP
|
||||
v{WBM.programVersion}"
|
||||
);
|
||||
}
|
||||
|
||||
private void moveUIOnKeyPress()
|
||||
{
|
||||
if (Input.GetKey(KeyCode.LeftControl))
|
||||
{
|
||||
// move GUI
|
||||
if (Input.GetKey(KeyCode.LeftShift))
|
||||
{
|
||||
if (Input.GetKey(KeyCode.UpArrow)) this.GUIOffsetY.Value -= 1;
|
||||
if (Input.GetKey(KeyCode.DownArrow)) this.GUIOffsetY.Value += 1;
|
||||
if (Input.GetKey(KeyCode.LeftArrow)) this.GUIOffsetX.Value -= 1;
|
||||
if (Input.GetKey(KeyCode.RightArrow)) this.GUIOffsetX.Value += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Input.GetKeyDown(KeyCode.UpArrow)) this.GUIOffsetY.Value -= 1;
|
||||
if (Input.GetKeyDown(KeyCode.DownArrow)) this.GUIOffsetY.Value += 1;
|
||||
if (Input.GetKeyDown(KeyCode.LeftArrow)) this.GUIOffsetX.Value -= 1;
|
||||
if (Input.GetKeyDown(KeyCode.RightArrow)) this.GUIOffsetX.Value += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void resetUIOnKeyPress()
|
||||
{
|
||||
if (this.resetGUIShortcut.Value.IsDown())
|
||||
{
|
||||
this.GUIOffsetX.Value = (int)this.GUIOffsetX.DefaultValue;
|
||||
this.GUIOffsetY.Value = (int)this.GUIOffsetY.DefaultValue;
|
||||
}
|
||||
}
|
||||
|
||||
private void toggleUIOnKeyPress()
|
||||
{
|
||||
if (this.showGUIShortcut.Value.IsDown()) this.showGUI.Value = !this.showGUI.Value;
|
||||
}
|
||||
|
||||
private void showConfigOnKeyPress()
|
||||
{
|
||||
if (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightShift)) this._showConfig = true;
|
||||
if (!Input.GetKey(KeyCode.LeftControl) && !Input.GetKey(KeyCode.RightShift)) this._showConfig = false;
|
||||
}
|
||||
}
|
||||
}
|
41
WBM/features/fpsUnlock.cs
Normal file
41
WBM/features/fpsUnlock.cs
Normal file
|
@ -0,0 +1,41 @@
|
|||
using HarmonyLib;
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace WBM
|
||||
{
|
||||
/// patch for onFPSChanged function
|
||||
[HarmonyPatch(typeof(webguy))]
|
||||
[HarmonyPatch(MangledNames.onFPSChanged)]
|
||||
class FPSSliderPatch
|
||||
{
|
||||
private static int defaultTargetFrameRate = -1;
|
||||
private static int maxTargetFrameRate = 1000;
|
||||
|
||||
private static GameObject fpsSliderTextObj = GameObject.Find("fpsSlideFuckText");
|
||||
private static Slider slider = GameObject.Find("fpsSlider").GetComponent<Slider>();
|
||||
private static AccessTools.FieldRef<webguy, float> fpsValueRef = AccessTools.FieldRefAccess<webguy, float>(MangledNames.fpsValue);
|
||||
|
||||
static bool Prefix(webguy __instance, float CNFIJGNCMNE)
|
||||
{
|
||||
fpsValueRef(__instance) = CNFIJGNCMNE;
|
||||
int targetFrameRate = (int)(CNFIJGNCMNE * maxTargetFrameRate);
|
||||
|
||||
if (targetFrameRate == 0)
|
||||
{
|
||||
((InfernalBehaviour)__instance).CEHBKMNGHPG(fpsSliderTextObj, __instance.ILCOAONDEKP("Disabled"));
|
||||
targetFrameRate = defaultTargetFrameRate;
|
||||
}
|
||||
else
|
||||
{
|
||||
((InfernalBehaviour)__instance).CEHBKMNGHPG(fpsSliderTextObj, targetFrameRate.ToString());
|
||||
}
|
||||
|
||||
if (targetFrameRate > 0 && targetFrameRate < 5) targetFrameRate = 5;
|
||||
|
||||
Application.targetFrameRate = targetFrameRate;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
42
WBM/features/killStreakSFX.cs
Normal file
42
WBM/features/killStreakSFX.cs
Normal file
|
@ -0,0 +1,42 @@
|
|||
using BepInEx.Configuration;
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace WBM
|
||||
{
|
||||
partial class WBM
|
||||
{
|
||||
private ConfigEntry<bool> killStreakSFX;
|
||||
private ConfigEntry<KeyboardShortcut> killStreakSFXShortcut;
|
||||
|
||||
private int killStreak = 0;
|
||||
|
||||
private AudioSource killStreakAudioSource;
|
||||
private Dictionary<int, string> killStreakSFXDictionary = new Dictionary<int, string>()
|
||||
{
|
||||
{10, "rampage"},
|
||||
{20, "killing spree"},
|
||||
{30, "unstoppable"},
|
||||
{50, "godlike"},
|
||||
{69, "nice"},
|
||||
};
|
||||
|
||||
private void setupKillStreakSFX()
|
||||
{
|
||||
this.killStreakSFX = Config.Bind("Config", "kill streak sound effect", true);
|
||||
this.killStreakSFXShortcut = Config.Bind("Hotkeys", "kill streak sound effect", new KeyboardShortcut(KeyCode.F, KeyCode.RightShift));
|
||||
}
|
||||
|
||||
private void doKillStreakSFX()
|
||||
{
|
||||
this.toggleKillStreakSFXOnKeyPress();
|
||||
}
|
||||
|
||||
private void toggleKillStreakSFXOnKeyPress()
|
||||
{
|
||||
if (this.killStreakSFXShortcut.Value.IsDown()) this.killStreakSFX.Value = !this.killStreakSFX.Value;
|
||||
}
|
||||
}
|
||||
}
|
71
WBM/features/oldGunSound.cs
Normal file
71
WBM/features/oldGunSound.cs
Normal file
|
@ -0,0 +1,71 @@
|
|||
using BepInEx.Configuration;
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
using CAudioClip = KGEACBNNOIM;
|
||||
|
||||
namespace WBM
|
||||
{
|
||||
public partial class WBM
|
||||
{
|
||||
private ConfigEntry<bool> useOldGunSoundConf;
|
||||
|
||||
private CAudioClip oldGunSound;
|
||||
|
||||
private FieldInfo AKSoundRef;
|
||||
private CAudioClip AKSoundRaw
|
||||
{
|
||||
set
|
||||
{
|
||||
this.AKSoundRef.SetValue(this.webguy, value);
|
||||
}
|
||||
}
|
||||
private CAudioClip newAKSound;
|
||||
|
||||
private FieldInfo SMGSoundRef;
|
||||
private CAudioClip SMGSoundRaw
|
||||
{
|
||||
set
|
||||
{
|
||||
this.SMGSoundRef.SetValue(this.webguy, value);
|
||||
}
|
||||
}
|
||||
private CAudioClip newSMGSound;
|
||||
|
||||
private void setupOldGunSound()
|
||||
{
|
||||
this.useOldGunSoundConf = Config.Bind("Config", "use old gun sound", true);
|
||||
this.useOldGunSoundConf.SettingChanged += this.onOldGunSoundChange;
|
||||
|
||||
this.AKSoundRef = webguyType.GetField(MangledNames.AKRifleShotClip, bindFlags);
|
||||
this.SMGSoundRef = webguyType.GetField(MangledNames.SMGShotClip, bindFlags);
|
||||
|
||||
|
||||
this.oldGunSound = new CAudioClip("Sound/gun_shot", 1f, 0f);
|
||||
this.oldGunSound.DMMKODLJJGP(50f, 1_000f);
|
||||
|
||||
this.newAKSound = new CAudioClip("Sound/AK47_Krinkov_Close_Single", 1f, 0f);
|
||||
this.newAKSound.DMMKODLJJGP(50f, 1_000f);
|
||||
|
||||
this.newSMGSound = new CAudioClip("Sound/smg_gun_shot", 1f, 0f);
|
||||
this.newSMGSound.DMMKODLJJGP(50f, 1_000f);
|
||||
|
||||
this.onOldGunSoundChange(new object(), new EventArgs());
|
||||
}
|
||||
|
||||
private void onOldGunSoundChange(object sender, EventArgs e)
|
||||
{
|
||||
if (this.useOldGunSoundConf.Value)
|
||||
{
|
||||
this.AKSoundRaw = this.oldGunSound;
|
||||
this.SMGSoundRaw = this.oldGunSound;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.AKSoundRaw = this.newAKSound;
|
||||
this.SMGSoundRaw = this.newSMGSound;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
53
WBM/features/playerStats.cs
Normal file
53
WBM/features/playerStats.cs
Normal file
|
@ -0,0 +1,53 @@
|
|||
using BepInEx.Configuration;
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
using System;
|
||||
|
||||
namespace WBM
|
||||
{
|
||||
partial class WBM
|
||||
{
|
||||
private ConfigEntry<bool> showPlayerStats;
|
||||
private ConfigEntry<KeyboardShortcut> showPlayerStatsShortcut;
|
||||
|
||||
private void togglePlayerStatsOnKeyPress()
|
||||
{
|
||||
if (this.showPlayerStatsShortcut.Value.IsDown()) this.showPlayerStats.Value = !this.showPlayerStats.Value;
|
||||
}
|
||||
|
||||
private void doPlayerStats()
|
||||
{
|
||||
this.togglePlayerStatsOnKeyPress();
|
||||
}
|
||||
|
||||
private void drawPlayerStats()
|
||||
{
|
||||
if (!this.showPlayerStats.Value) return;
|
||||
|
||||
try
|
||||
{
|
||||
string killsEloDeltaSign = this.myPlayerStats.killsEloDelta >= 0 ? "+" : "";
|
||||
string gamesEloDeltaSign = this.myPlayerStats.gamesEloDelta >= 0 ? "+" : "";
|
||||
|
||||
GUI.Box(
|
||||
new Rect(this.GUIOffsetX.Value, this.GUIOffsetY.Value + 65, 220, 180),
|
||||
$@"Player stats
|
||||
|
||||
KDR: {Util.formatKDR(this.myPlayerStats.kills, this.myPlayerStats.deaths)}
|
||||
kills Elo: {this.myPlayerStats.killsElo} {killsEloDeltaSign}{Util.formatDecimal((float)this.myPlayerStats.killsEloDelta / 10)}
|
||||
games Elo: {this.myPlayerStats.gamesElo} {gamesEloDeltaSign}{Util.formatDecimal((float)this.myPlayerStats.gamesEloDelta / 10)}
|
||||
Damage dealt: {this.myPlayerStats.damage}
|
||||
Longest Kill: {this.myPlayerStats.longestKill}m
|
||||
Points: {this.myPlayerStats.points}
|
||||
Headshots: {this.myPlayerStats.headShots}
|
||||
Kill streak: {this.killStreak}"
|
||||
);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
47
WBM/features/shiftToCrouch.cs
Normal file
47
WBM/features/shiftToCrouch.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
using BepInEx.Configuration;
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace WBM
|
||||
{
|
||||
partial class WBM
|
||||
{
|
||||
private ConfigEntry<bool> shiftToCrouch;
|
||||
private ConfigEntry<KeyboardShortcut> shiftToCrouchShortcut;
|
||||
|
||||
private void setupShiftToCrouch()
|
||||
{
|
||||
this.shiftToCrouch = Config.Bind("Config", "shift to crouch", true);
|
||||
this.shiftToCrouchShortcut = Config.Bind("Hotkeys", "shift to crouch", new KeyboardShortcut(KeyCode.C, KeyCode.RightShift));
|
||||
}
|
||||
|
||||
private void doShiftToCrouch()
|
||||
{
|
||||
this.crouchOnKeyPress();
|
||||
this.toggleShiftToCrouchOnKeyPress();
|
||||
}
|
||||
|
||||
private void crouchOnKeyPress()
|
||||
{
|
||||
// Skip if this setting is not activated
|
||||
if (!this.shiftToCrouch.Value) return;
|
||||
|
||||
// Skip if right buttton is being pressed (if weapon is zoomed)
|
||||
if (Input.GetMouseButton(1)) return;
|
||||
|
||||
if (Input.GetKeyDown(KeyCode.LeftShift)) setCrouchState(true);
|
||||
if (Input.GetKeyUp(KeyCode.LeftShift)) setCrouchState(false);
|
||||
}
|
||||
|
||||
private void toggleShiftToCrouchOnKeyPress()
|
||||
{
|
||||
if (this.shiftToCrouchShortcut.Value.IsDown()) this.shiftToCrouch.Value = !this.shiftToCrouch.Value;
|
||||
}
|
||||
|
||||
private void setCrouchState(bool crouchState)
|
||||
{
|
||||
// CFPSGuy.inSt.isCrouching
|
||||
HGIJNAOOGIC.AIPINJPLLIN.GDKHEALABDI = crouchState;
|
||||
}
|
||||
}
|
||||
}
|
53
WBM/features/showEloOnLeaderboard.cs
Normal file
53
WBM/features/showEloOnLeaderboard.cs
Normal file
|
@ -0,0 +1,53 @@
|
|||
using BepInEx.Configuration;
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace WBM
|
||||
{
|
||||
partial class WBM
|
||||
{
|
||||
private ConfigEntry<bool> showEloOnLeaderboard;
|
||||
private ConfigEntry<KeyboardShortcut> showEloOnLeaderboardShortcut;
|
||||
|
||||
private FieldInfo showEloOnLeaderboardRef;
|
||||
private bool showEloOnLeaderboardRaw
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)this.showEloOnLeaderboardRef.GetValue(this.webguy);
|
||||
}
|
||||
set
|
||||
{
|
||||
this.showEloOnLeaderboardRef.SetValue(this.webguy, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void setupShowEloOnLeaderBoard()
|
||||
{
|
||||
this.showEloOnLeaderboardRef = webguyType.GetField(MangledNames.showElo, bindFlags);
|
||||
|
||||
this.showEloOnLeaderboard = Config.Bind("Config", "show Elo on leaderboard", true);
|
||||
this.showEloOnLeaderboard.SettingChanged += this.onShowEloOnLeaderboardChange;
|
||||
this.showEloOnLeaderboardShortcut = Config.Bind("Hotkeys", "show Elo on leaderboard", new KeyboardShortcut(KeyCode.E, KeyCode.RightShift));
|
||||
this.showEloOnLeaderboardRaw = this.showEloOnLeaderboard.Value;
|
||||
}
|
||||
|
||||
private void doLeaderboardElo()
|
||||
{
|
||||
this.toggleLeaderboardEloOnKeyPress();
|
||||
}
|
||||
|
||||
private void toggleLeaderboardEloOnKeyPress()
|
||||
{
|
||||
if (this.showEloOnLeaderboardShortcut.Value.IsDown()) this.showEloOnLeaderboard.Value = !this.showEloOnLeaderboard.Value;
|
||||
}
|
||||
|
||||
private void onShowEloOnLeaderboardChange(object sender, EventArgs e)
|
||||
{
|
||||
this.showEloOnLeaderboardRaw = this.showEloOnLeaderboard.Value;
|
||||
}
|
||||
}
|
||||
}
|
53
WBM/features/showSquadServer.cs
Normal file
53
WBM/features/showSquadServer.cs
Normal file
|
@ -0,0 +1,53 @@
|
|||
using BepInEx.Configuration;
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace WBM
|
||||
{
|
||||
partial class WBM
|
||||
{
|
||||
private ConfigEntry<bool> showSquadServer;
|
||||
private ConfigEntry<KeyboardShortcut> showSquadServerShortcut;
|
||||
|
||||
private FieldInfo showSquadServerRef;
|
||||
private bool showSquadServerRaw
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)this.showSquadServerRef.GetValue(this.webguy);
|
||||
}
|
||||
set
|
||||
{
|
||||
this.showSquadServerRef.SetValue(this.webguy, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void setupShowSquadServer()
|
||||
{
|
||||
this.showSquadServerRef = webguyType.GetField(MangledNames.isClan, bindFlags);
|
||||
|
||||
this.showSquadServer = Config.Bind("Config", "show squad server", true);
|
||||
this.showSquadServer.SettingChanged += this.onShowSquadServerChange;
|
||||
this.showSquadServerShortcut = Config.Bind("Hotkeys", "show squad server", new KeyboardShortcut(KeyCode.S, KeyCode.RightShift));
|
||||
this.showSquadServerRaw = this.showSquadServer.Value;
|
||||
}
|
||||
|
||||
private void doShowSquadServer()
|
||||
{
|
||||
this.toggleShowSquadServerOnKeyPress();
|
||||
}
|
||||
|
||||
private void toggleShowSquadServerOnKeyPress()
|
||||
{
|
||||
if (this.showSquadServerShortcut.Value.IsDown()) this.showSquadServer.Value = !this.showSquadServer.Value;
|
||||
}
|
||||
|
||||
private void onShowSquadServerChange(object sender, EventArgs e)
|
||||
{
|
||||
this.showSquadServerRaw = this.showSquadServer.Value;
|
||||
}
|
||||
}
|
||||
}
|
53
WBM/features/showTestingServer.cs
Normal file
53
WBM/features/showTestingServer.cs
Normal file
|
@ -0,0 +1,53 @@
|
|||
using BepInEx.Configuration;
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace WBM
|
||||
{
|
||||
partial class WBM
|
||||
{
|
||||
private ConfigEntry<bool> showTestingServer;
|
||||
private ConfigEntry<KeyboardShortcut> showTestingServerShortcut;
|
||||
|
||||
private FieldInfo showTestingServerRef;
|
||||
private bool showTestingServerRaw
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)this.showTestingServerRef.GetValue(this.webguy);
|
||||
}
|
||||
set
|
||||
{
|
||||
this.showTestingServerRef.SetValue(this.webguy, value);
|
||||
}
|
||||
}
|
||||
|
||||
private void setupShowTestingServer()
|
||||
{
|
||||
this.showTestingServerRef = webguyType.GetField(MangledNames.isTesting, bindFlags);
|
||||
|
||||
this.showTestingServer = Config.Bind("Config", "show testing server", true);
|
||||
this.showTestingServer.SettingChanged += this.onShowTestingServerChange;
|
||||
this.showTestingServerShortcut = Config.Bind("Hotkeys", "show testing server", new KeyboardShortcut(KeyCode.T, KeyCode.RightShift));
|
||||
this.showTestingServerRaw = this.showTestingServer.Value;
|
||||
}
|
||||
|
||||
private void doTestingServer()
|
||||
{
|
||||
this.toggleTestingServerOnKeyPress();
|
||||
}
|
||||
|
||||
private void toggleTestingServerOnKeyPress()
|
||||
{
|
||||
if (this.showTestingServerShortcut.Value.IsDown()) this.showTestingServer.Value = !this.showTestingServer.Value;
|
||||
}
|
||||
|
||||
private void onShowTestingServerChange(object sender, EventArgs e)
|
||||
{
|
||||
this.showTestingServerRaw = this.showTestingServer.Value;
|
||||
}
|
||||
}
|
||||
}
|
77
WBM/features/teamStats.cs
Normal file
77
WBM/features/teamStats.cs
Normal file
|
@ -0,0 +1,77 @@
|
|||
using BepInEx.Configuration;
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
using System;
|
||||
|
||||
namespace WBM
|
||||
{
|
||||
partial class WBM
|
||||
{
|
||||
private ConfigEntry<bool> showTeamStats;
|
||||
private ConfigEntry<KeyboardShortcut> showTeamStatsShortcut;
|
||||
|
||||
private void doTeamStats()
|
||||
{
|
||||
this.toggleTeamStatsOnKeyPress();
|
||||
}
|
||||
|
||||
private void drawTeamStats()
|
||||
{
|
||||
if (!this.showTeamStats.Value) return;
|
||||
|
||||
try
|
||||
{
|
||||
string teamNames = "Nickname\n\n";
|
||||
string teamKDR = "KDR\n\n";
|
||||
string teamPoints = "pts\n\n";
|
||||
string teamDamage = "Damage\n\n";
|
||||
|
||||
int teamTotalKills = 0;
|
||||
int teamTotalDeaths = 0;
|
||||
int teamTotalDamage = 0;
|
||||
|
||||
for (int i = 0; i < this.data.playerStatsArray.Length; i++)
|
||||
{
|
||||
Data.PlayerStatsStruct stat = this.data.playerStatsArray[i];
|
||||
|
||||
// if player is not a bot and if player is in my team
|
||||
if ((stat.killsElo != 0) && (this.teamList[i] == this.myTeam))
|
||||
{
|
||||
teamNames += $"{this.data.nickList[i]}\n";
|
||||
teamKDR += $"{Util.formatKDR(stat.kills, stat.deaths)}\n";
|
||||
teamPoints += $"{stat.points}\n";
|
||||
teamDamage += $"{stat.damage}\n";
|
||||
|
||||
teamTotalKills += stat.kills;
|
||||
teamTotalDeaths += stat.deaths;
|
||||
teamTotalDamage += stat.damage;
|
||||
}
|
||||
}
|
||||
|
||||
int teamStatOffset = (this.data.gameState == Data.GameStateEnum.Results) ? 280 : 0;
|
||||
GUI.Box(new Rect(Screen.width - 320, 445 + teamStatOffset, 300, 270), "Team Stats");
|
||||
GUI.Label(new Rect(Screen.width - 315, 470 + teamStatOffset, 105, 190), teamNames);
|
||||
GUI.Label(new Rect(Screen.width - 200, 470 + teamStatOffset, 40, 190), teamKDR);
|
||||
GUI.Label(new Rect(Screen.width - 150, 470 + teamStatOffset, 40, 190), teamPoints);
|
||||
GUI.Label(new Rect(Screen.width - 100, 470 + teamStatOffset, 70, 190), teamDamage);
|
||||
|
||||
GUI.Label(
|
||||
new Rect(Screen.width - 315, 655 + teamStatOffset, 300, 55),
|
||||
$@"total damage: {teamTotalDamage}
|
||||
total deaths: {teamTotalDeaths}
|
||||
total kills: {teamTotalKills}"
|
||||
);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void toggleTeamStatsOnKeyPress()
|
||||
{
|
||||
if (this.showTeamStatsShortcut.Value.IsDown()) this.showTeamStats.Value = !this.showTeamStats.Value;
|
||||
}
|
||||
}
|
||||
}
|
47
WBM/features/weaponStats.cs
Normal file
47
WBM/features/weaponStats.cs
Normal file
|
@ -0,0 +1,47 @@
|
|||
using BepInEx.Configuration;
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
using System;
|
||||
|
||||
namespace WBM
|
||||
{
|
||||
partial class WBM
|
||||
{
|
||||
private ConfigEntry<bool> showWeaponStats;
|
||||
private ConfigEntry<KeyboardShortcut> showWeaponStatsShortcut;
|
||||
|
||||
private void doWeaponStats()
|
||||
{
|
||||
this.toggleWeaponStatsOnKeyPress();
|
||||
}
|
||||
|
||||
private void drawWeaponStats()
|
||||
{
|
||||
|
||||
if (!this.showWeaponStats.Value) return;
|
||||
|
||||
try
|
||||
{
|
||||
GUI.Box(
|
||||
new Rect(this.GUIOffsetX.Value, this.GUIOffsetY.Value + 250, 230, 130),
|
||||
$@"Weapon stats
|
||||
|
||||
fire Timer: {String.Format("{0:0.00}", Util.getGunFireTimer(this.personGun))}s (max: {String.Format("{0:0.00}", Util.getGunFireRate(this.personGun))}s)
|
||||
reload Timer: {Util.getGunReloadTimer(this.personGun)}
|
||||
speed: {Util.getGunFireVelocity(this.personGun)}
|
||||
zoom: {Util.getGunZoom(this.personGun)}"
|
||||
);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.LogError(e);
|
||||
}
|
||||
}
|
||||
|
||||
private void toggleWeaponStatsOnKeyPress()
|
||||
{
|
||||
if (this.showWeaponStatsShortcut.Value.IsDown()) this.showWeaponStats.Value = !this.showWeaponStats.Value;
|
||||
}
|
||||
}
|
||||
}
|
BIN
images/elo.png
BIN
images/elo.png
Binary file not shown.
Before Width: | Height: | Size: 24 KiB |
Binary file not shown.
Before Width: | Height: | Size: 18 KiB |
Binary file not shown.
Before Width: | Height: | Size: 18 KiB |
Loading…
Add table
Add a link
Reference in a new issue